From bb17aea73ac6fb48f3436f656c245e8ed91298fb Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 15 Oct 2016 01:15:08 +0200 Subject: [PATCH] You can now mark a register as corrupting a certain register class; calls work, or at least look like they work. The bad news is that the register allocator has a rare talent for putting things in the wrong register. --- mach/proto/mcg/hop.c | 17 ++-- mach/proto/mcg/hop.h | 1 + mach/proto/mcg/pass_instructionselection.c | 1 + mach/proto/mcg/pass_registerallocator.c | 102 +++++++++++++++------ mach/proto/mcg/table | 2 + util/mcgg/gram.y | 3 + util/mcgg/iburg.c | 21 +++++ util/mcgg/iburg.h | 1 + util/mcgg/mcgg.h | 1 + util/mcgg/scan.l | 1 + 10 files changed, 115 insertions(+), 35 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index b42cd9548..6b84c62a7 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -178,20 +178,19 @@ void hop_print(char k, struct hop* hop) hop_render(hop); - print_header(k, hop); - p = strtok(buffer, "\n"); - if (!p) - { - print_header(k, hop); - tracef(k, "\n"); - } + print_header(k, hop); while (p) { - print_header(k, hop); - tracef(k, "%s\n", p); + tracef(k, "%s", p); p = strtok(NULL, "\n"); + if (p) + { + tracef(k, "\n"); + print_header(k, hop); + } } + tracef(k, "\n"); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index ab2b39d59..1dbf5772c 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -34,6 +34,7 @@ struct hop int id; struct basicblock* bb; struct ir* ir; + const struct burm_instruction_data* insndata; ARRAYOF(struct insel) insels; struct vreg* output; diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index e8c9c453f..9b5a615c6 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -182,6 +182,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal) if (!insn->insndata->is_fragment) { insn->hop = current_hop = new_hop(current_bb, insn->ir); + current_hop->insndata = insn->insndata; emit(insn); if (!current_hop->output) diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 9068c5958..fffc6a138 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -99,10 +99,19 @@ static struct hreg* evict(struct vreg* vreg) assert(false); } -static bool allocatable(struct hreg* hreg, struct vreg* vreg) +static bool allocatable_input(struct hreg* hreg, struct vreg* vreg) { struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); - return (hreg->attrs & c->attrs); + return !pmap_findleft(current_ins, hreg) && + (!c || (hreg->attrs & c->attrs)); +} + +static bool allocatable_output(struct hreg* hreg, struct vreg* vreg) +{ + struct constraint* c = pmap_findleft(¤t_hop->constraints, vreg); + return !pmap_findleft(current_outs, hreg) && + (!c || (hreg->attrs & c->attrs)) && + !(hreg->attrs & current_hop->insndata->corrupts); } static struct hreg* find_input_reg(struct vreg* vreg) @@ -113,8 +122,7 @@ static struct hreg* find_input_reg(struct vreg* vreg) for (i=0; iconstraints, vreg); if (c->equals_to) { + tracef('R', "R: outputput equality constraint of %%%d to %%%d\n", + vreg->id, c->equals_to->id); + /* This output register is constrained to be in the same hreg as an * input register (most likely for a 2op instruction). */ hreg = pmap_findright(current_ins, c->equals_to); - /* If this register is current unused as an output, use it. */ + /* If this register is currently unused as an output, use it. */ - if (!pmap_findleft(current_outs, hreg)) + if (allocatable_output(hreg, c->equals_to)) { pmap_add(current_outs, hreg, vreg); return; @@ -235,6 +256,38 @@ static void add_output_register(struct vreg* vreg) } } +static void add_through_register(struct vreg* vreg, struct hreg* hreg) +{ + /* Register hint for an input? */ + + if (hreg) + { + bool infree = allocatable_input(hreg, vreg); + bool outfree = allocatable_output(hreg, vreg); + + if (infree && outfree) + { + /* Register unused --- use it. */ + } + if ((infree || pmap_findleft(current_ins, hreg) == vreg) && + (outfree || pmap_findleft(current_outs, hreg) == vreg)) + { + /* Input and output are either free or already assigned. */ + } + else + { + /* Nope, can't honour the hint. */ + hreg = NULL; + } + } + + if (!hreg) + hreg = find_through_reg(vreg); + + pmap_put(current_ins, hreg, vreg); + pmap_put(current_outs, hreg, vreg); +} + static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src) { uint32_t srctype = src->type; @@ -249,8 +302,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s { hreg = hregs.item[i]; if ((hreg->type == src->type) && - !pmap_findleft(current_ins, hreg) && - !pmap_findleft(current_outs, hreg)) + allocatable_input(hreg, vreg) && + allocatable_output(hreg, vreg)) { goto found; } @@ -283,10 +336,7 @@ static void select_registers(struct hop* hop, { struct vreg* vreg = hop->throughs.item[i]; struct hreg* hreg = pmap_findright(old, vreg); - assert(hreg != NULL); - - pmap_put(current_ins, hreg, vreg); - pmap_put(current_outs, hreg, vreg); + add_through_register(vreg, hreg); } /* Any registers being *read* by the instruction should also stay where diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 4653e2d60..dce199cae 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -305,10 +305,12 @@ PATTERNS cost 8; CALL(dest:LABEL4) + with corrupted(volatile) emit "bl $dest" cost 4; CALL(dest:(int)reg) + with corrupted(volatile) emit "mtspr ctr, %dest" emit "bcctrl ALWAYS, 0, 0" cost 8; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index 3fe5f9c10..748d3fa38 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -26,6 +26,7 @@ extern int yylex(void); } %term COPY +%term CORRUPTED %term COST %term DECLARATIONS %term EMIT @@ -145,6 +146,8 @@ constraint : '(' constraint ')' { $$ = $2; } | '%' ID EQUALS '%' ID { $$ = calloc(1, sizeof(*$$)); $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; } + | CORRUPTED '(' ID ')' { $$ = calloc(1, sizeof(*$$)); + $$->type = CONSTRAINT_CORRUPTED_ATTR; $$->left = $3; } ; qfragments diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index a3d9568e8..ff8b1e973 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -1239,6 +1239,27 @@ static void emitinsndata(Rule rules) print("%2%s,\n", r->lhs->is_fragment ? "true" : "false"); + { + int i; + uint32_t attrs = 0; + + for (i=0; iconstraints.count; i++) + { + struct constraint* c = r->constraints.item[i]; + + if (c->type == CONSTRAINT_CORRUPTED_ATTR) + { + struct regattr* p = smap_get(®isterattrs, c->left); + if (!p) + yyerror("no such register attribute '%s'", c->left); + + attrs |= 1<<(p->number); + } + } + + print("%2%d, /* corruption attrs */\n", attrs); + } + print("%1},\n"); r = r->link; } diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index ebd22fbe3..689a84177 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -20,6 +20,7 @@ typedef struct term* Term; enum { CONSTRAINT_EQUALS, + CONSTRAINT_CORRUPTED_ATTR, }; struct constraint diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index c0c9d87fb..242c1efcd 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -56,6 +56,7 @@ struct burm_instruction_data const char* name; burm_emitter_t* emitter; bool is_fragment; + uint32_t corrupts; }; extern const struct burm_instruction_data burm_instruction_data[]; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 68de96ed4..d6a60d361 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -38,6 +38,7 @@ static int braces = 0; "DECLARATIONS" return DECLARATIONS; "PATTERNS" return PATTERNS; "REGISTERS" return REGISTERS; +"corrupted" return CORRUPTED; "cost" return COST; "emit" return EMIT; "fragment" return FRAGMENT;