Add a pass to do critical edge splitting.
authorDavid Given <dg@cowlark.com>
Tue, 4 Oct 2016 21:42:00 +0000 (23:42 +0200)
committerDavid Given <dg@cowlark.com>
Tue, 4 Oct 2016 21:42:00 +0000 (23:42 +0200)
mach/proto/mcg/mcg.h
mach/proto/mcg/pass_splitcriticaledges.c [new file with mode: 0644]
mach/proto/mcg/procedure.c

index a5fa110..dc70028 100644 (file)
@@ -100,13 +100,14 @@ extern void tb_fileend(void);
 extern void tb_procedure(struct procedure* proc);
 extern void tb_regvar(struct procedure* proc, arith offset, int size, int type, int priority);
 
+extern void pass_convert_locals_to_ssa(struct procedure* proc);
 extern void pass_convert_stack_ops(struct procedure* proc);
-extern void pass_remove_dead_blocks(struct procedure* proc);
 extern void pass_eliminate_trivial_blocks(struct procedure* proc);
+extern void pass_group_irs(struct procedure* proc);
 extern void pass_instruction_selector(struct procedure* proc);
 extern void pass_promote_float_ops(struct procedure* proc);
-extern void pass_group_irs(struct procedure* proc);
-extern void pass_convert_locals_to_ssa(struct procedure* proc);
+extern void pass_remove_dead_blocks(struct procedure* proc);
+extern void pass_split_critical_edges(struct procedure* proc);
 
 #endif
 
diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c
new file mode 100644 (file)
index 0000000..a7fa63e
--- /dev/null
@@ -0,0 +1,91 @@
+#include "mcg.h"
+
+/* Insert empty nodes at certain places in the basic block graph so that when
+ * we convert out of SSA form, we have somewhere to insert copies. This is
+ * necessary for correctness in certain circumstances. The best explanation of
+ * why I've found is here, starting at the bottom of page 23.
+ *
+ * Briggs, Preston, et al.
+ * "Practical improvements to the construction and destruction of static single assignment form."
+ * Software-Practice and experience 28.8 (1998): 859-882.
+ *
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.25.749
+ */
+
+static struct procedure* current_proc;
+
+struct rewrite_params
+{
+       struct basicblock* find;
+       struct basicblock* replace;
+};
+
+static bool find_replace_cb(struct ir* ir, void* user)
+{
+       struct rewrite_params* rwp = user;
+
+       if ((ir->opcode == IR_BLOCK) && (ir->u.bvalue == rwp->find))
+               ir->u.bvalue = rwp->replace;
+       
+       return false;
+}
+
+static void split_edge(struct basicblock* source, struct basicblock* sink)
+{
+       int i;
+       struct rewrite_params rwp;
+       struct basicblock* bb = bb_get(NULL);
+       
+       array_append(&bb->irs,
+               new_ir1(
+                       IR_JUMP, 0,
+                       new_bbir(sink)
+               )
+       );
+
+       rwp.find = sink;
+       rwp.replace = bb;
+
+       for (i=0; i<source->irs.count; i++)
+               ir_walk(source->irs.item[i], find_replace_cb, &rwp);
+
+       array_remove(&source->nexts, sink);
+       array_append(&source->nexts, bb);
+
+       array_append(&bb->prevs, source);
+       array_append(&bb->nexts, sink);
+
+       array_remove(&sink->prevs, source);
+       array_append(&sink->prevs, bb);
+
+       array_append(&current_proc->blocks, bb);
+}
+
+static void consider_edges_leading_to(struct basicblock* bb)
+{
+       if (bb->prevs.count > 1)
+       {
+               int i;
+
+               for (i=0; i<bb->prevs.count; i++)
+               {
+                       struct basicblock* prev = bb->prevs.item[i];
+                       if (prev->nexts.count > 1)
+                               split_edge(prev, bb);
+               }
+       }
+}
+
+void pass_split_critical_edges(struct procedure* proc)
+{
+       int i;
+
+       current_proc = proc;
+
+    for (i=0; i<proc->blocks.count; i++)
+               consider_edges_leading_to(proc->blocks.item[i]);
+}
+
+/* vim: set sw=4 ts=4 expandtab : */
+
+
index 5ea0372..8fbccd5 100644 (file)
@@ -15,7 +15,23 @@ static void print_blocks(char k, struct procedure* proc)
             bb->is_fake ? "FAKE " : "",
             bb->name);
 
-               for (int j=0; j<bb->irs.count; j++)
+        if (bb->prevs.count > 0)
+        {
+            tracef(k, "%c: FROM:", k);
+            for (j=0; j<bb->prevs.count; j++)
+                tracef(k, " %s", bb->prevs.item[j]->name);
+            tracef(k, "\n");
+        }
+
+        if (bb->nexts.count > 0)
+        {
+            tracef(k, "%c:   TO:", k);
+            for (j=0; j<bb->nexts.count; j++)
+                tracef(k, " %s", bb->nexts.item[j]->name);
+            tracef(k, "\n");
+        }
+
+               for (j=0; j<bb->irs.count; j++)
                        ir_print(k, bb->irs.item[j]);
        }
 }
@@ -40,8 +56,10 @@ void procedure_compile(struct procedure* proc)
     print_blocks('3', proc);
     pass_convert_locals_to_ssa(proc);
     print_blocks('4', proc);
-    pass_promote_float_ops(proc);
+    pass_split_critical_edges(proc);
     print_blocks('5', proc);
+    pass_promote_float_ops(proc);
+    print_blocks('6', proc);
 
 
     pass_instruction_selector(proc);