From 92bd1ac5f4e62ad9793401c5c075e7d856b66aa4 Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 10 Oct 2016 23:19:46 +0200 Subject: [PATCH] Register allocator now gets all the way through all of my test file without crashing (albeit with register moves and swaps stubbed out). Correct code? Who knows. --- mach/proto/mcg/hop.c | 49 ++++-- mach/proto/mcg/hop.h | 3 + mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_registerallocator.c | 192 +++++++++++++++++++++++- 4 files changed, 227 insertions(+), 18 deletions(-) diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index d0a2dfcf3..68b776280 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -28,6 +28,13 @@ void hop_add_string_insel(struct hop* hop, const char* string) array_append(&hop->insels, insel); } +void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg) +{ + struct insel* insel = new_insel(INSEL_HREG); + insel->u.hreg = hreg; + array_append(&hop->insels, insel); +} + void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg) { struct insel* insel = new_insel(INSEL_VREG); @@ -48,10 +55,30 @@ void hop_add_eoi_insel(struct hop* hop) array_append(&hop->insels, insel); } +static void print_header(char k, struct hop* hop) +{ + int i; + + tracef(k, "%c: %d", k, hop->id); + if (hop->ir) + tracef(k, " from $%d", hop->ir->id); + tracef(k, ":"); + + for (i=0; iins.count; i++) + tracef(k, " r%%%d", hop->ins.item[i]->id); + for (i=0; ithroughs.count; i++) + tracef(k, " =%%%d", hop->throughs.item[i]->id); + for (i=0; iouts.count; i++) + tracef(k, " w%%%d", hop->outs.item[i]->id); + tracef(k, " "); +} + void hop_print(char k, struct hop* hop) { - int i, j; - bool soi = true; + int i; + bool soi = false; + + print_header(k, hop); i = 0; for (i=0; iinsels.count; i++) @@ -60,16 +87,7 @@ void hop_print(char k, struct hop* hop) if (soi) { - tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id); - - for (j=0; jins.count; j++) - tracef(k, " r%%%d", hop->ins.item[j]->id); - for (j=0; jthroughs.count; j++) - tracef(k, " =%%%d", hop->throughs.item[j]->id); - for (j=0; jouts.count; j++) - tracef(k, " w%%%d", hop->outs.item[j]->id); - tracef(k, " "); - + print_header(k, hop); soi = false; } @@ -80,6 +98,13 @@ void hop_print(char k, struct hop* hop) soi = true; break; + case INSEL_HREG: + { + struct hreg* hreg = insel->u.hreg; + tracef(k, "%s", hreg->name); + break; + } + case INSEL_VREG: { struct vreg* vreg = insel->u.vreg; diff --git a/mach/proto/mcg/hop.h b/mach/proto/mcg/hop.h index 4e7868c9a..34d5c116f 100644 --- a/mach/proto/mcg/hop.h +++ b/mach/proto/mcg/hop.h @@ -4,6 +4,7 @@ enum insel_type { INSEL_STRING, + INSEL_HREG, INSEL_VREG, INSEL_VALUE, INSEL_EOI @@ -15,6 +16,7 @@ struct insel union { const char* string; + struct hreg* hreg; struct vreg* vreg; struct ir* value; } @@ -46,6 +48,7 @@ struct hop extern struct hop* new_hop(struct basicblock* bb, struct ir* ir); extern void hop_add_string_insel(struct hop* hop, const char* string); +extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg); 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/mcg.h b/mach/proto/mcg/mcg.h index db4d570b3..e1b8083e1 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -106,6 +106,7 @@ extern void pass_convert_stack_ops(struct procedure* proc); extern void pass_eliminate_trivial_blocks(struct procedure* proc); extern void pass_find_phi_congruence_groups(void); extern void pass_group_irs(struct procedure* proc); +extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_vreg_analysis(void); extern void pass_promote_float_ops(struct procedure* proc); diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 2e2ad0764..f2d9fb6ab 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -3,6 +3,9 @@ static ARRAYOF(struct hreg) hregs; static int stacksize; +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs); + static void populate_hregs(void) { const struct burm_register_data* brd = burm_register_data; @@ -89,13 +92,10 @@ static void select_registers(struct hop* hop, } } -void pass_register_allocator(void) +static void assign_hregs_to_vregs(void) { int i, j, k; - populate_hregs(); - wire_up_blocks_ins_outs(); - for (i=0; iregsin; register_assignment_t* out = &hop->regsout;; + select_registers(hop, old, in, out); + 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); @@ -188,14 +190,192 @@ void pass_register_allocator(void) 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"); + tracef('R', " ["); + for (k=0; kregsin.count; k++) + { + struct hreg* hreg = hop->regsin.item[k].left; + struct vreg* vreg = hop->regsin.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->name); + } + tracef('R', "] ["); + for (k=0; kregsout.count; k++) + { + struct hreg* hreg = hop->regsout.item[k].left; + struct vreg* vreg = hop->regsout.item[k].right; + if (k != 0) + tracef('R', " "); + tracef('R', "%%%d=>%s", vreg->id, hreg->name); + } + tracef('R', "]\n"); - select_registers(hop, old, in, out); + if (j > 0) + j += insert_moves(bb, j, old, in); old = out; } } } +static struct hop* create_move(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + hop_add_string_insel(hop, "! move "); + hop_add_hreg_insel(hop, src); + hop_add_string_insel(hop, " -> "); + hop_add_hreg_insel(hop, dest); + hop_add_eoi_insel(hop); + + return hop; +} + +static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest) +{ + struct hop* hop = new_hop(bb, NULL); + + hop_add_string_insel(hop, "! swap "); + hop_add_hreg_insel(hop, src); + hop_add_string_insel(hop, " <-> "); + hop_add_hreg_insel(hop, dest); + hop_add_eoi_insel(hop); + + return hop; +} + +/* returns the number of instructions inserted */ +static int insert_moves(struct basicblock* bb, int index, + register_assignment_t* srcregs, register_assignment_t* destregs) +{ + int i; + int inserted = 0; + static PMAPOF(struct hreg, struct hreg) copies; + + copies.count = 0; + for (i=0; icount; i++) + { + struct hreg* dest = destregs->item[i].left; + struct vreg* vreg = destregs->item[i].right; + struct hreg* src = pmap_findright(srcregs, vreg); + assert(src != NULL); + + if (src != dest) + pmap_add(&copies, src, dest); + } + + while (copies.count > 0) + { + struct hreg* src; + struct hreg* dest; + struct hreg* temp; + struct hop* hop; + + /* Try and find a destination which isn't a source. */ + + src = NULL; + for (i=0; ihops, hop, index + inserted); + inserted++; + } + + return inserted; +} + +static void insert_phi_copies(void) +{ + int i, j, k; + + /* If we're importing an hreg from a parent block via a phi, insert a move + * at the end of the parent block to put the result into the right + * register. */ + + for (i=0; iprevs.count; j++) + { + struct basicblock* prevbb = bb->prevs.item[j]; + static register_assignment_t destregs; + + tracef('R', "R: inserting phis for %s -> %s\n", + prevbb->name, bb->name); + destregs.count = 0; + for (k=0; kphis.count; k++) + { + struct vreg* vreg = bb->phis.item[k].left; + struct phi* phi = bb->phis.item[k].right; + struct hreg* dest = pmap_findright(bb->regsin, vreg); + + if ((phi->prev == prevbb) && dest) + { + /* We inserted critical edges to guarantee this. */ + assert(prevbb->nexts.count == 1); + + tracef('R', "R: map %%%d -> %%%d (%s)\n", + phi->ir->result->id, + vreg->id, dest->name); + + pmap_put(&destregs, dest, phi->ir->result); + } + } + + /* Add any non-phi inputs. */ + + for (k=0; kregsin->count; k++) + { + struct hreg* hreg = bb->regsin->item[k].left; + struct vreg* vreg = bb->regsin->item[k].right; + if (!pmap_findleft(&bb->phis, vreg)) + pmap_add(&destregs, hreg, vreg); + } + + /* The last instruction of a block should be the jump that sends us + * to the next block. Insert the moves before then. */ + + insert_moves(prevbb, prevbb->hops.count-1, prevbb->regsout, &destregs); + } + } +} + +void pass_register_allocator(void) +{ + populate_hregs(); + wire_up_blocks_ins_outs(); + assign_hregs_to_vregs(); + insert_phi_copies(); +} + /* vim: set sw=4 ts=4 expandtab : */