Basic building and initial coalescing of the interference graph now works.
authorDavid Given <dg@cowlark.com>
Mon, 28 Nov 2016 22:38:38 +0000 (23:38 +0100)
committerDavid Given <dg@cowlark.com>
Mon, 28 Nov 2016 22:38:38 +0000 (23:38 +0100)
mach/proto/mcg/hop.c
mach/proto/mcg/hop.h
mach/proto/mcg/main.c
mach/proto/mcg/mcg.h
mach/proto/mcg/pass_registerallocator.c
mach/proto/mcg/reg.h

index 72464a8..c928b8f 100644 (file)
@@ -162,6 +162,22 @@ void hop_add_insel(struct hop* hop, const char* fmt, ...)
     va_end(ap);
 }
 
+void hop_walk(hop_walker_t* callback, void* user)
+{
+    int i, j, k;
+
+    for (i=0; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        for (j=0; j<bb->hops.count; j++)
+        {
+            struct hop* hop = bb->hops.item[j];
+            callback(hop, user);
+        }
+    }
+}
+
 static void print_header(char k, struct hop* hop)
 {
     int i;
index 21c7e92..d7b8f34 100644 (file)
@@ -66,6 +66,9 @@ extern void hop_add_eoi_insel(struct hop* hop);
 
 extern void hop_add_insel(struct hop* hop, const char* fmt, ...);
 
+typedef void hop_walker_t(struct hop* hop, void* user);
+extern void hop_walk(hop_walker_t* callback, void* user);
+
 extern char* hop_render(struct hop* hop);
 extern void hop_print(char k, struct hop* hop);
 
index cf8a443..bc776b5 100644 (file)
@@ -7,6 +7,7 @@ static const char* tracechars = NULL;
 FILE* outputfile = NULL;
 FILE* dominance_dot_file = NULL;
 FILE* cfg_dot_file = NULL;
+FILE* regalloc_dot_file = NULL;
 
 bool tracing(char k)
 {
@@ -37,6 +38,35 @@ static bool find_procedures_cb(struct symbol* symbol, void* user)
     return false;
 }
 
+static FILE* open_dot_file(const char* filename)
+{
+    FILE* fp = fopen(filename, "w");
+    if (!fp)
+        fatal("couldn't open output file '%s': %s",
+            filename, strerror(errno));
+    fprintf(fp, "digraph {\n");
+    return fp;
+}
+
+static void close_dot_files(void)
+{
+    if (cfg_dot_file)
+    {
+        fprintf(cfg_dot_file, "}\n");
+        fclose(cfg_dot_file);
+    }
+    if (dominance_dot_file)
+    {
+        fprintf(dominance_dot_file, "}\n");
+        fclose(dominance_dot_file);
+    }
+    if (regalloc_dot_file)
+    {
+        fprintf(regalloc_dot_file, "}\n");
+        fclose(regalloc_dot_file);
+    }
+}
+
 int main(int argc, char* const argv[])
 {
     const char* inputfilename = NULL;
@@ -48,26 +78,22 @@ int main(int argc, char* const argv[])
     opterr = 1;
     for (;;)
     {
-        int c = getopt(argc, argv, "-d:D:C:o:");
+        int c = getopt(argc, argv, "-d:D:C:R:o:");
         if (c == -1)
             break;
 
         switch (c)
         {
             case 'C':
-                cfg_dot_file = fopen(optarg, "w");
-                if (!cfg_dot_file)
-                    fatal("couldn't open output file '%s': %s",
-                        optarg, strerror(errno));
-                fprintf(cfg_dot_file, "digraph {\n");
+                cfg_dot_file = open_dot_file(optarg);
                 break;
 
             case 'D':
-                dominance_dot_file = fopen(optarg, "w");
-                if (!dominance_dot_file)
-                    fatal("couldn't open output file '%s': %s",
-                        optarg, strerror(errno));
-                fprintf(dominance_dot_file, "digraph {\n");
+                dominance_dot_file = open_dot_file(optarg);
+                break;
+
+            case 'R':
+                regalloc_dot_file = open_dot_file(optarg);
                 break;
 
             case 'd':
@@ -86,6 +112,7 @@ int main(int argc, char* const argv[])
                 inputfilename = optarg;
         }
     }
+    atexit(close_dot_files);
 
     symbol_init();
 
@@ -120,17 +147,6 @@ int main(int argc, char* const argv[])
         fclose(outputfile);
        EM_close();
 
-    if (cfg_dot_file)
-    {
-        fprintf(cfg_dot_file, "}\n");
-        fclose(cfg_dot_file);
-    }
-    if (dominance_dot_file)
-    {
-        fprintf(dominance_dot_file, "}\n");
-        fclose(dominance_dot_file);
-    }
-
        return 0;
 }
 
index 8607042..6ea7c61 100644 (file)
@@ -131,6 +131,7 @@ extern const char* platform_label(const char* label);
 extern FILE* outputfile;
 extern FILE* dominance_dot_file;
 extern FILE* cfg_dot_file;
+extern FILE* regalloc_dot_file;
 
 #endif
 
index a5436bc..f5187e2 100644 (file)
@@ -1,5 +1,28 @@
 #include "mcg.h"
 
+/* This is based around the elegant graph colouring algorithm here:
+ * 
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.32.5924
+ *
+struct anode
+{
+    int id;
+    int degree;
+    struct vref* vref;
+};
+
+struct vref
+{
+    struct vref* next;
+    struct vreg* vreg;
+};
+
+static struct heap anode_heap;
+static bool interference_graph_valid;
+static PMAPOF(struct anode, struct anode) interference;
+static ARRAYOF(struct anode) vertices;
+static ARRAYOF(struct anode) simplified;
+#if 0
 struct assignment
 {
     struct vreg* in;
@@ -756,15 +779,227 @@ static void layout_stack_frame(void)
     stacksize = pack_stackframe(stacksize, EM_wordsize*1, burm_int_ATTR);
     current_proc->spills_size = stacksize;
 }
+#endif
+
+static void walk_vregs(void (*callback)(struct vreg* vreg))
+{
+    int i, j, k;
+
+    interference.count = 0;
+    for (i=0; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        for (j=0; j<bb->hops.count; j++)
+        {
+            struct hop* hop = bb->hops.item[j];
+
+            for (k=0; k<hop->ins.count; k++)
+                callback(hop->ins.item[k]);
+            for (k=0; k<hop->outs.count; k++)
+                callback(hop->outs.item[k]);
+            for (k=0; k<hop->throughs.count; k++)
+                callback(hop->throughs.item[k]);
+        }
+    }
+}
+
+static void clear_anode_cb(struct vreg* vreg)
+{
+    vreg->anode = NULL;
+}
+
+static void assign_anode_cb(struct vreg* vreg)
+{
+    static int id = 1;
+    struct anode* anode = heap_alloc(&anode_heap, 1, sizeof(*anode));
+    struct vref* vref = heap_alloc(&anode_heap, 1, sizeof(*vref));
+    anode->id = id++;
+    anode->vref = vref;
+    vref->vreg = vreg;
+    vreg->anode = anode;
+}
+
+/* Calling this makes the interference graph invalid */
+static void coalesce_anodes(struct anode* left, struct anode* right)
+{
+    struct vref* vref;
+    int i;
+
+    if (left == right)
+        return;
+
+    vref = left->vref;
+    if (vref)
+    {
+        while (vref->next)
+            vref = vref->next;
+        vref = vref->next = right->vref;
+    }
+    else
+        vref = left->vref = right->vref;
+
+    while (vref)
+    {
+        vref->vreg->anode = left;
+        vref = vref->next;
+    }
+
+    interference_graph_valid = false;
+}
+
+static void coalesce_phis(void)
+{
+    int i, j;
+
+    interference.count = 0;
+    for (i=0; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        for (j=0; j<bb->phis.count; j++)
+        {
+            struct vreg* dest = bb->phis.item[j].left;
+            struct phi* phi = bb->phis.item[j].right;
+            struct vreg* src = phi->ir->result;
+
+            coalesce_anodes(src->anode, dest->anode);
+        }
+    }
+}
+
+static void interferes_with(struct vreg** regs1, int count1, struct vreg** regs2, int count2)
+{
+    int i, j;
+
+    for (i=0; i<count1; i++)
+    {
+        struct anode* left = regs1[i]->anode;
+
+        for (j=0; j<count2; j++)
+        {
+            struct anode* right = regs2[j]->anode;
+
+            if (left != right)
+                pmap_add_bi(&interference, left, right);
+        }
+    }
+}
+
+static void dump_anode(struct anode* anode)
+{
+    struct vref* vref;
+
+    fprintf(regalloc_dot_file, "%s.%d deg %d\n",
+        current_proc->name, anode->id, anode->degree);
+    vref = anode->vref;
+    while (vref)
+    {
+        fprintf(regalloc_dot_file, "%%%d ", vref->vreg->id);
+        vref = vref->next;
+    }
+}
+
+static void dump_interference_graph(void)
+{
+    int i;
+
+    fprintf(regalloc_dot_file, "subgraph \"%s\" {\n", current_proc->name);
+
+    for (i=0; i<interference.count; i++)
+    {
+        fprintf(regalloc_dot_file, "\t\"");
+        dump_anode(interference.item[i].left);
+        fprintf(regalloc_dot_file, "\" -> \"");
+        dump_anode(interference.item[i].right);
+        fprintf(regalloc_dot_file, "\";\n");
+    }
+
+    fprintf(regalloc_dot_file, "}\n");
+}
+
+static void build_interference_graph_cb(struct hop* hop, void* user)
+{
+    int i;
+
+    interferes_with(hop->ins.item, hop->ins.count, hop->ins.item, hop->ins.count);
+    interferes_with(hop->outs.item, hop->outs.count, hop->outs.item, hop->outs.count);
+    interferes_with(hop->throughs.item, hop->throughs.count, hop->throughs.item, hop->throughs.count);
+    interferes_with(hop->throughs.item, hop->throughs.count, hop->ins.item, hop->ins.count);
+    interferes_with(hop->throughs.item, hop->throughs.count, hop->outs.item, hop->outs.count);
+
+    for (i=0; i<hop->constraints.count; i++)
+    {
+        struct vreg* vreg = hop->constraints.item[i].left;
+        struct constraint* c = hop->constraints.item[i].right;
+
+        if (c->preserved)
+            interferes_with(&vreg, 1, hop->outs.item, hop->outs.count);
+        if (c->equals_to)
+            coalesce_anodes(vreg->anode, c->equals_to->anode);
+    }
+}
+
+void collect_vertices(void)
+{
+    int i;
+
+    vertices.count = 0;
+    for (i=0; i<interference.count; i++)
+    {
+        array_appendu(&vertices, interference.item[i].left);
+        array_appendu(&vertices, interference.item[i].right);
+    }
+}
+
+void update_degrees(void)
+{
+    int i, j;
+
+    for (i=0; i<vertices.count; i++)
+    {
+        struct anode* candidate = vertices.item[i];
+
+        candidate->degree = 0;
+        for (j=0; j<interference.count; j++)
+        {
+            if (interference.item[j].left == candidate)
+                candidate->degree++;
+            if (interference.item[j].right == candidate)
+                candidate->degree++;
+        }
+    }
+}
 
 void pass_register_allocator(void)
 {
+    simplified.count = 0;
+    walk_vregs(clear_anode_cb);
+    walk_vregs(assign_anode_cb);
+    coalesce_phis();
+
+    do
+    {
+        interference_graph_valid = true;
+        hop_walk(build_interference_graph_cb, NULL);
+    }
+    while (!interference_graph_valid);
+
+    collect_vertices();
+    update_degrees();
+
+    dump_interference_graph();
+    heap_free(&anode_heap);
+
+    exit(1);
+    #if 0
     populate_hregs();
     wire_up_blocks_ins_outs();
 
     assign_hregs_to_vregs();
     insert_phi_copies();
     layout_stack_frame();
+    #endif
 }
 
 /* vim: set sw=4 ts=4 expandtab : */
index 00c8220..d1c4cbc 100644 (file)
@@ -27,6 +27,7 @@ struct vreg
     uint32_t type;
     struct phicongruence* congruence;
     struct hop* defined;
+    struct anode* anode;
     ARRAYOF(struct hop) used;
 };