From: David Given Date: Thu, 2 Feb 2017 22:18:00 +0000 (+0100) Subject: Add a couple of passes to collapse and prune moves together, which keeps the X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ba502fe970f2d3dcf2e22ad910d5340abdbef808;p=ack.git Add a couple of passes to collapse and prune moves together, which keeps the number of vregs under vastly better control; also remember that you can't coalesce vregs connected with an interference edge (because they have to be different). The generated register assignments now look sort of correct. --- diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index c7a81f0bb..26ba4e655 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -109,6 +109,7 @@ extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, extern void pass_assign_vregs(void); extern void pass_calculate_vreg_spillibility(void); +extern void pass_collapse_adjacent_moves(void); extern void pass_convert_copies_to_moves(void); extern void pass_convert_inputs_to_phis(void); extern void pass_convert_locals_to_ssa(void); @@ -122,6 +123,7 @@ extern void pass_insert_moves(void); extern void pass_instruction_selector(void); extern void pass_live_value_analysis(void); extern void pass_add_prologue_epilogue(void); +extern void pass_prune_stray_moves(void); extern void pass_register_allocator(void); extern void pass_remove_dead_blocks(void); extern void pass_remove_dead_phis(void); diff --git a/mach/proto/mcg/pass_collapsemoves.c b/mach/proto/mcg/pass_collapsemoves.c new file mode 100644 index 000000000..bd2ff2db5 --- /dev/null +++ b/mach/proto/mcg/pass_collapsemoves.c @@ -0,0 +1,57 @@ +#include "mcg.h" + +static struct vreg* find_source_of_vreg(struct hop* hop, struct vreg* vreg); + +static void merge(struct hop* master, struct hop* slave) +{ + int i, j; + + for (i=0; ivregusage.count; i++) + { + struct vreg* sinput = slave->vregusage.item[i].left; + struct vreg* soutput = slave->vregusage.item[i].right; + + if (sinput && soutput) + { + for (j=0; jvregusage.count; j++) + { + struct vreg* minput = master->vregusage.item[j].left; + struct vreg* moutput = master->vregusage.item[j].right; + + if (minput && moutput && (sinput == moutput)) + { + /* The input of the slave was written by the master; so instead source + * the slave's copy from the source of the master. */ + sinput = minput; + break; + } + } + + hop_add_through_vreg(master, sinput, soutput); + } + } +} + +void pass_collapse_adjacent_moves(void) +{ + int i, j; + + for (i=0; ihops.count-1)) + { + struct hop* firstmove = bb->hops.item[j]; + struct hop* secondmove = bb->hops.item[j+1]; + if (firstmove->is_move && secondmove->is_move) + { + merge(firstmove, secondmove); + array_remove(&bb->hops, secondmove); + } + else + j++; + } + } +} diff --git a/mach/proto/mcg/pass_prunestraymoves.c b/mach/proto/mcg/pass_prunestraymoves.c new file mode 100644 index 000000000..b2eff58fd --- /dev/null +++ b/mach/proto/mcg/pass_prunestraymoves.c @@ -0,0 +1,56 @@ +#include "mcg.h" + +static struct vreg* find_source_of_vreg(struct hop* hop, struct vreg* vreg); + +static void prune(struct hop* master, struct hop* slave) +{ + int i, j; + + for (i=0; ivregusage.count; i++) + { + struct vreg* minput = master->vregusage.item[i].left; + struct vreg* moutput = master->vregusage.item[i].right; + + if (moutput) + { + bool found = false; + + for (j=0; jvregusage.count; j++) + { + struct vreg* sinput = slave->vregusage.item[j].left; + struct vreg* soutput = slave->vregusage.item[j].right; + + if (sinput == moutput) + { + found = true; + break; + } + } + + if (!found) + { + pmap_remove_index(&master->vregusage, i); + i--; + } + } + } +} + +void pass_prune_stray_moves(void) +{ + int i, j; + + for (i=0; ihops.count-1); j++) + { + struct hop* firstmove = bb->hops.item[j]; + struct hop* secondmove = bb->hops.item[j+1]; + if (firstmove->is_move && !secondmove->is_move) + prune(firstmove, secondmove); + } + } +} + diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index b2ffa7912..9327dc2ee 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -68,17 +68,18 @@ static void generate_graph(void) struct vreg* invreg1 = actual(hop->vregusage.item[k].left); struct vreg* outvreg1 = actual(hop->vregusage.item[k].right); + if (invreg1) + graph_add_vertex(&interference, invreg1); + if (outvreg1) + graph_add_vertex(&interference, outvreg1); + for (m=k; mvregusage.count; m++) { struct vreg* invreg2 = actual(hop->vregusage.item[m].left); struct vreg* outvreg2 = actual(hop->vregusage.item[m].right); - if (invreg1) - graph_add_vertex(&interference, invreg1); if (invreg2) graph_add_vertex(&interference, invreg2); - if (outvreg1) - graph_add_vertex(&interference, outvreg1); if (outvreg2) graph_add_vertex(&interference, outvreg2); @@ -95,6 +96,16 @@ static void generate_graph(void) } } +static void check_graph(void) +{ + struct edge_iterator eit = {}; + while (graph_next_edge(&interference, &eit)) + assert(!graph_contains_edge(&affinity, eit.left, eit.right)); + + while (graph_next_edge(&affinity, &eit)) + assert(!graph_contains_edge(&interference, eit.left, eit.right)); +} + static void dump_vreg(struct vreg* vreg) { fprintf(regalloc_dot_file, "[%%%d]", vreg->id); @@ -178,7 +189,7 @@ static bool attempt_to_coalesce(void) thisdegree++; } - if (thisdegree < degree) + if ((thisdegree < degree) && !graph_contains_edge(&interference, left, right)) { vmaster = left; vslave = right; @@ -375,6 +386,7 @@ void pass_register_allocator(void) { wire_together_bbs(); generate_graph(); + check_graph(); dump_interference_graph(); simplified.count = 0; diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 129df5388..b9bd4857a 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -186,16 +186,18 @@ void procedure_compile(struct procedure* proc) current_proc = proc; pass_group_irs(); - print_blocks('1'); + print_blocks('a'); /* Passes from here on must preserve IR grouping */ pass_eliminate_trivial_blocks(); pass_remove_dead_blocks(); - print_blocks('2'); + print_blocks('b'); update_graph_data(); + print_blocks('c'); pass_split_critical_edges(); + print_blocks('d'); update_graph_data(); if (cfg_dot_file) @@ -206,27 +208,37 @@ void procedure_compile(struct procedure* proc) /* Passes from here on can't alter the BB graph without also updating prevs * and nexts (and then calling update_graph_data()). */ - print_blocks('3'); + print_blocks('e'); pass_wire_up_return_values(); + print_blocks('f'); pass_convert_stack_ops(); + print_blocks('g'); pass_convert_locals_to_ssa(); - print_blocks('4'); + print_blocks('h'); pass_convert_inputs_to_phis(); + print_blocks('i'); pass_convert_nonlocal_phis(); + print_blocks('j'); pass_remove_dead_phis(); - print_blocks('5'); + print_blocks('k'); pass_infer_types(); - print_blocks('6'); + print_blocks('l'); pass_instruction_selector(); - print_hops('7'); + print_hops('m'); pass_live_value_analysis(); - print_hops('8'); + print_hops('n'); pass_assign_vregs(); - pass_calculate_vreg_spillibility(); + print_hops('o'); pass_convert_copies_to_moves(); - print_hops('9'); + print_hops('p'); + pass_collapse_adjacent_moves(); + print_hops('q'); + pass_prune_stray_moves(); + print_hops('r'); + pass_calculate_vreg_spillibility(); + print_hops('s'); pass_register_allocator(); - print_hops('a'); + print_hops('t'); #if 0 pass_add_prologue_epilogue(); print_hops('9');