The register allocator now makes a spirited attempt to honour register
authorDavid Given <dg@cowlark.com>
Sun, 9 Oct 2016 13:09:34 +0000 (15:09 +0200)
committerDavid Given <dg@cowlark.com>
Sun, 9 Oct 2016 13:09:34 +0000 (15:09 +0200)
attributes when allocating. Unfortunately, backward edges don't work (because
the limited def-use chain stuff doesn't work across basic blocks). Needs more
thought.

mach/proto/mcg/hop.h
mach/proto/mcg/pass_instructionselection.c
mach/proto/mcg/pass_registerallocator.c
util/mcgg/iburg.c
util/mcgg/iburg.h
util/mcgg/ir.dat
util/mcgg/mcgg.h

index 16a39f7..4e7868c 100644 (file)
@@ -21,6 +21,11 @@ struct insel
        u;
 };
 
+struct constraint
+{
+    uint32_t attrs;
+};
+
 struct hop
 {
        int id;
@@ -29,6 +34,8 @@ struct hop
        ARRAYOF(struct insel) insels;
        struct vreg* output;
 
+    PMAPOF(struct vreg, struct constraint) constraints;
+
        ARRAYOF(struct vreg) ins;
        ARRAYOF(struct vreg) outs;
     ARRAYOF(struct vreg) throughs;
index db52802..6ab678a 100644 (file)
@@ -78,15 +78,29 @@ static void emit_eoi(void)
        hop_add_eoi_insel(current_hop);
 }
 
-static void constrain_input_reg(int child, int attr)
+static struct constraint* get_constraint(struct vreg* vreg)
+{
+    struct constraint* c = pmap_findleft(&current_hop->constraints, vreg);
+    if (!c)
+    {
+        c = calloc(1, sizeof(*c));
+        pmap_put(&current_hop->constraints, vreg, c);
+    }
+    return c;
+}
+
+static void constrain_input_reg(int child, uint32_t attr)
 {
     struct vreg* vreg = find_vreg_of_child(child);
+    struct constraint* c;
 
     if (vreg)
         array_appendu(&current_hop->ins, vreg);
+
+    get_constraint(vreg)->attrs = attr;
 }
 
-static void constrain_output_reg(int attr)
+static void constrain_output_reg(uint32_t attr)
 {
     struct vreg* vreg = current_hop->output;
 
@@ -95,6 +109,8 @@ static void constrain_output_reg(int attr)
 
     array_appendu(&current_hop->outs, vreg);
     vreg->defined = current_hop;
+
+    get_constraint(vreg)->attrs = attr;
 }
 
 static const struct burm_emitter_data emitter_data =
index bb22a4d..0bacdd2 100644 (file)
@@ -28,7 +28,7 @@ static void wire_up_blocks_ins_outs(void)
     }
 }
 
-static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg)
+static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg, uint32_t attr)
 {
     int i;
 
@@ -37,8 +37,11 @@ static struct hreg* allocate_hreg(register_assignment_t* regs, struct vreg* vreg
         struct hreg* hreg = hregs.item[i];
         if (!pmap_findleft(regs, hreg))
         {
-            pmap_put(regs, hreg, vreg);
-            return hreg;
+            if (hreg->attrs & attr)
+            {
+                pmap_put(regs, hreg, vreg);
+                return hreg;
+            }
         }
     }
 
@@ -81,7 +84,8 @@ static void select_registers(struct hop* hop,
     for (i=0; i<hop->outs.count; i++)
     {
         struct vreg* vreg = hop->outs.item[i];
-        allocate_hreg(out, vreg);
+        struct constraint* c = pmap_findleft(&hop->constraints, vreg);
+        allocate_hreg(out, vreg, c->attrs);
     }
 }
 
@@ -97,7 +101,7 @@ void pass_register_allocator(void)
         struct basicblock* bb = dominance.preorder.item[i];
         register_assignment_t* old = bb->regsin;
         
-        tracef('R', "R: allocating block %s\n", bb->name);
+        tracef('R', "R: considering block %s\n", bb->name);
 
         /* Attempt to import any block input registers from a predecessor. At
          * least one predecessor should export it; our graph traversal order
@@ -151,21 +155,42 @@ void pass_register_allocator(void)
 
         /* It's possible for the previous stage to fail because in in has
          * clobbered the physical register we were wanting. So we need to
-         * allocate a new register for that phi value. */
+         * allocate a new register for that phi value.
+         *
+         * We don't bother allocating anything if the vreg is never used.
+         * */
 
         for (j=0; j<bb->phis.count; j++)
         {
             struct vreg* vreg = bb->phis.item[j].left;
-            if (!pmap_findright(old, vreg))
-                allocate_hreg(old, vreg);
+            struct phi* phi = bb->phis.item[j].right;
+            if (!pmap_findright(old, vreg) && (vreg->used.count > 0))
+            {
+                struct hop* used = vreg->used.item[0];
+                struct constraint* c = pmap_findleft(&used->constraints, vreg);
+                struct hreg* hreg = allocate_hreg(old, vreg, c->attrs);
+
+                tracef('R', "R: import fallback hreg %s for phi input %%%d from %s\n",
+                    hreg->name, vreg->id, phi->prev->name);
+            }
         }
             
         for (j=0; j<bb->hops.count; j++)
         {
+            int k;
             struct hop* hop = bb->hops.item[j];
             register_assignment_t* in = &hop->regsin;
             register_assignment_t* out = &hop->regsout;;
 
+                       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);
+                       for (k=0; k<hop->throughs.count; k++)
+                               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");
+
             select_registers(hop, old, in, out);
 
             old = out;
index c93a1b3..9f2c6b7 100644 (file)
@@ -400,8 +400,8 @@ Tree tree(const struct terminfo* ti, Tree left, Tree right)
 
                if (ti->attr && ti->attr[0])
                {
-                       nt->attr = smap_get(&registerattrs, ti->attr);
-                       if (!nt->attr)
+                       t->attr = smap_get(&registerattrs, ti->attr);
+                       if (!t->attr)
                                yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
                }
        }
@@ -1077,10 +1077,12 @@ static void emit_input_regs(Tree node, int* index)
        Nonterm nt = node->op;
        if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right)
        {
-               uint32_t attr = 0;
-               if (nt->attr->number)
-                       attr = 1<<nt->attr->number;
-               print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr);
+               if (node->attr)
+               {
+                       uint32_t attr = 1<<node->attr->number;
+                       print("%1data->constrain_input_reg(%d, 0x%x /* %s */);\n",
+                               *index, attr, node->attr->name);
+               }
        }
 
        if (!node->left && !node->right)
@@ -1118,7 +1120,8 @@ static void emitinsndata(Rule rules)
                print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern);
 
                if (r->attr)
-                       print("%1data->constrain_output_reg(0x%x);\n", 1<<r->attr->number);
+                       print("%1data->constrain_output_reg(0x%x /* %s */);\n",
+                               1<<r->attr->number, r->attr->name);
 
                {
                        int index = 0;
index d9d69b8..8a5a71b 100644 (file)
@@ -96,7 +96,6 @@ struct nonterm
        Rule chain;       /* chain rules w/non-terminal on rhs */
        Nonterm link;     /* next terminal in number order */
        bool is_fragment; /* these instructions are all fragments */
-       struct regattr* attr; /* input register attribute */
 };
 extern void* lookup(const char* name);
 extern Nonterm nonterm(const char* id, bool allocate);
@@ -109,6 +108,7 @@ struct tree
        const char* label;  /* user label for this node */
        Tree left, right;   /* operands */
        int nterms;         /* number of terminal nodes in this tree */
+       struct regattr* attr; /* input register attribute */
 };
 extern Tree tree(const struct terminfo* ti, Tree left, Tree right);
 
index 50c2e44..31574ad 100644 (file)
@@ -42,6 +42,10 @@ S AND
 S OR
 S EOR
 S NOT
+S ASL
+S ASR
+S LSL
+S LSR
 
 # Conversions
 S CII1
index 14353c0..4e86e79 100644 (file)
@@ -44,8 +44,8 @@ struct burm_emitter_data
     void (*emit_reg)(int child);
     void (*emit_value)(int child);
     void (*emit_eoi)(void);
-    void (*constrain_input_reg)(int child, int attr);
-    void (*constrain_output_reg)(int attr);
+    void (*constrain_input_reg)(int child, uint32_t attr);
+    void (*constrain_output_reg)(uint32_t attr);
 };
 
 typedef void burm_emitter_t(const struct burm_emitter_data* data);