From: David Given Date: Sat, 21 Jan 2017 19:51:32 +0000 (+0100) Subject: We now allocate fake registers! Although it's broken and needs reworking. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=27dfbc08b84cacf3460ba4d313ebe02715631d1f;p=ack.git We now allocate fake registers! Although it's broken and needs reworking. --- diff --git a/mach/proto/mcg/hop.c b/mach/proto/mcg/hop.c index eaf5baf77..4753bf99d 100644 --- a/mach/proto/mcg/hop.c +++ b/mach/proto/mcg/hop.c @@ -233,6 +233,20 @@ static char* appendf(const char* fmt, ...) return p; } +static struct vreg* actual(struct vreg* vreg) +{ + while (vreg->coalesced_with) + vreg = vreg->coalesced_with; + return vreg; +} + +void appendvreg(struct vreg* vreg) +{ + appendf("%%%d=%d", vreg->id, vreg->hreg); + if (vreg->is_spilt) + appendf("S"); +} + void appendvalue(struct hop* hop, struct value* value) { struct valueusage* usage = hop_get_value_usage(hop, value); @@ -255,7 +269,7 @@ void appendvalue(struct hop* hop, struct value* value) } if (vreg) - appendf("%%%d", vreg->id); + appendvreg(actual(vreg)); else appendf("$%d:%d", value->ir->id, value->subid); } @@ -303,6 +317,26 @@ char* hop_render(struct hop* hop) bufferlen = 0; buffer[0] = '\0'; + if (hop->is_move) + { + struct hashtable_iterator hit = {}; + appendf("@move:"); + while (hashtable_next(hop->valueusage, &hit)) + { + struct valueusage* usage = hit.value; + struct vreg* left = actual(usage->invreg); + struct vreg* right = actual(usage->outvreg); + if (left != right) + { + appendf(" "); + appendvreg(usage->invreg); + appendf("->"); + appendvreg(usage->outvreg); + } + } + appendf("\n"); + } + if (hop->pseudo) appendf("@"); diff --git a/mach/proto/mcg/pass_assignvregs.c b/mach/proto/mcg/pass_assignvregs.c index 88d882006..4238cf293 100644 --- a/mach/proto/mcg/pass_assignvregs.c +++ b/mach/proto/mcg/pass_assignvregs.c @@ -10,6 +10,7 @@ static struct vreg* create_vreg(struct value* value) struct vreg* vreg = heap_alloc(&proc_heap, 1, sizeof(*vreg)); vreg->id = vregcount++; vreg->value = value; + vreg->hreg = -1; return vreg; } diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 05f48e303..15c19e474 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -1,6 +1,7 @@ #include "mcg.h" #include "bigraph.h" #include "set.h" +#include "bitmap.h" #include /* This is based around the elegant graph colouring algorithm here: @@ -20,12 +21,13 @@ static struct vreg* actual(struct vreg* vreg) return vreg; } -static void coalesce(struct vreg* v1, struct vreg* v2) +static void coalesce(struct vreg* vmaster, struct vreg* vslave) { - tracef('R', "R: coalescing %%%d into %%%d\n", v1->id, v2->id); - v1 = actual(v1); - v2 = actual(v2); - v1->coalesced_with = v2; + vmaster = actual(vmaster); + vslave = actual(vslave); + bitmap_or(&vmaster->bitmap, 32, &vslave->bitmap); + vmaster->needs_register |= vslave->needs_register; + vslave->coalesced_with = vmaster; } static void wire_together_bbs(void) @@ -144,8 +146,8 @@ static void dump_interference_graph(void) static bool attempt_to_coalesce(void) { - struct vreg* v1 = NULL; - struct vreg* v2 = NULL; + struct vreg* vmaster = NULL; + struct vreg* vslave = NULL; int degree = INT_MAX; /* Find the affinity edge with the lowest interference degree. */ @@ -166,41 +168,124 @@ static bool attempt_to_coalesce(void) if (combined.count < degree) { - v1 = left; - v2 = right; + vmaster = left; + vslave = right; degree = combined.count; } } } - if (!v1) - return false; - if (degree > DEGREE) + if (!vmaster || (degree > DEGREE)) return false; tracef('R', "R: coalescing affinity edge: %%%d->%%%d, degree %d\n", - v1->id, v2->id, degree); - coalesce(v1, v2); + vmaster->id, vslave->id, degree); + coalesce(vmaster, vslave); - graph_merge_vertices(&affinity, v1, v2); - if (graph_get_vertex_degree(&affinity, v1) == 0) - graph_remove_vertex(&affinity, v1); + graph_merge_vertices(&affinity, vmaster, vslave); + if (graph_get_vertex_degree(&affinity, vslave) == 0) + graph_remove_vertex(&affinity, vslave); - graph_merge_vertices(&interference, v1, v2); + graph_merge_vertices(&interference, vmaster, vslave); return true; } static bool attempt_to_simplify(void) { - return false; + struct vreg* vreg = NULL; + int degree = INT_MAX; + + /* Find the vreg with the lowest degree that's not move-related (i.e. + * has no affinity edges). */ + + { + struct vertex_iterator vit = {}; + while (graph_next_vertex(&interference, &vit)) + { + struct vreg* v = vit.data; + if (graph_get_vertex_degree(&affinity, v) == 0) + { + int d = graph_get_vertex_degree(&interference, v); + if (d < degree) + { + vreg = v; + degree = d; + } + } + } + } + + if (!vreg || (degree > DEGREE)) + return false; + + /* Allocate a register. */ + + vreg->hreg = bitmap_find_unset_bit(&vreg->bitmap, 32); + tracef('R', "R: simplifying vreg %%%d with degree %d and bitmap 0x%x to hreg %d\n", + vreg->id, degree, vreg->bitmap, vreg->hreg); + { + struct neighbour_iterator nit = {}; + while (graph_next_neighbour(&interference, vreg, &nit)) + { + struct vreg* neighbour = nit.data; + bitmap_set(&neighbour->bitmap, 32, vreg->hreg); + } + } + + /* ...and remove it from the graph. */ + + graph_remove_vertex(&interference, vreg); + graph_remove_vertex(&affinity, vreg); + + return true; +} + +static bool attempt_to_spill(void) +{ + struct vreg* vreg = NULL; + int degree = INT_MIN; + + /* Find the spillable vreg with the *highest* degree. */ + + { + struct vertex_iterator vit = {}; + while (graph_next_vertex(&interference, &vit)) + { + struct vreg* v = vit.data; + if (!v->needs_register) + { + int d = graph_get_vertex_degree(&interference, v); + if (d > degree) + { + vreg = v; + degree = d; + } + } + } + } + + if (!vreg) + return false; + + tracef('R', "R: spilling vreg %%%d with degree %d\n", + vreg->id, degree); + vreg->is_spilt = true; + + /* ...and remove it from the graph. */ + + graph_remove_vertex(&interference, vreg); + graph_remove_vertex(&affinity, vreg); + + return true; } + static void iterate(void) { struct anode* spill; - while (true) + while (interference.vertices.size > 0) { tracef('R', "R: iterating; interference graph: %d, affinity graph: %d\n", interference.edges.table.size, affinity.edges.table.size); @@ -211,10 +296,10 @@ static void iterate(void) if (attempt_to_simplify()) continue; - // if (attempt_to_spill_or_simplify()) - // continue; + if (attempt_to_spill()) + continue; - break; + fatal("unable to allocate registers!"); } } @@ -223,9 +308,8 @@ void pass_register_allocator(void) wire_together_bbs(); generate_graph(); - //iterate(); - dump_interference_graph(); + iterate(); graph_reset(&interference); graph_reset(&affinity); diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 82160727d..100bbb44a 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -228,10 +228,10 @@ void procedure_compile(struct procedure* proc) #if 0 pass_add_prologue_epilogue(); print_hops('9'); +#endif emit_procedure(proc); -#endif heap_free(&proc_heap); } diff --git a/mach/proto/mcg/reg.h b/mach/proto/mcg/reg.h index d8e4053e1..cc5868dfa 100644 --- a/mach/proto/mcg/reg.h +++ b/mach/proto/mcg/reg.h @@ -18,7 +18,10 @@ struct vreg int id; struct value* value; struct vreg* coalesced_with; + int hreg; + unsigned int bitmap; bool needs_register; + bool is_spilt; }; extern struct hreg* new_hreg(const struct burm_register_data* brd);