From 288ee562035e0c36509540748bdf5b62711e2baf Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 2 Oct 2016 23:25:54 +0200 Subject: [PATCH] Get quite a long way towards basic output-register equality constraints (needed to make special nodes like NOP work properly). Realise that the way I'm dealing with the instruction selector is all wrong; I need to physically copy chunks of tree to give to burg (so I can terminate them correctly). --- mach/proto/mcg/hop.c | 13 +- mach/proto/mcg/hop.h | 12 +- mach/proto/mcg/ir.h | 2 +- mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_instructionselection.c | 34 +++- mach/proto/mcg/table | 1 + mach/proto/mcg/vreg.c | 10 ++ mach/proto/mcg/vreg.h | 12 ++ util/mcgg/iburg.c | 182 +++++++++++++-------- util/mcgg/mcgg.h | 4 +- 10 files changed, 177 insertions(+), 94 deletions(-) create mode 100644 mach/proto/mcg/vreg.c create mode 100644 mach/proto/mcg/vreg.h diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index a57d4988a..e4552e04e 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -28,11 +28,10 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } -void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no) +void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) { - struct insel* insel = new_insel(INSEL_REG); - insel->u.reg.ir = ir; - insel->u.reg.insn_no = insn_no; + struct insel* insel = new_insel(INSEL_VREG); + insel->u.vreg = vreg; array_append(&hop->insels, insel); } @@ -61,7 +60,7 @@ void hop_print(char k, struct hop* hop) if (soi) { - tracef(k, "%c: %d: ", k, hop->id); + tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id); soi = false; } @@ -72,8 +71,8 @@ void hop_print(char k, struct hop* hop) soi = true; break; - case INSEL_REG: - tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no); + case INSEL_VREG: + tracef(k, "%%%d", insel->u.vreg->id); break; case INSEL_STRING: diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index e6cc8f809..3e2f9d6e7 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -4,7 +4,7 @@ enum insel_type { INSEL_STRING, - INSEL_REG, + INSEL_VREG, INSEL_VALUE, INSEL_EOI }; @@ -15,12 +15,7 @@ struct insel union { const char* string; - struct - { - struct ir* ir; - int insn_no; - } - reg; + struct vreg* vreg; struct ir* value; } u; @@ -32,12 +27,13 @@ struct hop int insn_no; struct ir* ir; ARRAYOF(struct insel) insels; + struct vreg* output; }; extern struct hop* new_hop(int insn_no, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); -extern void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no); +extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg); extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_eoi_insel(struct hop* hop); diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index dc66ff757..ce90fcbde 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -23,7 +23,7 @@ struct ir void* state_label; /* used by the iburg instruction selector */ int insn_no; /* the table rule number for this instruction */ int goal_no; /* the semantic type of this instruction; not stmt */ - ARRAYOF(struct hop) hops; /* only for root IRs */ + IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; extern const char* ir_names[]; diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index ba23e2d4f..a5fa1102c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -24,6 +24,7 @@ #include "ir.h" #include "mcgg.h" #include "hop.h" +#include "vreg.h" #include "basicblock.h" #include "procedure.h" diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 2cb070dde..a1f80a855 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -29,7 +29,9 @@ int burm_calculate_label(struct ir* ir) static void emit_reg(struct ir* ir, int goal) { - hop_add_reg_insel(current_hop, ir, goal); + struct hop* hop = imap_get(¤t_ir->hops, goal); + + hop_add_vreg_insel(current_hop, hop->output); } static void emit_string(const char* data) @@ -50,23 +52,30 @@ static void emit_value(struct ir* ir) hop_add_value_insel(current_hop, ir); } -static void emit_resultreg(void) -{ -} - static void emit_eoi(void) { hop_add_eoi_insel(current_hop); } +static void emit_constraint_equals(struct ir* ir, int goal) +{ + struct hop* hop; + + if (!goal) + goal = 2; + hop = imap_get(¤t_ir->hops, goal); + + current_hop->output = hop->output; +} + static const struct burm_emitter_data emitter_data = { &emit_string, &emit_fragment, &emit_reg, &emit_value, - &emit_resultreg, - &emit_eoi + &emit_eoi, + &emit_constraint_equals }; @@ -83,6 +92,11 @@ static void walk_instructions(struct ir* ir, int goal) { parent_hop = current_hop; current_hop = new_hop(insn_no, ir); + if (goal != 1) + { + current_hop->output = new_vreg(); + imap_add(¤t_ir->hops, goal, current_hop); + } } burm_kids(ir, insn_no, children); @@ -102,8 +116,10 @@ static void walk_instructions(struct ir* ir, int goal) if (!insndata->is_fragment) { - if (insndata->emitter) - insndata->emitter(ir, &emitter_data); + /* This may cause the vregs to be reassigned for this instruction (and + * fragments contained within it). */ + + insndata->emitter(ir, &emitter_data); hop_print('I', current_hop); array_append(&ir->hops, current_hop); diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4292dd8e0..0db5f6a99 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -69,6 +69,7 @@ PATTERNS reg = in:REG4 with (reg == in) + emit "reg %reg" cost 1; reg = NOP4(in:reg) diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c new file mode 100644 index 000000000..636475de7 --- /dev/null +++ b/mach/proto/mcg/vreg.c @@ -0,0 +1,10 @@ +#include "mcg.h" + +static int vreg_count = 1; + +struct vreg* new_vreg(void) +{ + struct vreg* vreg = calloc(1, sizeof *vreg); + vreg->id = vreg_count++; + return vreg; +} diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h new file mode 100644 index 000000000..ef92fd224 --- /dev/null +++ b/mach/proto/mcg/vreg.h @@ -0,0 +1,12 @@ +#ifndef VREG_H +#define VREG_H + +struct vreg +{ + int id; +}; + +extern struct vreg* new_vreg(void); + +#endif + diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 2fb6e2cab..937a0df8e 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -954,6 +954,49 @@ static void emitpredicatedefinitions(Rule r) } } +static void invalid_equals_constraint(Rule rule) +{ + yylineno = rule->lineno; + yyerror("left hand side of an equality constraint must be the output register"); + exit(1); +} + +static void emit_ir_expr(Rule rule, const char* label) +{ + if (strcmp(label, rule->lhs->name) == 0) + print("node, %P%s_NT", label); + else + { + Tree node; + uint32_t path = find_label(rule->pattern, label, 0, &node); + Nonterm nt = node->op; + + if (path == PATH_MISSING) + label_not_found(rule, label); + + print_path(path); + if (nt->kind == NONTERM) + print(", %P%s_NT", ((Nonterm)node->op)->name); + else + print(", 0"); + } +} + +static void emit_constraint(Rule rule, struct constraint* c) +{ + switch (c->type) + { + case CONSTRAINT_EQUALS: + if (strcmp(c->left, rule->lhs->name) != 0) + invalid_equals_constraint(rule); + + print("%1data->emit_constraint_equals("); + emit_ir_expr(rule, c->right); + print(");\n"); + break; + } +} + /* emitinsndata - emit the code generation data */ static void emitinsndata(Rule rules) { @@ -964,68 +1007,8 @@ static void emitinsndata(Rule rules) while (r) { struct stringfragment* f = r->code.first; - if (f) - { - print("/* %R */\n", r); - print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); - while (f) - { - switch (f->data[0]) - { - case '%': - { - const char* label = f->data + 1; - - if (strcmp(label, r->lhs->name) == 0) - print("%1data->emit_reg(node, %P%s_NT);\n", label); - else - { - Tree node; - uint32_t path = find_label(r->pattern, label, 0, &node); - Nonterm nt = node->op; - - if (path == PATH_MISSING) - label_not_found(r, label); - - if (nt->is_fragment) - print("%1data->emit_fragment("); - else - print("%1data->emit_reg("); - - print_path(path); - print(", %P%s_NT);\n", ((Nonterm)node->op)->name); - } - break; - } - - case '$': - { - const char* label = f->data + 1; - uint32_t path = find_label(r->pattern, label, 0, NULL); - print("%1data->emit_value("); - if (path == PATH_MISSING) - label_not_found(r, label); - print_path(path); - print(");\n"); - break; - } - - case '\n': - assert(f->data[1] == 0); - print("%1data->emit_eoi();\n"); - break; - - default: - print("%1data->emit_string(\"%s\");\n", f->data); - } - - f = f->next; - } - - print("}\n\n"); - } - else + if (!f) { /* This instruction has no code; make sure it's not a fragment. */ if (r->lhs->is_fragment) @@ -1035,6 +1018,77 @@ static void emitinsndata(Rule rules) } } + print("/* %R */\n", r); + print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); + + /* Constraints come first, because they may cause vreg reassignment, which + * we want to happen before the instruction emission. */ + + { + int i; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + emit_constraint(r, c); + } + } + + while (f) + { + switch (f->data[0]) + { + case '%': + { + const char* label = f->data + 1; + + if (strcmp(label, r->lhs->name) == 0) + print("%1data->emit_reg(node, %P%s_NT);\n", label); + else + { + Tree node; + uint32_t path = find_label(r->pattern, label, 0, &node); + Nonterm nt = node->op; + + if (path == PATH_MISSING) + label_not_found(r, label); + + if (nt->is_fragment) + print("%1data->emit_fragment("); + else + print("%1data->emit_reg("); + + print_path(path); + print(", %P%s_NT);\n", ((Nonterm)node->op)->name); + } + break; + } + + case '$': + { + const char* label = f->data + 1; + uint32_t path = find_label(r->pattern, label, 0, NULL); + print("%1data->emit_value("); + if (path == PATH_MISSING) + label_not_found(r, label); + print_path(path); + print(");\n"); + break; + } + + case '\n': + assert(f->data[1] == 0); + print("%1data->emit_eoi();\n"); + break; + + default: + print("%1data->emit_string(\"%s\");\n", f->data); + } + + f = f->next; + } + + print("}\n\n"); r = r->link; } @@ -1051,11 +1105,7 @@ static void emitinsndata(Rule rules) print("%2\"%R\",\n", r); - print("%2"); - if (r->code.first) - print("&%Pemitter_%d,\n", r->ern); - else - print("NULL,\n"); + print("%2&%Pemitter_%d,\n", r->ern); if (r->lhs->allocate) print("%2%d,\n", r->lhs->allocate->number); diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index a2f20b4b4..1d806852b 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -12,7 +12,6 @@ ((size) == 0) ? 0 : \ (size-1))) - #define STATE_TYPE void* typedef struct ir* NODEPTR_TYPE; @@ -30,9 +29,8 @@ struct burm_emitter_data void (*emit_fragment)(struct ir* ir, int goal); void (*emit_reg)(struct ir* ir, int goal); void (*emit_value)(struct ir* ir); - void (*emit_resultreg)(void); void (*emit_eoi)(void); - void (*emit_usereg)(struct ir* ir); + void (*emit_constraint_equals)(struct ir* rightir, int rightgoal); }; typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data);