Get quite a long way towards basic output-register equality constraints (needed
authorDavid Given <dg@cowlark.com>
Sun, 2 Oct 2016 21:25:54 +0000 (23:25 +0200)
committerDavid Given <dg@cowlark.com>
Sun, 2 Oct 2016 21:25:54 +0000 (23:25 +0200)
to make special nodes like NOP work properly). Realise that the way I'm dealing
with the instruction selector is all wrong; I need to physically copy chunks of
tree to give to burg (so I can terminate them correctly).

mach/proto/mcg/hop.c
mach/proto/mcg/hop.h
mach/proto/mcg/ir.h
mach/proto/mcg/mcg.h
mach/proto/mcg/pass_instructionselection.c
mach/proto/mcg/table
mach/proto/mcg/vreg.c [new file with mode: 0644]
mach/proto/mcg/vreg.h [new file with mode: 0644]
util/mcgg/iburg.c
util/mcgg/mcgg.h

index a57d498..e4552e0 100644 (file)
@@ -28,11 +28,10 @@ void hop_add_string_insel(struct hop* hop, const char* string)
        array_append(&hop->insels, insel);
 }
 
-void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no)
+void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg)
 {
-       struct insel* insel = new_insel(INSEL_REG);
-       insel->u.reg.ir = ir;
-       insel->u.reg.insn_no = insn_no;
+       struct insel* insel = new_insel(INSEL_VREG);
+       insel->u.vreg = vreg;
        array_append(&hop->insels, insel);
 }
 
@@ -61,7 +60,7 @@ void hop_print(char k, struct hop* hop)
 
                if (soi)
                {
-                       tracef(k, "%c: %d: ", k, hop->id);
+                       tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id);
                        soi = false;
                }
 
@@ -72,8 +71,8 @@ void hop_print(char k, struct hop* hop)
                                soi = true;
                                break;
 
-                       case INSEL_REG:
-                               tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no);
+                       case INSEL_VREG:
+                               tracef(k, "%%%d", insel->u.vreg->id);
                                break;
 
                        case INSEL_STRING:
index e6cc8f8..3e2f9d6 100644 (file)
@@ -4,7 +4,7 @@
 enum insel_type
 {
        INSEL_STRING,
-       INSEL_REG,
+       INSEL_VREG,
        INSEL_VALUE,
        INSEL_EOI
 };
@@ -15,12 +15,7 @@ struct insel
        union
        {
                const char* string;
-               struct
-               {
-                       struct ir* ir;
-                       int insn_no;
-               }
-               reg;
+               struct vreg* vreg;
                struct ir* value;
        }
        u;
@@ -32,12 +27,13 @@ struct hop
        int insn_no;
        struct ir* ir;
        ARRAYOF(struct insel) insels;
+       struct vreg* output;
 };
 
 extern struct hop* new_hop(int insn_no, struct ir* ir);
 
 extern void hop_add_string_insel(struct hop* hop, const char* string);
-extern void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no);
+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 dc66ff7..ce90fcb 100644 (file)
@@ -23,7 +23,7 @@ struct ir
        void* state_label; /* used by the iburg instruction selector */
        int insn_no;       /* the table rule number for this instruction */
        int goal_no;       /* the semantic type of this instruction; not stmt */
-       ARRAYOF(struct hop) hops; /* only for root IRs */
+       IMAPOF(struct hop) hops; /* only for root IRs; by goal */
 };
 
 extern const char* ir_names[];
index ba23e2d..a5fa110 100644 (file)
@@ -24,6 +24,7 @@
 #include "ir.h"
 #include "mcgg.h"
 #include "hop.h"
+#include "vreg.h"
 #include "basicblock.h"
 #include "procedure.h"
 
index 2cb070d..a1f80a8 100644 (file)
@@ -29,7 +29,9 @@ int burm_calculate_label(struct ir* ir)
 
 static void emit_reg(struct ir* ir, int goal)
 {
-    hop_add_reg_insel(current_hop, ir, goal);
+    struct hop* hop = imap_get(&current_ir->hops, goal);
+
+    hop_add_vreg_insel(current_hop, hop->output);
 }
 
 static void emit_string(const char* data)
@@ -50,13 +52,20 @@ static void emit_value(struct ir* ir)
        hop_add_value_insel(current_hop, ir);
 }
 
-static void emit_resultreg(void)
+static void emit_eoi(void)
 {
+       hop_add_eoi_insel(current_hop);
 }
 
-static void emit_eoi(void)
+static void emit_constraint_equals(struct ir* ir, int goal)
 {
-       hop_add_eoi_insel(current_hop);
+    struct hop* hop;
+    
+    if (!goal)
+        goal = 2;
+    hop = imap_get(&current_ir->hops, goal);
+
+    current_hop->output = hop->output;
 }
 
 static const struct burm_emitter_data emitter_data =
@@ -65,8 +74,8 @@ static const struct burm_emitter_data emitter_data =
     &emit_fragment,
     &emit_reg,
     &emit_value,
-    &emit_resultreg,
-    &emit_eoi
+    &emit_eoi,
+    &emit_constraint_equals
 };
 
 
@@ -83,6 +92,11 @@ static void walk_instructions(struct ir* ir, int goal)
     {
         parent_hop = current_hop;
         current_hop = new_hop(insn_no, ir);
+        if (goal != 1)
+        {
+            current_hop->output = new_vreg();
+            imap_add(&current_ir->hops, goal, current_hop);
+        }
     }
 
     burm_kids(ir, insn_no, children);
@@ -102,8 +116,10 @@ static void walk_instructions(struct ir* ir, int goal)
 
     if (!insndata->is_fragment)
     {
-        if (insndata->emitter)
-            insndata->emitter(ir, &emitter_data);
+        /* This may cause the vregs to be reassigned for this instruction (and
+         * fragments contained within it). */
+
+        insndata->emitter(ir, &emitter_data);
 
         hop_print('I', current_hop);
         array_append(&ir->hops, current_hop);
index 4292dd8..0db5f6a 100644 (file)
@@ -69,6 +69,7 @@ PATTERNS
 
        reg = in:REG4
                with (reg == in)
+               emit "reg %reg"
                cost 1;
 
        reg = NOP4(in:reg)
diff --git a/mach/proto/mcg/vreg.c b/mach/proto/mcg/vreg.c
new file mode 100644 (file)
index 0000000..636475d
--- /dev/null
@@ -0,0 +1,10 @@
+#include "mcg.h"
+
+static int vreg_count = 1;
+
+struct vreg* new_vreg(void)
+{
+       struct vreg* vreg = calloc(1, sizeof *vreg);
+       vreg->id = vreg_count++;
+       return vreg;
+}
diff --git a/mach/proto/mcg/vreg.h b/mach/proto/mcg/vreg.h
new file mode 100644 (file)
index 0000000..ef92fd2
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef VREG_H
+#define VREG_H
+
+struct vreg
+{
+       int id;
+};
+
+extern struct vreg* new_vreg(void);
+
+#endif
+
index 2fb6e2c..937a0df 100644 (file)
@@ -954,6 +954,49 @@ static void emitpredicatedefinitions(Rule r)
        }
 }
 
+static void invalid_equals_constraint(Rule rule)
+{
+       yylineno = rule->lineno;
+       yyerror("left hand side of an equality constraint must be the output register");
+       exit(1);
+}
+
+static void emit_ir_expr(Rule rule, const char* label)
+{
+       if (strcmp(label, rule->lhs->name) == 0)
+               print("node, %P%s_NT", label);
+       else
+       {
+               Tree node;
+               uint32_t path = find_label(rule->pattern, label, 0, &node);
+               Nonterm nt = node->op;
+
+               if (path == PATH_MISSING)
+                       label_not_found(rule, label);
+
+               print_path(path);
+               if (nt->kind == NONTERM)
+                       print(", %P%s_NT", ((Nonterm)node->op)->name);
+               else
+                       print(", 0");
+       }
+}
+
+static void emit_constraint(Rule rule, struct constraint* c)
+{
+       switch (c->type)
+       {
+               case CONSTRAINT_EQUALS:
+                       if (strcmp(c->left, rule->lhs->name) != 0)
+                               invalid_equals_constraint(rule);
+
+                       print("%1data->emit_constraint_equals(");
+                       emit_ir_expr(rule, c->right);
+                       print(");\n");
+                       break;
+       }
+}
+
 /* emitinsndata - emit the code generation data */
 static void emitinsndata(Rule rules)
 {
@@ -964,77 +1007,88 @@ static void emitinsndata(Rule rules)
        while (r)
        {
                struct stringfragment* f = r->code.first;
-               if (f)
+
+               if (!f)
+               {
+                       /* This instruction has no code; make sure it's not a fragment. */
+                       if (r->lhs->is_fragment)
+                       {
+                               yylineno = r->lineno;
+                               yyerror("rule is a fragment, but doesn't emit anything");
+                       }
+               }
+
+               print("/* %R */\n", r);
+               print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
+
+               /* Constraints come first, because they may cause vreg reassignment, which
+                * we want to happen before the instruction emission. */
+
                {
-                       print("/* %R */\n", r);
-                       print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
+                       int i;
 
-                       while (f)
+                       for (i=0; i<r->constraints.count; i++)
                        {
-                               switch (f->data[0])
-                               {
-                                       case '%':
-                                       {
-                                               const char* label = f->data + 1;
+                               struct constraint* c = r->constraints.item[i];
+                               emit_constraint(r, c);
+                       }
+               }
 
-                                               if (strcmp(label, r->lhs->name) == 0)
-                                                       print("%1data->emit_reg(node, %P%s_NT);\n", label);
-                                               else
-                                               {
-                                                       Tree node;
-                                                       uint32_t path = find_label(r->pattern, label, 0, &node);
-                                                       Nonterm nt = node->op;
-
-                                                       if (path == PATH_MISSING)
-                                                               label_not_found(r, label);
-
-                                                       if (nt->is_fragment)
-                                                               print("%1data->emit_fragment(");
-                                                       else
-                                                               print("%1data->emit_reg(");
-
-                                                       print_path(path);
-                                                       print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
-                                               }
-                                               break;
-                                       }
+               while (f)
+               {
+                       switch (f->data[0])
+                       {
+                               case '%':
+                               {
+                                       const char* label = f->data + 1;
 
-                                       case '$':
+                                       if (strcmp(label, r->lhs->name) == 0)
+                                               print("%1data->emit_reg(node, %P%s_NT);\n", label);
+                                       else
                                        {
-                                               const char* label = f->data + 1;
-                                               uint32_t path = find_label(r->pattern, label, 0, NULL);
-                                               print("%1data->emit_value(");
+                                               Tree node;
+                                               uint32_t path = find_label(r->pattern, label, 0, &node);
+                                               Nonterm nt = node->op;
+
                                                if (path == PATH_MISSING)
                                                        label_not_found(r, label);
+
+                                               if (nt->is_fragment)
+                                                       print("%1data->emit_fragment(");
+                                               else
+                                                       print("%1data->emit_reg(");
+
                                                print_path(path);
-                                               print(");\n");
-                                               break;
+                                               print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
                                        }
+                                       break;
+                               }
 
-                                       case '\n':
-                                               assert(f->data[1] == 0);
-                                               print("%1data->emit_eoi();\n");
-                                               break;
-                                       
-                                       default:
-                                               print("%1data->emit_string(\"%s\");\n", f->data);
+                               case '$':
+                               {
+                                       const char* label = f->data + 1;
+                                       uint32_t path = find_label(r->pattern, label, 0, NULL);
+                                       print("%1data->emit_value(");
+                                       if (path == PATH_MISSING)
+                                               label_not_found(r, label);
+                                       print_path(path);
+                                       print(");\n");
+                                       break;
                                }
 
-                               f = f->next;
+                               case '\n':
+                                       assert(f->data[1] == 0);
+                                       print("%1data->emit_eoi();\n");
+                                       break;
+                               
+                               default:
+                                       print("%1data->emit_string(\"%s\");\n", f->data);
                        }
 
-                       print("}\n\n");
-               }
-               else
-               {
-                       /* This instruction has no code; make sure it's not a fragment. */
-                       if (r->lhs->is_fragment)
-                       {
-                               yylineno = r->lineno;
-                               yyerror("rule is a fragment, but doesn't emit anything");
-                       }
+                       f = f->next;
                }
 
+               print("}\n\n");
                r = r->link;
        }
 
@@ -1051,11 +1105,7 @@ static void emitinsndata(Rule rules)
 
                print("%2\"%R\",\n", r);
 
-               print("%2");
-               if (r->code.first)
-                       print("&%Pemitter_%d,\n", r->ern);
-               else
-                       print("NULL,\n");
+               print("%2&%Pemitter_%d,\n", r->ern);
 
                if (r->lhs->allocate)
                        print("%2%d,\n", r->lhs->allocate->number);
index a2f20b4..1d80685 100644 (file)
@@ -12,7 +12,6 @@
                 ((size) == 0) ? 0 : \
                  (size-1)))
 
-
 #define STATE_TYPE void*
 typedef struct ir* NODEPTR_TYPE;
 
@@ -30,9 +29,8 @@ struct burm_emitter_data
     void (*emit_fragment)(struct ir* ir, int goal);
     void (*emit_reg)(struct ir* ir, int goal);
     void (*emit_value)(struct ir* ir);
-    void (*emit_resultreg)(void);
     void (*emit_eoi)(void);
-    void (*emit_usereg)(struct ir* ir);
+    void (*emit_constraint_equals)(struct ir* rightir, int rightgoal);
 };
 
 typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data);