From: David Given Date: Sat, 8 Oct 2016 21:32:54 +0000 (+0200) Subject: Basic register allocation works! X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=d75cc0a66317060772b79c7e71100a964f6f0430;p=ack.git Basic register allocation works! --- diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 4c65721e4..323fa4dd5 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -24,6 +24,12 @@ struct basicblock ARRAYOF(struct vreg) liveins; ARRAYOF(struct vreg) liveouts; + /* Register assignments on entry and exit. These are *pointers* (because + * they just point to the regsin/regsout of the first and last hop + * respectively). */ + register_assignment_t* regsin; + register_assignment_t* regsout; + bool is_fake : 1; bool is_root : 1; bool is_terminated : 1; diff --git a/mach/proto/mcg/graph.c b/mach/proto/mcg/graph.c index 9c976735b..395b7bfca 100644 --- a/mach/proto/mcg/graph.c +++ b/mach/proto/mcg/graph.c @@ -87,10 +87,10 @@ static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2 while (p1 != p2) { while (p1->order < p2->order) - p1 = pmap_get(&dominance.graph, p1); + p1 = pmap_findleft(&dominance.graph, p1); while (p2->order < p1->order) - p2 = pmap_get(&dominance.graph, p2); + p2 = pmap_findleft(&dominance.graph, p2); } return p1; @@ -129,16 +129,16 @@ static void calculate_dominance_graph(void) struct basicblock* p = b->prevs.item[j]; /* Skip unprocessed blocks. */ - if (!pmap_get(&dominance.graph, p)) + if (!pmap_findleft(&dominance.graph, p)) continue; if (!new_idom) new_idom = p; - else if (pmap_get(&dominance.graph, p)) + else if (pmap_findleft(&dominance.graph, p)) new_idom = intersect(p, new_idom); } - if (pmap_get(&dominance.graph, b) != new_idom) + if (pmap_findleft(&dominance.graph, b) != new_idom) { pmap_put(&dominance.graph, b, new_idom); changed = true; diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index 652b9f658..d0a2dfcf3 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -81,8 +81,17 @@ void hop_print(char k, struct hop* hop) break; case INSEL_VREG: - tracef(k, "%%%d", insel->u.vreg->id); + { + struct vreg* vreg = insel->u.vreg; + struct hreg* hreg = pmap_findright(&hop->regsin, vreg); + if (!hreg) + hreg = pmap_findright(&hop->regsout, vreg); + if (hreg) + tracef(k, "%s", hreg->name); + else + tracef(k, "%%%d", vreg->id); break; + } case INSEL_STRING: tracef(k, "%s", insel->u.string); diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 18e70d3b4..16a39f734 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -32,7 +32,8 @@ struct hop ARRAYOF(struct vreg) ins; ARRAYOF(struct vreg) outs; ARRAYOF(struct vreg) throughs; - PMAPOF(struct vreg, struct hreg) registers; + register_assignment_t regsin; + register_assignment_t regsout; }; extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index f4e33f2af..a90bbb5ef 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -23,8 +23,8 @@ #include "astring.h" #include "ir.h" #include "mcgg.h" -#include "hop.h" #include "reg.h" +#include "hop.h" #include "basicblock.h" #include "procedure.h" #include "graph.h" diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index e7cf1d7dd..bb22a4d43 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -1,7 +1,176 @@ #include "mcg.h" +static ARRAYOF(struct hreg) hregs; +static int stacksize; + +static void populate_hregs(void) +{ + const struct burm_register_data* brd = burm_register_data; + + stacksize = 0; + while (brd->name) + { + array_append(&hregs, new_hreg(brd)); + brd++; + } +} + +static void wire_up_blocks_ins_outs(void) +{ + int i, j; + + for (i=0; ihops.count >= 1); + bb->regsin = &bb->hops.item[0]->regsin; + bb->regsout = &bb->hops.item[bb->hops.count-1]->regsout; + } +} + +static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg) +{ + int i; + + for (i=0; ithroughs.count; i++) + { + struct vreg* vreg = hop->throughs.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + assert(hreg != NULL); + + pmap_put(in, hreg, vreg); + pmap_put(out, hreg, vreg); + } + + /* Any registers being *read* by the instruction should also stay where + * they are. (This is likely to duplicate some throughs.) */ + + for (i=0; iins.count; i++) + { + struct vreg* vreg = hop->ins.item[i]; + struct hreg* hreg = pmap_findright(old, vreg); + assert(hreg != NULL); + + pmap_put(in, hreg, vreg); + } + + /* Any output registers will be *new* vregs (because SSA). So, allocate + * new hregs for them. */ + + for (i=0; iouts.count; i++) + { + struct vreg* vreg = hop->outs.item[i]; + allocate_hreg(out, vreg); + } +} + void pass_register_allocator(void) { + int i, j, k; + + populate_hregs(); + wire_up_blocks_ins_outs(); + + for (i=0; iregsin; + + tracef('R', "R: allocating 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 + * guarantees it. */ + + for (j=0; jliveins.count; j++) + { + struct vreg* vreg = bb->liveins.item[j]; + for (k=0; kprevs.count; k++) + { + struct basicblock* prevbb = bb->prevs.item[k]; + struct hreg* hreg = pmap_findright(prevbb->regsout, vreg); + if (hreg) + { + tracef('R', "R: import hreg %s for input %%%d from %s\n", + hreg->name, vreg->id, prevbb->name); + assert(!pmap_findleft(old, hreg)); + pmap_put(old, hreg, vreg); + goto nextvreg; + } + } + + fatal("couldn't find a register assignment for $%d", vreg->id); + nextvreg:; + } + + /* And now do the same for the phis. Unlike input vregs, a phi can + * import a vreg from multiple locations. However, we don't care which + * one we find, as this is just a hint. Picking the same register as a + * predecessor helps reduce the number of copies the SSA deconstruction + * pass will need to insert. */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + struct phi* phi = bb->phis.item[j].right; + if (!pmap_findright(old, vreg)) + { + /* This variable isn't allocated yet. */ + + struct hreg* hreg = pmap_findright( + phi->prev->regsout, phi->ir->result); + if (hreg && !pmap_findleft(old, hreg)) + { + tracef('R', "R: import hreg %s for phi input %%%d from %s\n", + hreg->name, vreg->id, phi->prev->name); + pmap_put(old, hreg, vreg); + } + } + } + + /* 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. */ + + for (j=0; jphis.count; j++) + { + struct vreg* vreg = bb->phis.item[j].left; + if (!pmap_findright(old, vreg)) + allocate_hreg(old, vreg); + } + + for (j=0; jhops.count; j++) + { + struct hop* hop = bb->hops.item[j]; + register_assignment_t* in = &hop->regsin; + register_assignment_t* out = &hop->regsout;; + + select_registers(hop, old, in, out); + + old = out; + } + } } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 64f67698a..9bf2d777b 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -26,7 +26,7 @@ static void calculate_dominance_frontier_graph(void) for (i=0; iprevs.count >= 2) { for (j=0; jprevs.count; j++) @@ -37,7 +37,7 @@ static void calculate_dominance_frontier_graph(void) tracef('S', "S: %s is in %s's dominance frontier\n", b->name, runner->name); pmap_add(&dominancefrontiers, runner, b); - runner = pmap_get(&dominance.graph, runner); + runner = pmap_findleft(&dominance.graph, runner); } } } @@ -187,7 +187,7 @@ static void ssa_convert(void) for (i=0; iname); diff --git a/mach/proto/mcg/reg.c b/mach/proto/mcg/reg.c index c4cf71058..848c1cd98 100644 --- a/mach/proto/mcg/reg.c +++ b/mach/proto/mcg/reg.c @@ -9,7 +9,7 @@ struct vreg* new_vreg(void) return vreg; } -struct hreg* new_hreg(struct burm_register_data* brd) +struct hreg* new_hreg(const struct burm_register_data* brd) { struct hreg* hreg = calloc(1, sizeof *hreg); hreg->name = brd->name; diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index b901eb667..743b9c3e5 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -18,9 +18,11 @@ struct vreg ARRAYOF(struct hop) used; }; +typedef PMAPOF(struct hreg, struct vreg) register_assignment_t; + extern struct vreg* new_vreg(void); -extern struct hreg* new_hreg(struct burm_register_data* brd); +extern struct hreg* new_hreg(const struct burm_register_data* brd); extern struct hreg* new_stacked_hreg(int offset, uint32_t attrs); #endif diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index c589101d6..932172480 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -104,7 +104,7 @@ PATTERNS cost 4; SETRET4(in:(ret)reg) - emit "mov r0, %in" + emit "mr r3, %in" cost 4; (ret)reg = GETRET4