Massive rewrite of how emitters and the instruction selector works, after I
authorDavid Given <dg@cowlark.com>
Mon, 3 Oct 2016 22:16:06 +0000 (00:16 +0200)
committerDavid Given <dg@cowlark.com>
Mon, 3 Oct 2016 22:16:06 +0000 (00:16 +0200)
realised that the existing approach wasn't working. Now, hopefully, tracks the
instruction trees generated during selection properly.

mach/proto/mcg/ir.h
mach/proto/mcg/pass_instructionselection.c
mach/proto/mcg/table
util/mcgg/gram.y
util/mcgg/iburg.c
util/mcgg/mcgg.h

index 52c5dc7..ea84e1a 100644 (file)
@@ -20,6 +20,7 @@ struct ir
                ARRAYOF(struct ir) phivalue;
        } u;
 
+       struct vreg* result;     /* vreg containing IR result */
        IMAPOF(struct hop) hops; /* only for root IRs; by goal */
 };
 
index 5c92aae..20a93c6 100644 (file)
@@ -1,10 +1,22 @@
 #include "mcg.h"
 
+#define MAX_CHILDREN 10
+
+struct insn
+{
+    struct ir* ir;
+    struct hop* hop;
+    const struct burm_instruction_data* insndata;
+    int num_children;
+    struct insn* children[MAX_CHILDREN];
+};
+
 static struct basicblock* current_bb;
 static struct hop* current_hop;
 static struct ir* current_ir;
+static struct insn* current_insn;
 
-static const struct burm_emitter_data emitter_data;
+static void emit(struct insn* insn);
 
 void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) {
     const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
@@ -20,11 +32,23 @@ void burm_panic_cannot_match(struct burm_node* node)
        exit(1);
 }
 
-static void emit_reg(struct burm_node* node, int goal)
+static void emit_return_reg(void)
+{
+    hop_add_vreg_insel(current_hop, current_hop->output);
+}
+
+static void emit_reg(int child)
 {
-    struct hop* hop = imap_get(&current_ir->hops, goal);
+    struct insn* insn = current_insn->children[child];
+    struct vreg* vreg;
 
-    hop_add_vreg_insel(current_hop, hop->output);
+    if (insn->hop)
+        vreg = insn->hop->output;
+    else
+        vreg = insn->ir->result;
+
+    if (vreg)
+        hop_add_vreg_insel(current_hop, vreg);
 }
 
 static void emit_string(const char* data)
@@ -32,17 +56,14 @@ static void emit_string(const char* data)
        hop_add_string_insel(current_hop, data);
 }
 
-static void emit_fragment(struct burm_node* node, int goal)
+static void emit_fragment(int child)
 {
-    int insn_no = burm_rule(node->state_label, goal);
-    const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
-    if (insndata->emitter)
-        insndata->emitter(node, &emitter_data);
+    emit(current_insn->children[child]);
 }
 
-static void emit_value(struct burm_node* node)
+static void emit_value(int child)
 {
-       hop_add_value_insel(current_hop, node->ir);
+       hop_add_value_insel(current_hop, current_insn->children[child]->ir);
 }
 
 static void emit_eoi(void)
@@ -50,73 +71,75 @@ static void emit_eoi(void)
        hop_add_eoi_insel(current_hop);
 }
 
-static void emit_constraint_equals(struct burm_node* node, int goal)
-{
-#if 0
-    struct hop* hop;
-    
-    if (!goal)
-        goal = ir->goal_no;
-    hop = imap_get(&current_ir->hops, goal);
-
-    current_hop->output = hop->output;
-#endif
-}
-
 static const struct burm_emitter_data emitter_data =
 {
     &emit_string,
     &emit_fragment,
+    &emit_return_reg,
     &emit_reg,
     &emit_value,
     &emit_eoi,
-    &emit_constraint_equals
 };
 
+static void emit(struct insn* insn)
+{
+    struct insn* old = current_insn;
+    current_insn = insn;
+
+    insn->insndata->emitter(&emitter_data);
+
+    current_insn = old;
+}
 
-static void walk_instructions(struct burm_node* node, int goal)
+static struct insn* walk_instructions(struct burm_node* node, int goal)
 {
-    struct burm_node* children[10];
-    int insn_no = burm_rule(node->state_label, goal);
-    const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
-    const short* nts = burm_nts[insn_no];
-    struct hop* parent_hop = NULL;
-    struct ir* ir = node->ir;
+    struct insn* insn = calloc(1, sizeof(*insn));
     int i;
-    
-    if (!insndata->is_fragment)
+
+    insn->ir = node->ir;
+    insn->num_children = 0;
+
+    if (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);
-        }
-    }
+        int insn_no = burm_rule(node->state_label, goal);
+        const short* nts = burm_nts[insn_no];
+        struct burm_node* children[MAX_CHILDREN] = {0};
 
-    burm_kids(node, insn_no, children);
-    for (i=0; nts[i]; i++)
-        walk_instructions(children[i], nts[i]);
+        insn->insndata = &burm_instruction_data[insn_no];
 
-    tracef('I', "I: $%d goal %d selected %s %d: %s\n",
-        ir->id,
-        goal,
-        insndata->is_fragment ? "fragment" : "instruction",
-        insn_no,
-        insndata->name);
+        burm_kids(node, insn_no, children);
 
-    if (!insndata->is_fragment)
-    {
-        /* This may cause the vregs to be reassigned for this instruction (and
-         * fragments contained within it). */
+        i = 0;
+        for (;;)
+        {
+            if (!children[i])
+                break;
+
+            insn->children[i] = walk_instructions(children[i], nts[i]);
+            insn->num_children++;
+            i++;
+        }
 
-        insndata->emitter(node, &emitter_data);
+        tracef('I', "I: $%d goal %d %s selected %d: %s\n",
+            node->ir->id,
+            goal,
+            insn->insndata->is_fragment ? "fragment" : "instruction",
+            insn_no,
+            insn->insndata->name);
 
-        hop_print('I', current_hop);
-        array_append(&ir->hops, current_hop);
-        current_hop = parent_hop;
+        if (!insn->insndata->is_fragment)
+        {
+            insn->hop = current_hop = new_hop(0, insn->ir);
+            insn->hop->output = new_vreg();
+            emit(insn);
+            hop_print('I', current_hop);
+
+            if (goal != 1)
+                insn->ir->result = insn->hop->output;
+        }
     }
+
+    return insn;
 }
 
 static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir)
index 5f589d1..0fa07b6 100644 (file)
@@ -52,6 +52,7 @@ PATTERNS
                cost 4;
 
        reg = POP4
+               with int reg
                emit "pop %reg"
                cost 4;
 
@@ -68,12 +69,11 @@ PATTERNS
                cost 4;
 
        reg = in:REG
-               with (reg == in)
-               emit "reg %reg"
+               emit "mov %reg, %in"
                cost 1;
 
        reg = NOP(in:reg)
-               with (reg == in)
+               emit "mov %reg, %in"
                cost 1;
 
 
@@ -90,18 +90,22 @@ PATTERNS
                cost 4;
 
        reg = LOAD4(addr:address)
+               with int reg
                emit "ldr %reg, %addr"
                cost 4;
 
        reg = LOAD1(addr:address)
+               with int reg
                emit "ldrb %reg, %addr"
                cost 4;
 
        reg = CIU14(LOAD1(addr:address))
+               with int reg
                emit "ldrb %reg, %addr"
                cost 4;
        
        reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
+               with int reg
                emit "ldrsb %reg, %addr"
                cost 4;
 
@@ -109,6 +113,7 @@ PATTERNS
 /* Locals */
 
        reg = in:LOCAL4
+               with int reg
                emit "add %reg, fp, #$in"
                cost 4;
 
@@ -161,14 +166,17 @@ PATTERNS
 /* Comparisons */
 
        cc = COMPARES4(left:reg, right:aluparam)
+               with cc cc
                emit "cmp %left, %right"
                cost 4;
 
        cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4)
+               with cc cc
                emit "cmp %left, %right"
                cost 4;
 
        reg = cc
+               with int reg
                emit "mov %reg, #0"
                emit "movlt %reg, #-1"
                emit "movgt %reg, #1"
@@ -178,10 +186,12 @@ PATTERNS
 /* Conversions */
 
        reg = CII14(CIU41(value:reg))
+               with int reg
                emit "sxtb %reg, %value"
                cost 4;
 
        reg = CIU41(in:reg)
+               with int reg
                emit "and %reg, %in, #0xff"
                cost 4;
 
@@ -189,19 +199,23 @@ PATTERNS
 /* ALU operations */
 
        reg = ADD4(left:reg, right:aluparam)
+               with int reg
                emit "add %reg, %left, %right"
                cost 4;
 
        reg = ADD4(left:aluparam, right:reg)
+               with int reg
                emit "add %reg, %right, %left"
                cost 4;
 
        reg = MOD4(left:reg, right:reg)
+               with int reg
                emit "udiv %reg, %left, %right"
                emit "mls %reg, %reg, %right, %left"
                cost 8;
 
        reg = DIV4(left:reg, right:aluparam)
+               with int reg
                emit "div %reg, %left, %right"
                cost 4;
 
@@ -212,28 +226,34 @@ PATTERNS
                emit "%value";
 
        reg = value:aluparam
+               with int reg
                emit "mov %reg, %value"
                cost 4;
 
        reg = value:LABEL4
+               with int reg
                emit "adr %reg, $value"
                cost 4;
 
        reg = value:BLOCK4
+               with int reg
                emit "adr %reg, $value"
                cost 4;
 
        reg = value:CONST4
+               with int reg
                emit "ldr %reg, address-containing-$value"
                cost 8;
 
        reg = value:CONSTF4
+               with int reg
                emit "vldr %reg, address-containing-$value"
                cost 8;
 
 /* FPU operations */
 
        reg = ADDF4(left:reg, right:reg)
+               with int reg
                emit "fadds %reg, %left, %right"
                cost 4;
 
index 9927d15..5dc23a8 100644 (file)
@@ -28,6 +28,7 @@ static int nextern = 1;
 }
 
 %term ALLOCATES
+%term COPY
 %term COST
 %term DECLARATIONS
 %term EMIT
@@ -105,24 +106,24 @@ patterns
        ;
 
 pattern
-    : ID '=' rhs                      { nonterm($1, false); $$ = rule($1,     $3, nextern++); }
-    | rhs                             {                     $$ = rule("stmt", $1, nextern++); }
-    | pattern PREFERS predicate       { $$ = $1; array_append(&$$->prefers, $3); }
-    | pattern WHEN predicate          { $$ = $1; array_append(&$$->requires, $3); }
-    | pattern COST INT                { $$ = $1; $$->cost = $3; }
-    | pattern_constraints             { $$ = $1; }
-    | pattern_emit                    { $$ = $1; }
+    : ID '=' rhs                        { nonterm($1, false); $$ = rule($1,     $3, nextern++); }
+    | rhs                               {                     $$ = rule("stmt", $1, nextern++); }
+    | pattern PREFERS predicate         { $$ = $1; array_append(&$$->prefers, $3); }
+    | pattern WHEN predicate            { $$ = $1; array_append(&$$->requires, $3); }
+    | pattern COST INT                  { $$ = $1; $$->cost = $3; }
+    | pattern_constraints               { $$ = $1; }
+    | pattern_emit                      { $$ = $1; }
     ;
 
 rhs
-    : terminfo                        { $$ = tree(&$1, NULL, NULL); }
-       | terminfo '(' rhs ')'            { $$ = tree(&$1,   $3, NULL); }
-       | terminfo '(' rhs ',' rhs ')'    { $$ = tree(&$1,   $3, $5); }
+    : terminfo                          { $$ = tree(&$1, NULL, NULL); }
+       | terminfo '(' rhs ')'              { $$ = tree(&$1,   $3, NULL); }
+       | terminfo '(' rhs ',' rhs ')'      { $$ = tree(&$1,   $3, $5); }
        ;
 
 terminfo
-    : ID                              { $$.name = $1; }
-    | ID ':' ID                       { $$.label = $1; $$.name = $3; }
+    : ID                                { $$.name = $1; }
+    | ID ':' ID                         { $$.label = $1; $$.name = $3; }
     ;
 
 pattern_emit
index 937a0df..af3106a 100644 (file)
@@ -679,20 +679,22 @@ static void emitheader(void)
 }
 
 /* computekids - compute paths to kids in tree t */
-static char* computekids(Tree t, const char* v, char* bp, int* ip)
+static char* computekids(Tree node, const char* v, char* bp, int* ip)
 {
-       Term p = t->op;
+       Term t = node->op;
 
-       if (p->kind == NONTERM)
+       if (!node->left && !node->right)
        {
                sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
                bp += strlen(bp);
        }
-       else if (p->arity > 0)
+
+       if (t->kind == TERM)
        {
-               bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip);
-               if (p->arity == 2)
-                       bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip);
+               if (t->arity >= 1)
+                       bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip);
+               if (t->arity == 2)
+                       bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip);
        }
        return bp;
 }
@@ -910,6 +912,27 @@ static void label_not_found(Rule rule, const char* label)
        exit(1);
 }
 
+static bool find_child_index(Tree node, const char* name, int* index, Tree* found)
+{
+       /* This must return the same ordering as the burm_kids() function uses. */
+
+       if (node->label && strcmp(node->label, name) == 0)
+       {
+               if (found)
+                       *found = node;
+               return true;
+       }
+
+       if (!node->left && !node->right)
+               (*index)++;
+
+       if (node->left && find_child_index(node->left, name, index, found))
+               return true;
+       if (node->right && find_child_index(node->right, name, index, found))
+               return true;
+       return false;
+}
+       
 /* emitpredicates - emit predicates for rules */
 static void emitpredicatedefinitions(Rule r)
 {
@@ -954,49 +977,6 @@ 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)
 {
@@ -1007,6 +987,7 @@ static void emitinsndata(Rule rules)
        while (r)
        {
                struct stringfragment* f = r->code.first;
+               yylineno = r->lineno;
 
                if (!f)
                {
@@ -1019,20 +1000,7 @@ static void emitinsndata(Rule rules)
                }
 
                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. */
-
-               {
-                       int i;
-
-                       for (i=0; i<r->constraints.count; i++)
-                       {
-                               struct constraint* c = r->constraints.item[i];
-                               emit_constraint(r, c);
-                       }
-               }
+               print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern);
 
                while (f)
                {
@@ -1043,23 +1011,26 @@ static void emitinsndata(Rule rules)
                                        const char* label = f->data + 1;
 
                                        if (strcmp(label, r->lhs->name) == 0)
-                                               print("%1data->emit_reg(node, %P%s_NT);\n", label);
+                                               print("%1data->emit_return_reg();\n", label);
                                        else
                                        {
                                                Tree node;
-                                               uint32_t path = find_label(r->pattern, label, 0, &node);
-                                               Nonterm nt = node->op;
-
-                                               if (path == PATH_MISSING)
+                                               int index = 0;
+                                               if (!find_child_index(r->pattern, label, &index, &node))
                                                        label_not_found(r, label);
+                                               Nonterm nt = node->op;
 
-                                               if (nt->is_fragment)
-                                                       print("%1data->emit_fragment(");
+                                               if (nt->kind == NONTERM)
+                                               {
+                                                       if (nt->is_fragment)
+                                                               print("%1data->emit_fragment(");
+                                                       else
+                                                               print("%1data->emit_reg(");
+                                               }
                                                else
                                                        print("%1data->emit_reg(");
 
-                                               print_path(path);
-                                               print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
+                                               print("%d);\n", index);
                                        }
                                        break;
                                }
@@ -1067,12 +1038,11 @@ static void emitinsndata(Rule rules)
                                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)
+                                       int index = 0;
+                                       if (!find_child_index(r->pattern, label, &index, NULL))
                                                label_not_found(r, label);
-                                       print_path(path);
-                                       print(");\n");
+
+                                       print("%1data->emit_value(%d);\n", index);
                                        break;
                                }
 
index 9180113..a3ff019 100644 (file)
@@ -39,14 +39,14 @@ extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost);
 struct burm_emitter_data
 {
     void (*emit_string)(const char* data);
-    void (*emit_fragment)(NODEPTR_TYPE node, int goal);
-    void (*emit_reg)(NODEPTR_TYPE node, int goal);
-    void (*emit_value)(NODEPTR_TYPE node);
+    void (*emit_fragment)(int child);
+    void (*emit_return_reg)(void);
+    void (*emit_reg)(int child);
+    void (*emit_value)(int child);
     void (*emit_eoi)(void);
-    void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal);
 };
 
-typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data);
+typedef void burm_emitter_t(const struct burm_emitter_data* data);
 
 struct burm_instruction_data
 {