You can now mark a register as corrupting a certain register class; calls work,
authorDavid Given <dg@cowlark.com>
Fri, 14 Oct 2016 23:15:08 +0000 (01:15 +0200)
committerDavid Given <dg@cowlark.com>
Fri, 14 Oct 2016 23:15:08 +0000 (01:15 +0200)
or at least look like they work. The bad news is that the register allocator
has a rare talent for putting things in the wrong register.

mach/proto/mcg/hop.c
mach/proto/mcg/hop.h
mach/proto/mcg/pass_instructionselection.c
mach/proto/mcg/pass_registerallocator.c
mach/proto/mcg/table
util/mcgg/gram.y
util/mcgg/iburg.c
util/mcgg/iburg.h
util/mcgg/mcgg.h
util/mcgg/scan.l

index b42cd95..6b84c62 100644 (file)
@@ -178,20 +178,19 @@ void hop_print(char k, struct hop* hop)
 
     hop_render(hop);
 
-    print_header(k, hop);
-
     p = strtok(buffer, "\n");
-    if (!p)
-    {
-        print_header(k, hop);
-        tracef(k, "\n");
-    }
+    print_header(k, hop);
     while (p)
     {
-        print_header(k, hop);
-        tracef(k, "%s\n", p);
+        tracef(k, "%s", p);
         p = strtok(NULL, "\n");
+        if (p)
+        {
+            tracef(k, "\n");
+            print_header(k, hop);
+        }
     }
+    tracef(k, "\n");
 }
 
 /* vim: set sw=4 ts=4 expandtab : */
index ab2b39d..1dbf577 100644 (file)
@@ -34,6 +34,7 @@ struct hop
        int id;
     struct basicblock* bb;
        struct ir* ir;
+    const struct burm_instruction_data* insndata;
        ARRAYOF(struct insel) insels;
        struct vreg* output;
 
index e8c9c45..9b5a615 100644 (file)
@@ -182,6 +182,7 @@ static struct insn* walk_instructions(struct burm_node* node, int goal)
         if (!insn->insndata->is_fragment)
         {
             insn->hop = current_hop = new_hop(current_bb, insn->ir);
+            current_hop->insndata = insn->insndata;
             emit(insn);
 
             if (!current_hop->output)
index 9068c59..fffc6a1 100644 (file)
@@ -99,10 +99,19 @@ static struct hreg* evict(struct vreg* vreg)
     assert(false);
 }
 
-static bool allocatable(struct hreg* hreg, struct vreg* vreg)
+static bool allocatable_input(struct hreg* hreg, struct vreg* vreg)
 {
     struct constraint* c = pmap_findleft(&current_hop->constraints, vreg);
-    return (hreg->attrs & c->attrs);
+    return !pmap_findleft(current_ins, hreg) &&
+        (!c || (hreg->attrs & c->attrs));
+}
+
+static bool allocatable_output(struct hreg* hreg, struct vreg* vreg)
+{
+    struct constraint* c = pmap_findleft(&current_hop->constraints, vreg);
+    return !pmap_findleft(current_outs, hreg) &&
+        (!c || (hreg->attrs & c->attrs)) &&
+        !(hreg->attrs & current_hop->insndata->corrupts);
 }
 
 static struct hreg* find_input_reg(struct vreg* vreg)
@@ -113,8 +122,7 @@ static struct hreg* find_input_reg(struct vreg* vreg)
     for (i=0; i<hregs.count; i++)
     {
         hreg = hregs.item[i];
-        if (allocatable(hreg, vreg) &&
-            !pmap_findleft(current_ins, hreg))
+        if (allocatable_input(hreg, vreg))
         {
             return hreg;
         }
@@ -131,8 +139,7 @@ static struct hreg* find_output_reg(struct vreg* vreg)
     for (i=0; i<hregs.count; i++)
     {
         hreg = hregs.item[i];
-        if (allocatable(hreg, vreg) &&
-            !pmap_findleft(current_outs, hreg))
+        if (allocatable_output(hreg, vreg))
         {
             return hreg;
         }
@@ -149,9 +156,8 @@ static struct hreg* find_through_reg(struct vreg* vreg)
     for (i=0; i<hregs.count; i++)
     {
         hreg = hregs.item[i];
-        if (allocatable(hreg, vreg) &&
-            !pmap_findleft(current_ins, hreg) &&
-            !pmap_findleft(current_outs, hreg))
+        if (allocatable_input(hreg, vreg) &&
+            allocatable_output(hreg, vreg))
         {
             return hreg;
         }
@@ -166,19 +172,31 @@ static void add_input_register(struct vreg* vreg, struct hreg* hreg)
 
     /* Register hint for an input? */
 
-    if (hreg && allocatable(hreg, vreg))
+    if (hreg)
     {
-        /* If it's already assigned, it's most likely a through. */
-        if (!pmap_findleft(current_ins, hreg))
-            pmap_add(current_ins, hreg, vreg);
-        return;
+        if (pmap_findleft(current_ins, hreg) == vreg)
+        {
+            /* Yup, already there. */
+        }
+        else if (allocatable_input(hreg, vreg))
+        {
+            /* The register is free. */
+        }
+        else
+        {
+            /* Can't honour the hint. */
+            hreg = NULL;
+        }
     }
 
-    /* Find an unused input register of the right class. */
-
-    hreg = find_input_reg(vreg);
     if (!hreg)
-        hreg = evict(hreg);
+    {
+        /* Find an unused input register of the right class. */
+
+        hreg = find_input_reg(vreg);
+        if (!hreg)
+            hreg = evict(vreg);
+    }
 
     pmap_add(current_ins, hreg, vreg);
 }
@@ -195,14 +213,17 @@ static void add_output_register(struct vreg* vreg)
     c = pmap_findleft(&current_hop->constraints, vreg);
     if (c->equals_to)
     {
+        tracef('R', "R: outputput equality constraint of %%%d to %%%d\n",
+            vreg->id, c->equals_to->id);
+
         /* This output register is constrained to be in the same hreg as an
          * input register (most likely for a 2op instruction). */
 
         hreg = pmap_findright(current_ins, c->equals_to);
 
-        /* If this register is current unused as an output, use it. */
+        /* If this register is currently unused as an output, use it. */
 
-        if (!pmap_findleft(current_outs, hreg))
+        if (allocatable_output(hreg, c->equals_to))
         {
             pmap_add(current_outs, hreg, vreg);
             return;
@@ -235,6 +256,38 @@ static void add_output_register(struct vreg* vreg)
     }
 }
 
+static void add_through_register(struct vreg* vreg, struct hreg* hreg)
+{
+    /* Register hint for an input? */
+
+    if (hreg)
+    {
+        bool infree = allocatable_input(hreg, vreg);
+        bool outfree = allocatable_output(hreg, vreg);
+
+        if (infree && outfree)
+        {
+            /* Register unused --- use it. */
+        }
+        if ((infree || pmap_findleft(current_ins, hreg) == vreg) &&
+            (outfree || pmap_findleft(current_outs, hreg) == vreg))
+        {
+            /* Input and output are either free or already assigned. */
+        }
+        else
+        {
+            /* Nope, can't honour the hint. */
+            hreg = NULL;
+        }
+    }
+    
+    if (!hreg)
+        hreg = find_through_reg(vreg);
+
+    pmap_put(current_ins, hreg, vreg);
+    pmap_put(current_outs, hreg, vreg);
+}
+
 static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* src)
 {
     uint32_t srctype = src->type;
@@ -249,8 +302,8 @@ static void find_new_home_for_evicted_register(struct vreg* vreg, struct hreg* s
     {
         hreg = hregs.item[i];
         if ((hreg->type == src->type) &&
-            !pmap_findleft(current_ins, hreg) &&
-            !pmap_findleft(current_outs, hreg))
+            allocatable_input(hreg, vreg) &&
+            allocatable_output(hreg, vreg))
         {
             goto found;
         }
@@ -283,10 +336,7 @@ static void select_registers(struct hop* hop,
     {
         struct vreg* vreg = hop->throughs.item[i];
         struct hreg* hreg = pmap_findright(old, vreg);
-        assert(hreg != NULL);
-
-        pmap_put(current_ins, hreg, vreg);
-        pmap_put(current_outs, hreg, vreg);
+        add_through_register(vreg, hreg);
     }
 
     /* Any registers being *read* by the instruction should also stay where
index 4653e2d..dce199c 100644 (file)
@@ -305,10 +305,12 @@ PATTERNS
                cost 8;
 
        CALL(dest:LABEL4)
+        with corrupted(volatile)
                emit "bl $dest"
                cost 4;
 
     CALL(dest:(int)reg)
+        with corrupted(volatile)
         emit "mtspr ctr, %dest"
         emit "bcctrl ALWAYS, 0, 0"
         cost 8;
index 3fe5f9c..748d3fa 100644 (file)
@@ -26,6 +26,7 @@ extern int yylex(void);
 }
 
 %term COPY
+%term CORRUPTED
 %term COST
 %term DECLARATIONS
 %term EMIT
@@ -145,6 +146,8 @@ constraint
     : '(' constraint ')'                { $$ = $2; }
     | '%' ID EQUALS '%' ID              { $$ = calloc(1, sizeof(*$$));
                                           $$->type = CONSTRAINT_EQUALS; $$->left = $2; $$->right = $5; }
+    | CORRUPTED '(' ID ')'              { $$ = calloc(1, sizeof(*$$));
+                                          $$->type = CONSTRAINT_CORRUPTED_ATTR; $$->left = $3; }
     ;
 
 qfragments
index a3d9568..ff8b1e9 100644 (file)
@@ -1239,6 +1239,27 @@ static void emitinsndata(Rule rules)
 
                print("%2%s,\n", r->lhs->is_fragment ? "true" : "false");
 
+               {
+                       int i;
+                       uint32_t attrs = 0;
+
+                       for (i=0; i<r->constraints.count; i++)
+                       {
+                               struct constraint* c = r->constraints.item[i];
+
+                               if (c->type == CONSTRAINT_CORRUPTED_ATTR)
+                               {
+                                       struct regattr* p = smap_get(&registerattrs, c->left);
+                                       if (!p)
+                                               yyerror("no such register attribute '%s'", c->left);
+
+                                       attrs |= 1<<(p->number);
+                               }
+                       }
+
+                       print("%2%d, /* corruption attrs */\n", attrs);
+               }
+
                print("%1},\n");
                r = r->link;
        }
index ebd22fb..689a841 100644 (file)
@@ -20,6 +20,7 @@ typedef struct term* Term;
 enum
 {
        CONSTRAINT_EQUALS,
+       CONSTRAINT_CORRUPTED_ATTR,
 };
 
 struct constraint
index c0c9d87..242c1ef 100644 (file)
@@ -56,6 +56,7 @@ struct burm_instruction_data
     const char* name;
     burm_emitter_t* emitter;
     bool is_fragment;
+    uint32_t corrupts;
 };
 
 extern const struct burm_instruction_data burm_instruction_data[];
index 68de96e..d6a60d3 100644 (file)
@@ -38,6 +38,7 @@ static int braces = 0;
 "DECLARATIONS"              return DECLARATIONS;
 "PATTERNS"                  return PATTERNS;
 "REGISTERS"                 return REGISTERS;
+"corrupted"                 return CORRUPTED;
 "cost"                      return COST;
 "emit"                      return EMIT;
 "fragment"                  return FRAGMENT;