diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 16a39f734..4e7868c9a 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -21,6 +21,11 @@ struct insel u; }; +struct constraint +{ + uint32_t attrs; +}; + struct hop { int id; @@ -29,6 +34,8 @@ struct hop ARRAYOF(struct insel) insels; struct vreg* output; + PMAPOF(struct vreg, struct constraint) constraints; + ARRAYOF(struct vreg) ins; ARRAYOF(struct vreg) outs; ARRAYOF(struct vreg) throughs; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index db5280280..6ab678ac9 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -78,15 +78,29 @@ static void emit_eoi(void) hop_add_eoi_insel(current_hop); } -static void constrain_input_reg(int child, int attr) +static struct constraint* get_constraint(struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + if (!c) + { + c = calloc(1, sizeof(*c)); + pmap_put(¤t_hop->constraints, vreg, c); + } + return c; +} + +static void constrain_input_reg(int child, uint32_t attr) { struct vreg* vreg = find_vreg_of_child(child); + struct constraint* c; if (vreg) array_appendu(¤t_hop->ins, vreg); + + get_constraint(vreg)->attrs = attr; } -static void constrain_output_reg(int attr) +static void constrain_output_reg(uint32_t attr) { struct vreg* vreg = current_hop->output; @@ -95,6 +109,8 @@ static void constrain_output_reg(int attr) array_appendu(¤t_hop->outs, vreg); vreg->defined = current_hop; + + get_constraint(vreg)->attrs = attr; } static const struct burm_emitter_data emitter_data = diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index bb22a4d43..0bacdd225 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -28,7 +28,7 @@ static void wire_up_blocks_ins_outs(void) } } -static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg) +static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr) { int i; @@ -37,8 +37,11 @@ static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg struct hreg* hreg = hregs.item[i]; if (!pmap_findleft(regs, hreg)) { - pmap_put(regs, hreg, vreg); - return hreg; + if (hreg->attrs & attr) + { + pmap_put(regs, hreg, vreg); + return hreg; + } } } @@ -81,7 +84,8 @@ static void select_registers(struct hop* hop, for (i=0; iouts.count; i++) { struct vreg* vreg = hop->outs.item[i]; - allocate_hreg(out, vreg); + struct constraint* c = pmap_findleft(&hop->constraints, vreg); + allocate_hreg(out, vreg, c->attrs); } } @@ -97,7 +101,7 @@ void pass_register_allocator(void) struct basicblock* bb = dominance.preorder.item[i]; register_assignment_t* old = bb->regsin; - tracef('R', "R: allocating block %s\n", bb->name); + tracef('R', "R: considering block %s\n", bb->name); /* Attempt to import any block input registers from a predecessor. At * least one predecessor should export it; our graph traversal order @@ -151,21 +155,42 @@ void pass_register_allocator(void) /* It's possible for the previous stage to fail because in in has * clobbered the physical register we were wanting. So we need to - * allocate a new register for that phi value. */ + * allocate a new register for that phi value. + * + * We don't bother allocating anything if the vreg is never used. + * */ for (j=0; jphis.count; j++) { struct vreg* vreg = bb->phis.item[j].left; - if (!pmap_findright(old, vreg)) - allocate_hreg(old, vreg); + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg) && (vreg->used.count > 0)) + { + struct hop* used = vreg->used.item[0]; + struct constraint* c = pmap_findleft(&used->constraints, vreg); + struct hreg* hreg = allocate_hreg(old, vreg, c->attrs); + + tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n", + hreg->name, vreg->id, phi->prev->name); + } } for (j=0; jhops.count; j++) { + int k; struct hop* hop = bb->hops.item[j]; register_assignment_t* in = &hop->regsin; register_assignment_t* out = &hop->regsout;; + tracef('R', "R: %d from $%d:", hop->id, hop->ir->id); + for (k=0; kins.count; k++) + tracef('R', " r%%%d", hop->ins.item[k]->id); + for (k=0; kthroughs.count; k++) + tracef('R', " =%%%d", hop->throughs.item[k]->id); + for (k=0; kouts.count; k++) + tracef('R', " w%%%d", hop->outs.item[k]->id); + tracef('R', "\n"); + select_registers(hop, old, in, out); old = out; diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index c93a1b373..9f2c6b729 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -400,8 +400,8 @@ Tree tree(const struct terminfo* ti, Tree left, Tree right) if (ti->attr && ti->attr[0]) { - nt->attr = smap_get(®isterattrs, ti->attr); - if (!nt->attr) + t->attr = smap_get(®isterattrs, ti->attr); + if (!t->attr) yyerror("'%s' doesn't seem to be a known register attribute", ti->attr); } } @@ -1077,10 +1077,12 @@ static void emit_input_regs(Tree node, int* index) Nonterm nt = node->op; if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right) { - uint32_t attr = 0; - if (nt->attr->number) - attr = 1<attr->number; - print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr); + if (node->attr) + { + uint32_t attr = 1<attr->number; + print("%1data->constrain_input_reg(%d, 0x%x /* %s */);\n", + *index, attr, node->attr->name); + } } if (!node->left && !node->right) @@ -1118,7 +1120,8 @@ static void emitinsndata(Rule rules) print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); if (r->attr) - print("%1data->constrain_output_reg(0x%x);\n", 1<attr->number); + print("%1data->constrain_output_reg(0x%x /* %s */);\n", + 1<attr->number, r->attr->name); { int index = 0; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index d9d69b8c6..8a5a71b32 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -96,7 +96,6 @@ struct nonterm Rule chain; /* chain rules w/non-terminal on rhs */ Nonterm link; /* next terminal in number order */ bool is_fragment; /* these instructions are all fragments */ - struct regattr* attr; /* input register attribute */ }; extern void* lookup(const char* name); extern Nonterm nonterm(const char* id, bool allocate); @@ -109,6 +108,7 @@ struct tree const char* label; /* user label for this node */ Tree left, right; /* operands */ int nterms; /* number of terminal nodes in this tree */ + struct regattr* attr; /* input register attribute */ }; extern Tree tree(const struct terminfo* ti, Tree left, Tree right); diff --git a/util/mcgg/ir.dat b/util/mcgg/ir.dat index 50c2e44ed..31574adbb 100644 --- a/util/mcgg/ir.dat +++ b/util/mcgg/ir.dat @@ -42,6 +42,10 @@ S AND S OR S EOR S NOT +S ASL +S ASR +S LSL +S LSR # Conversions S CII1 diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 14353c0e3..4e86e79e0 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -44,8 +44,8 @@ struct burm_emitter_data void (*emit_reg)(int child); void (*emit_value)(int child); void (*emit_eoi)(void); - void (*constrain_input_reg)(int child, int attr); - void (*constrain_output_reg)(int attr); + void (*constrain_input_reg)(int child, uint32_t attr); + void (*constrain_output_reg)(uint32_t attr); }; typedef void burm_emitter_t(const struct burm_emitter_data* data);