Register allocator now gets all the way through all of my test file without
authorDavid Given <dg@cowlark.com>
Mon, 10 Oct 2016 21:19:46 +0000 (23:19 +0200)
committerDavid Given <dg@cowlark.com>
Mon, 10 Oct 2016 21:19:46 +0000 (23:19 +0200)
crashing (albeit with register moves and swaps stubbed out). Correct code? Who
knows.

mach/proto/mcg/hop.c
mach/proto/mcg/hop.h
mach/proto/mcg/mcg.h
mach/proto/mcg/pass_registerallocator.c

index d0a2dfc..68b7762 100644 (file)
@@ -28,6 +28,13 @@ void hop_add_string_insel(struct hop* hop, const char* string)
        array_append(&hop->insels, insel);
 }
 
+void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg)
+{
+       struct insel* insel = new_insel(INSEL_HREG);
+       insel->u.hreg = hreg;
+       array_append(&hop->insels, insel);
+}
+
 void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg)
 {
        struct insel* insel = new_insel(INSEL_VREG);
@@ -48,10 +55,30 @@ void hop_add_eoi_insel(struct hop* hop)
        array_append(&hop->insels, insel);
 }
 
+static void print_header(char k, struct hop* hop)
+{
+    int i;
+
+    tracef(k, "%c: %d", k, hop->id);
+    if (hop->ir)
+        tracef(k, " from $%d", hop->ir->id);
+    tracef(k, ":");
+
+    for (i=0; i<hop->ins.count; i++)
+        tracef(k, " r%%%d", hop->ins.item[i]->id);
+    for (i=0; i<hop->throughs.count; i++)
+        tracef(k, " =%%%d", hop->throughs.item[i]->id);
+    for (i=0; i<hop->outs.count; i++)
+        tracef(k, " w%%%d", hop->outs.item[i]->id);
+    tracef(k, " ");
+}
+
 void hop_print(char k, struct hop* hop)
 {
-       int i, j;
-       bool soi = true;
+       int i;
+       bool soi = false;
+
+    print_header(k, hop);
 
        i = 0;
        for (i=0; i<hop->insels.count; i++)
@@ -60,16 +87,7 @@ void hop_print(char k, struct hop* hop)
 
                if (soi)
                {
-                       tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id);
-
-                       for (j=0; j<hop->ins.count; j++)
-                               tracef(k, " r%%%d", hop->ins.item[j]->id);
-                       for (j=0; j<hop->throughs.count; j++)
-                               tracef(k, " =%%%d", hop->throughs.item[j]->id);
-                       for (j=0; j<hop->outs.count; j++)
-                               tracef(k, " w%%%d", hop->outs.item[j]->id);
-                       tracef(k, " ");
-
+            print_header(k, hop);
                        soi = false;
                }
 
@@ -80,6 +98,13 @@ void hop_print(char k, struct hop* hop)
                                soi = true;
                                break;
 
+            case INSEL_HREG:
+            {
+                struct hreg* hreg = insel->u.hreg;
+                tracef(k, "%s", hreg->name);
+                break;
+            }
+
                        case INSEL_VREG:
             {
                 struct vreg* vreg = insel->u.vreg;
index 4e7868c..34d5c11 100644 (file)
@@ -4,6 +4,7 @@
 enum insel_type
 {
        INSEL_STRING,
+    INSEL_HREG,
        INSEL_VREG,
        INSEL_VALUE,
        INSEL_EOI
@@ -15,6 +16,7 @@ struct insel
        union
        {
                const char* string;
+        struct hreg* hreg;
                struct vreg* vreg;
                struct ir* value;
        }
@@ -46,6 +48,7 @@ struct hop
 extern struct hop* new_hop(struct basicblock* bb, struct ir* ir);
 
 extern void hop_add_string_insel(struct hop* hop, const char* string);
+extern void hop_add_hreg_insel(struct hop* hop, struct hreg* hreg);
 extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg);
 extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
 extern void hop_add_eoi_insel(struct hop* hop);
index db4d570..e1b8083 100644 (file)
@@ -106,6 +106,7 @@ extern void pass_convert_stack_ops(struct procedure* proc);
 extern void pass_eliminate_trivial_blocks(struct procedure* proc);
 extern void pass_find_phi_congruence_groups(void);
 extern void pass_group_irs(struct procedure* proc);
+extern void pass_insert_moves(void);
 extern void pass_instruction_selector(void);
 extern void pass_live_vreg_analysis(void);
 extern void pass_promote_float_ops(struct procedure* proc);
index 2e2ad07..f2d9fb6 100644 (file)
@@ -3,6 +3,9 @@
 static ARRAYOF(struct hreg) hregs;
 static int stacksize;
 
+static int insert_moves(struct basicblock* bb, int index,
+    register_assignment_t* srcregs, register_assignment_t* destregs);
+
 static void populate_hregs(void)
 {
     const struct burm_register_data* brd = burm_register_data;
@@ -89,13 +92,10 @@ static void select_registers(struct hop* hop,
     }
 }
 
-void pass_register_allocator(void)
+static void assign_hregs_to_vregs(void)
 {
     int i, j, k;
 
-    populate_hregs();
-    wire_up_blocks_ins_outs();
-
     for (i=0; i<dominance.preorder.count; i++)
     {
         struct basicblock* bb = dominance.preorder.item[i];
@@ -181,6 +181,8 @@ void pass_register_allocator(void)
             register_assignment_t* in = &hop->regsin;
             register_assignment_t* out = &hop->regsout;;
 
+            select_registers(hop, old, in, out);
+
                        tracef('R', "R: %d from $%d:", hop->id, hop->ir->id);
                        for (k=0; k<hop->ins.count; k++)
                                tracef('R', " r%%%d", hop->ins.item[k]->id);
@@ -188,14 +190,192 @@ void pass_register_allocator(void)
                                tracef('R', " =%%%d", hop->throughs.item[k]->id);
                        for (k=0; k<hop->outs.count; k++)
                                tracef('R', " w%%%d", hop->outs.item[k]->id);
-            tracef('R', "\n");
+            tracef('R', " [");
+            for (k=0; k<hop->regsin.count; k++)
+            {
+                struct hreg* hreg = hop->regsin.item[k].left;
+                struct vreg* vreg = hop->regsin.item[k].right;
+                if (k != 0)
+                    tracef('R', " ");
+                tracef('R', "%%%d=>%s", vreg->id, hreg->name);
+            }
+            tracef('R', "] [");
+            for (k=0; k<hop->regsout.count; k++)
+            {
+                struct hreg* hreg = hop->regsout.item[k].left;
+                struct vreg* vreg = hop->regsout.item[k].right;
+                if (k != 0)
+                    tracef('R', " ");
+                tracef('R', "%%%d=>%s", vreg->id, hreg->name);
+            }
+            tracef('R', "]\n");
 
-            select_registers(hop, old, in, out);
+            if (j > 0)
+                j += insert_moves(bb, j, old, in);
 
             old = out;
         }
     }
 }
 
+static struct hop* create_move(struct basicblock* bb, struct hreg* src, struct hreg* dest)
+{
+    struct hop* hop = new_hop(bb, NULL);
+
+    hop_add_string_insel(hop, "! move ");
+    hop_add_hreg_insel(hop, src);
+    hop_add_string_insel(hop, " -> ");
+    hop_add_hreg_insel(hop, dest);
+    hop_add_eoi_insel(hop);
+
+    return hop;
+}
+
+static struct hop* create_swap(struct basicblock* bb, struct hreg* src, struct hreg* dest)
+{
+    struct hop* hop = new_hop(bb, NULL);
+
+    hop_add_string_insel(hop, "! swap ");
+    hop_add_hreg_insel(hop, src);
+    hop_add_string_insel(hop, " <-> ");
+    hop_add_hreg_insel(hop, dest);
+    hop_add_eoi_insel(hop);
+
+    return hop;
+}
+
+/* returns the number of instructions inserted */
+static int insert_moves(struct basicblock* bb, int index,
+    register_assignment_t* srcregs, register_assignment_t* destregs)
+{
+    int i;
+    int inserted = 0;
+    static PMAPOF(struct hreg, struct hreg) copies;
+
+    copies.count = 0;
+    for (i=0; i<destregs->count; i++)
+    {
+        struct hreg* dest = destregs->item[i].left;
+        struct vreg* vreg = destregs->item[i].right;
+        struct hreg* src = pmap_findright(srcregs, vreg);
+        assert(src != NULL);
+
+        if (src != dest)
+            pmap_add(&copies, src, dest);
+    }
+
+    while (copies.count > 0)
+    {
+        struct hreg* src;
+        struct hreg* dest;
+        struct hreg* temp;
+        struct hop* hop;
+
+        /* Try and find a destination which isn't a source. */
+
+        src = NULL;
+        for (i=0; i<copies.count; i++)
+        {
+            dest = copies.item[i].right;
+            if (!pmap_findleft(&copies, dest))
+            {
+                src = copies.item[i].left;
+                break;
+            }
+        }
+
+        if (src)
+        {
+            /* Copy. */
+
+            hop = create_move(bb, src, dest);
+            pmap_remove(&copies, src, dest);
+        }
+        else
+        {
+            /* Swap. */
+
+            src = copies.item[0].left;
+            dest = pmap_findleft(&copies, src);
+            hop = create_move(bb, src, dest);
+            pmap_remove(&copies, src, dest);
+            pmap_remove(&copies, dest, src);
+        }
+
+        array_insert(&bb->hops, hop, index + inserted);
+        inserted++;
+    }
+
+    return inserted;
+}
+
+static void insert_phi_copies(void)
+{
+    int i, j, k;
+
+    /* If we're importing an hreg from a parent block via a phi, insert a move
+     * at the end of the parent block to put the result into the right
+     * register. */
+
+    for (i=0; i<cfg.preorder.count; i++)
+    {
+        struct basicblock* bb = cfg.preorder.item[i];
+
+        /* Group together copies from each predecessor, so we can generate the
+         * appropriate parallel move. */
+
+        for (j=0; j<bb->prevs.count; j++)
+        {
+            struct basicblock* prevbb = bb->prevs.item[j];
+            static register_assignment_t destregs;
+
+            tracef('R', "R: inserting phis for %s -> %s\n",
+                prevbb->name, bb->name);
+            destregs.count = 0;
+            for (k=0; k<bb->phis.count; k++)
+            {
+                struct vreg* vreg = bb->phis.item[k].left;
+                struct phi* phi = bb->phis.item[k].right;
+                struct hreg* dest = pmap_findright(bb->regsin, vreg);
+
+                if ((phi->prev == prevbb) && dest)
+                {
+                    /* We inserted critical edges to guarantee this. */
+                    assert(prevbb->nexts.count == 1);
+
+                    tracef('R', "R: map %%%d -> %%%d (%s)\n",
+                        phi->ir->result->id, 
+                        vreg->id, dest->name);
+
+                    pmap_put(&destregs, dest, phi->ir->result);
+                }
+            }
+
+            /* Add any non-phi inputs. */
+
+            for (k=0; k<bb->regsin->count; k++)
+            {
+                struct hreg* hreg = bb->regsin->item[k].left;
+                struct vreg* vreg = bb->regsin->item[k].right;
+                if (!pmap_findleft(&bb->phis, vreg))
+                    pmap_add(&destregs, hreg, vreg);
+            }
+
+            /* The last instruction of a block should be the jump that sends us
+             * to the next block. Insert the moves before then. */
+
+            insert_moves(prevbb, prevbb->hops.count-1, prevbb->regsout, &destregs);
+        }
+    }
+}
+
+void pass_register_allocator(void)
+{
+    populate_hregs();
+    wire_up_blocks_ins_outs();
+    assign_hregs_to_vregs();
+    insert_phi_copies();
+}
+
 /* vim: set sw=4 ts=4 expandtab : */