Add a couple of passes to collapse and prune moves together, which keeps the
authorDavid Given <dg@cowlark.com>
Thu, 2 Feb 2017 22:18:00 +0000 (23:18 +0100)
committerDavid Given <dg@cowlark.com>
Thu, 2 Feb 2017 22:18:00 +0000 (23:18 +0100)
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.

mach/proto/mcg/mcg.h
mach/proto/mcg/pass_collapsemoves.c [new file with mode: 0644]
mach/proto/mcg/pass_prunestraymoves.c [new file with mode: 0644]
mach/proto/mcg/pass_registerallocator.c
mach/proto/mcg/procedure.c

index c7a81f0..26ba4e6 100644 (file)
@@ -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 (file)
index 0000000..bd2ff2d
--- /dev/null
@@ -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; i<slave->vregusage.count; i++)
+    {
+        struct vreg* sinput = slave->vregusage.item[i].left;
+        struct vreg* soutput = slave->vregusage.item[i].right;
+
+        if (sinput && soutput)
+        {
+            for (j=0; j<master->vregusage.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; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        j = 0;
+        while (j < (bb->hops.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 (file)
index 0000000..b2eff58
--- /dev/null
@@ -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; i<master->vregusage.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; j<slave->vregusage.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; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        for (j=0; j<(bb->hops.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);
+        }
+    }
+}
+
index b2ffa79..9327dc2 100644 (file)
@@ -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; m<hop->vregusage.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;
index 129df53..b9bd485 100644 (file)
@@ -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');