From bd28bddb92d81ae200a9dcb6162fcfe8c47c8bc8 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 4 Oct 2016 00:16:06 +0200 Subject: [PATCH] Massive rewrite of how emitters and the instruction selector works, after I realised that the existing approach wasn't working. Now, hopefully, tracks the instruction trees generated during selection properly. --- mach/proto/mcg/ir.h | 1 + mach/proto/mcg/pass_instructionselection.c | 147 ++++++++++++--------- mach/proto/mcg/table | 26 +++- util/mcgg/gram.y | 25 ++-- util/mcgg/iburg.c | 126 +++++++----------- util/mcgg/mcgg.h | 10 +- 6 files changed, 175 insertions(+), 160 deletions(-) diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 52c5dc7d2..ea84e1ae3 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -20,6 +20,7 @@ struct ir ARRAYOF(struct ir) phivalue; } u; + struct vreg* result; /* vreg containing IR result */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */ }; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index 5c92aae02..20a93c697 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -1,10 +1,22 @@ #include "mcg.h" +#define MAX_CHILDREN 10 + +struct insn +{ + struct ir* ir; + struct hop* hop; + const struct burm_instruction_data* insndata; + int num_children; + struct insn* children[MAX_CHILDREN]; +}; + static struct basicblock* current_bb; static struct hop* current_hop; static struct ir* current_ir; +static struct insn* current_insn; -static const struct burm_emitter_data emitter_data; +static void emit(struct insn* insn); void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) { const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; @@ -20,11 +32,23 @@ void burm_panic_cannot_match(struct burm_node* node) exit(1); } -static void emit_reg(struct burm_node* node, int goal) +static void emit_return_reg(void) { - struct hop* hop = imap_get(¤t_ir->hops, goal); + hop_add_vreg_insel(current_hop, current_hop->output); +} - hop_add_vreg_insel(current_hop, hop->output); +static void emit_reg(int child) +{ + struct insn* insn = current_insn->children[child]; + struct vreg* vreg; + + if (insn->hop) + vreg = insn->hop->output; + else + vreg = insn->ir->result; + + if (vreg) + hop_add_vreg_insel(current_hop, vreg); } static void emit_string(const char* data) @@ -32,17 +56,14 @@ static void emit_string(const char* data) hop_add_string_insel(current_hop, data); } -static void emit_fragment(struct burm_node* node, int goal) +static void emit_fragment(int child) { - int insn_no = burm_rule(node->state_label, goal); - const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; - if (insndata->emitter) - insndata->emitter(node, &emitter_data); + emit(current_insn->children[child]); } -static void emit_value(struct burm_node* node) +static void emit_value(int child) { - hop_add_value_insel(current_hop, node->ir); + hop_add_value_insel(current_hop, current_insn->children[child]->ir); } static void emit_eoi(void) @@ -50,73 +71,75 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } -static void emit_constraint_equals(struct burm_node* node, int goal) -{ -#if 0 - struct hop* hop; - - if (!goal) - goal = ir->goal_no; - hop = imap_get(¤t_ir->hops, goal); - - current_hop->output = hop->output; -#endif -} - static const struct burm_emitter_data emitter_data = { &emit_string, &emit_fragment, + &emit_return_reg, &emit_reg, &emit_value, &emit_eoi, - &emit_constraint_equals }; - -static void walk_instructions(struct burm_node* node, int goal) +static void emit(struct insn* insn) { - struct burm_node* children[10]; - int insn_no = burm_rule(node->state_label, goal); - const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no]; - const short* nts = burm_nts[insn_no]; - struct hop* parent_hop = NULL; - struct ir* ir = node->ir; + struct insn* old = current_insn; + current_insn = insn; + + insn->insndata->emitter(&emitter_data); + + current_insn = old; +} + +static struct insn* walk_instructions(struct burm_node* node, int goal) +{ + struct insn* insn = calloc(1, sizeof(*insn)); int i; - - if (!insndata->is_fragment) + + insn->ir = node->ir; + insn->num_children = 0; + + if (goal) { - parent_hop = current_hop; - current_hop = new_hop(insn_no, ir); - if (goal != 1) + int insn_no = burm_rule(node->state_label, goal); + const short* nts = burm_nts[insn_no]; + struct burm_node* children[MAX_CHILDREN] = {0}; + + insn->insndata = &burm_instruction_data[insn_no]; + + burm_kids(node, insn_no, children); + + i = 0; + for (;;) { - current_hop->output = new_vreg(); - imap_add(¤t_ir->hops, goal, current_hop); + if (!children[i]) + break; + + insn->children[i] = walk_instructions(children[i], nts[i]); + insn->num_children++; + i++; + } + + tracef('I', "I: $%d goal %d %s selected %d: %s\n", + node->ir->id, + goal, + insn->insndata->is_fragment ? "fragment" : "instruction", + insn_no, + insn->insndata->name); + + if (!insn->insndata->is_fragment) + { + insn->hop = current_hop = new_hop(0, insn->ir); + insn->hop->output = new_vreg(); + emit(insn); + hop_print('I', current_hop); + + if (goal != 1) + insn->ir->result = insn->hop->output; } } - burm_kids(node, insn_no, children); - for (i=0; nts[i]; i++) - walk_instructions(children[i], nts[i]); - - tracef('I', "I: $%d goal %d selected %s %d: %s\n", - ir->id, - goal, - insndata->is_fragment ? "fragment" : "instruction", - insn_no, - insndata->name); - - if (!insndata->is_fragment) - { - /* This may cause the vregs to be reassigned for this instruction (and - * fragments contained within it). */ - - insndata->emitter(node, &emitter_data); - - hop_print('I', current_hop); - array_append(&ir->hops, current_hop); - current_hop = parent_hop; - } + return insn; } static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir) diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 5f589d122..0fa07b6bc 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -52,6 +52,7 @@ PATTERNS cost 4; reg = POP4 + with int reg emit "pop %reg" cost 4; @@ -68,12 +69,11 @@ PATTERNS cost 4; reg = in:REG - with (reg == in) - emit "reg %reg" + emit "mov %reg, %in" cost 1; reg = NOP(in:reg) - with (reg == in) + emit "mov %reg, %in" cost 1; @@ -90,18 +90,22 @@ PATTERNS cost 4; reg = LOAD4(addr:address) + with int reg emit "ldr %reg, %addr" cost 4; reg = LOAD1(addr:address) + with int reg emit "ldrb %reg, %addr" cost 4; reg = CIU14(LOAD1(addr:address)) + with int reg emit "ldrb %reg, %addr" cost 4; reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) + with int reg emit "ldrsb %reg, %addr" cost 4; @@ -109,6 +113,7 @@ PATTERNS /* Locals */ reg = in:LOCAL4 + with int reg emit "add %reg, fp, #$in" cost 4; @@ -161,14 +166,17 @@ PATTERNS /* Comparisons */ cc = COMPARES4(left:reg, right:aluparam) + with cc cc emit "cmp %left, %right" cost 4; cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) + with cc cc emit "cmp %left, %right" cost 4; reg = cc + with int reg emit "mov %reg, #0" emit "movlt %reg, #-1" emit "movgt %reg, #1" @@ -178,10 +186,12 @@ PATTERNS /* Conversions */ reg = CII14(CIU41(value:reg)) + with int reg emit "sxtb %reg, %value" cost 4; reg = CIU41(in:reg) + with int reg emit "and %reg, %in, #0xff" cost 4; @@ -189,19 +199,23 @@ PATTERNS /* ALU operations */ reg = ADD4(left:reg, right:aluparam) + with int reg emit "add %reg, %left, %right" cost 4; reg = ADD4(left:aluparam, right:reg) + with int reg emit "add %reg, %right, %left" cost 4; reg = MOD4(left:reg, right:reg) + with int reg emit "udiv %reg, %left, %right" emit "mls %reg, %reg, %right, %left" cost 8; reg = DIV4(left:reg, right:aluparam) + with int reg emit "div %reg, %left, %right" cost 4; @@ -212,28 +226,34 @@ PATTERNS emit "%value"; reg = value:aluparam + with int reg emit "mov %reg, %value" cost 4; reg = value:LABEL4 + with int reg emit "adr %reg, $value" cost 4; reg = value:BLOCK4 + with int reg emit "adr %reg, $value" cost 4; reg = value:CONST4 + with int reg emit "ldr %reg, address-containing-$value" cost 8; reg = value:CONSTF4 + with int reg emit "vldr %reg, address-containing-$value" cost 8; /* FPU operations */ reg = ADDF4(left:reg, right:reg) + with int reg emit "fadds %reg, %left, %right" cost 4; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 9927d1598..5dc23a8be 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -28,6 +28,7 @@ static int nextern = 1; } %term ALLOCATES +%term COPY %term COST %term DECLARATIONS %term EMIT @@ -105,24 +106,24 @@ patterns ; pattern - : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } - | rhs { $$ = rule("stmt", $1, nextern++); } - | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } - | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } - | pattern COST INT { $$ = $1; $$->cost = $3; } - | pattern_constraints { $$ = $1; } - | pattern_emit { $$ = $1; } + : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } + | rhs { $$ = rule("stmt", $1, nextern++); } + | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } + | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } + | pattern COST INT { $$ = $1; $$->cost = $3; } + | pattern_constraints { $$ = $1; } + | pattern_emit { $$ = $1; } ; rhs - : terminfo { $$ = tree(&$1, NULL, NULL); } - | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } - | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } + : terminfo { $$ = tree(&$1, NULL, NULL); } + | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); } + | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); } ; terminfo - : ID { $$.name = $1; } - | ID ':' ID { $$.label = $1; $$.name = $3; } + : ID { $$.name = $1; } + | ID ':' ID { $$.label = $1; $$.name = $3; } ; pattern_emit diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 937a0df8e..af3106a8c 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -679,20 +679,22 @@ static void emitheader(void) } /* computekids - compute paths to kids in tree t */ -static char* computekids(Tree t, const char* v, char* bp, int* ip) +static char* computekids(Tree node, const char* v, char* bp, int* ip) { - Term p = t->op; + Term t = node->op; - if (p->kind == NONTERM) + if (!node->left && !node->right) { sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); bp += strlen(bp); } - else if (p->arity > 0) + + if (t->kind == TERM) { - bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); - if (p->arity == 2) - bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); + if (t->arity >= 1) + bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); + if (t->arity == 2) + bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); } return bp; } @@ -910,6 +912,27 @@ static void label_not_found(Rule rule, const char* label) exit(1); } +static bool find_child_index(Tree node, const char* name, int* index, Tree* found) +{ + /* This must return the same ordering as the burm_kids() function uses. */ + + if (node->label && strcmp(node->label, name) == 0) + { + if (found) + *found = node; + return true; + } + + if (!node->left && !node->right) + (*index)++; + + if (node->left && find_child_index(node->left, name, index, found)) + return true; + if (node->right && find_child_index(node->right, name, index, found)) + return true; + return false; +} + /* emitpredicates - emit predicates for rules */ static void emitpredicatedefinitions(Rule r) { @@ -954,49 +977,6 @@ 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) { @@ -1007,6 +987,7 @@ static void emitinsndata(Rule rules) while (r) { struct stringfragment* f = r->code.first; + yylineno = r->lineno; if (!f) { @@ -1019,20 +1000,7 @@ 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); - } - } + print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); while (f) { @@ -1043,23 +1011,26 @@ static void emitinsndata(Rule rules) const char* label = f->data + 1; if (strcmp(label, r->lhs->name) == 0) - print("%1data->emit_reg(node, %P%s_NT);\n", label); + print("%1data->emit_return_reg();\n", label); else { Tree node; - uint32_t path = find_label(r->pattern, label, 0, &node); + int index = 0; + if (!find_child_index(r->pattern, label, &index, &node)) + label_not_found(r, label); Nonterm nt = node->op; - if (path == PATH_MISSING) - label_not_found(r, label); - - if (nt->is_fragment) - print("%1data->emit_fragment("); + if (nt->kind == NONTERM) + { + if (nt->is_fragment) + print("%1data->emit_fragment("); + else + print("%1data->emit_reg("); + } else print("%1data->emit_reg("); - print_path(path); - print(", %P%s_NT);\n", ((Nonterm)node->op)->name); + print("%d);\n", index); } break; } @@ -1067,12 +1038,11 @@ static void emitinsndata(Rule rules) 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) + int index = 0; + if (!find_child_index(r->pattern, label, &index, NULL)) label_not_found(r, label); - print_path(path); - print(");\n"); + + print("%1data->emit_value(%d);\n", index); break; } diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 9180113a7..a3ff0197b 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -39,14 +39,14 @@ extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost); struct burm_emitter_data { void (*emit_string)(const char* data); - void (*emit_fragment)(NODEPTR_TYPE node, int goal); - void (*emit_reg)(NODEPTR_TYPE node, int goal); - void (*emit_value)(NODEPTR_TYPE node); + void (*emit_fragment)(int child); + void (*emit_return_reg)(void); + void (*emit_reg)(int child); + void (*emit_value)(int child); void (*emit_eoi)(void); - void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal); }; -typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data); +typedef void burm_emitter_t(const struct burm_emitter_data* data); struct burm_instruction_data {