Sort of keep track of registers and register classes. Start walking the
authorDavid Given <dg@cowlark.com>
Sun, 25 Sep 2016 20:17:14 +0000 (22:17 +0200)
committerDavid Given <dg@cowlark.com>
Sun, 25 Sep 2016 20:17:14 +0000 (22:17 +0200)
generated instruction tree --- holy cow, they look like instructions!

mach/proto/mcg/ir.h
mach/proto/mcg/mcgg_generated_header.h
mach/proto/mcg/pass_instructionselection.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 eaf0314..5868551 100644 (file)
@@ -35,6 +35,7 @@ struct ir
        } u;
 
        void* state_label; /* used by the iburg instruction selector */
+       int insn_no;
 
        bool is_sequence : 1;
        bool is_generated : 1;
index 36e394b..fbe0603 100644 (file)
@@ -7,7 +7,10 @@
 static int OP_LABEL(struct ir* ir)
 {
        if (ir->is_generated)
+       {
+               assert(ir->is_sequence);
                return ir_to_esn(IR_REG, ir->size);
+       }
        return ir_to_esn(ir->opcode, ir->size);
 }
 
index bfdaa77..dd386a7 100644 (file)
@@ -38,25 +38,75 @@ void burm_panic_cannot_match(struct ir* ir)
        exit(1);
 }
 
-static void queue_instructions(struct ir* ir, int goal)
+static const struct burm_emitter_data emitter_data;
+
+static void emit_string(const char* data)
 {
-       struct ir* children[10];
-       int ruleno = burm_rule(ir->state_label, goal);
-    const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
-       const short* nts = burm_nts[ruleno];
-       int i;
+    tracef('I', "I: emit: %s\n", data);
+}
+
+static void emit_reg(struct ir* ir)
+{
+    const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no];
+    if (insndata->is_fragment)
+        insndata->emitter(ir, &emitter_data);
+    else
+        tracef('I', "I: emit reg $%d\n", ir->id);
+}
+
+static void emit_value(struct ir* ir)
+{
+    tracef('I', "I: emit value\n");
+}
+
+static void emit_resultreg(void)
+{
+    tracef('I', "I: emit resultreg\n");
+}
+
+static void emit_eoi(void)
+{
+    tracef('I', "I: emit eoi\n");
+}
+
+static const struct burm_emitter_data emitter_data =
+{
+    &emit_string,
+    &emit_reg,
+    &emit_value,
+    &emit_resultreg,
+    &emit_eoi
+};
+
+static void walk_instructions(struct ir* ir, int goal)
+{
+    struct ir* children[10];
+    int insn_no = burm_rule(ir->state_label, goal);
+    const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
+    const short* nts = burm_nts[insn_no];
+    int i;
+
+    ir->insn_no = insn_no;
 
-       burm_kids(ir, ruleno, children);
-       for (i=0; nts[i]; i++)
-               queue_instructions(children[i], nts[i]);
+    burm_kids(ir, insn_no, children);
+    for (i=0; nts[i]; i++)
+        walk_instructions(children[i], nts[i]);
 
-    tracef('I', "I: $%d selected %s %d: %s\n",
+    tracef('I', "I: $%d %s selected %s %d: %s\n",
         ir->id,
+        ir->is_sequence ? "S" : " ",
         insndata->is_fragment ? "fragment" : "instruction",
-        ruleno,
+        insn_no,
         insndata->name);
+    ir->is_generated = true;
+
+    if (insndata->allocate)
+        tracef('I', "I: allocate reg of class %d\n", insndata->allocate);
+    if (!insndata->is_fragment && insndata->emitter)
+        insndata->emitter(ir, &emitter_data);
 }
 
+
 static void select_instructions(struct basicblock* bb)
 {
        int i;
@@ -73,7 +123,7 @@ static void select_instructions(struct basicblock* bb)
                if (!insnno)
                        burm_panic_cannot_match(ir);
 
-               queue_instructions(ir, 1);
+               walk_instructions(ir, 1);
        }
 }
 
@@ -86,7 +136,6 @@ void pass_instruction_selector(struct procedure* proc)
         struct basicblock* bb = proc->blocks[i];
         select_instructions(bb);
     }
-       exit(1);
 }
 
 /* vim: set sw=4 ts=4 expandtab : */
index 9146f63..d450842 100644 (file)
@@ -1,9 +1,35 @@
+REGISTERS
+
+       r0  GPR RET0;
+       r1  GPR RET1;
+       r2  GPR;
+       r3  GPR;
+       r4  GPR;
+       r5  GPR;
+       r6  GPR;
+       r7  GPR;
+       r8  GPR;
+       r9  GPR;
+       r10 GPR;
+       r11 GPR;
+
+       cc  CC;
+
+DECLARATIONS
+
+       address   fragment;
+       aluparam  fragment;
+       reg       allocates(GPR);
+       tristate  allocates(CC);
+
 PATTERNS
 
 /* Special */
 
        reg;
 
+       reg = REG4;
+
        PAIR(BLOCK4, BLOCK4);
 
 
@@ -25,6 +51,7 @@ PATTERNS
                emit "mov r0, %in"
                cost 4;
 
+
 /* Memory operations */
 
        STORE4(addr:address, value:reg)
@@ -55,16 +82,16 @@ PATTERNS
                cost 4;
 
        address = in:LOCAL4
-               fragment "[fp, #$in]";
+               emit "[fp, #$in]";
 
 
 /* Memory addressing modes */
 
-       address = ADD4(addr:reg, offset:CONST)
-               fragment "[%addr, #$offset]";
+       address = ADD4(addr:reg, offset:CONST4)
+               emit "[%addr, #$offset]";
 
        address = addr:reg
-               fragment "[%addr]";
+               emit "[%addr]";
 
 
 /* Branches */
@@ -82,7 +109,6 @@ PATTERNS
 /* Comparisons */
 
        tristate = COMPARES4(left:reg, right:aluparam)
-               outs CC
                emit "cmp %left, %right"
                cost 4;
 
@@ -115,7 +141,7 @@ PATTERNS
                cost 4;
 
        aluparam = value:CONST4
-               fragment "#$value";
+               emit "#$value";
 
        aluparam = reg;
 
index e248598..177f33d 100644 (file)
@@ -16,40 +16,80 @@ static int nextern = 1;
 %union {
        int n;
        char* string;
+    Nonterm nonterm;
        Tree tree;
     Rule rule;
+    struct reg* reg;
     struct stringlist* stringlist;
     char* stringpair[2];
 }
-%term TERMINAL
-%term START
-%term PPERCENT
 
-%term PATTERNS
-%term WHEN
+%term ALLOCATES
+%term COST
+%term DECLARATIONS
 %term EMIT
 %term FRAGMENT
-%term COST
 %term INS
 %term OUTS
+%term PATTERNS
+%term REGISTERS
+%term WHEN
 
 %token <n>          INT
 %token <string>     ID
 %token <string>     CFRAGMENT
 %token <string>     QFRAGMENT
 
-%type  <rule>       pattern
+%type  <nonterm>    allocates
+%type  <nonterm>    declaration
+%type  <reg>        register
 %type  <rule>       emit
+%type  <rule>       pattern
 %type  <stringlist> cfragments
 %type  <stringlist> qfragments
-%type  <tree>       rhs
 %type  <stringpair> labelledid
+%type  <tree>       rhs
 %%
 
 spec
-    : PATTERNS patterns
+    : REGISTERS registers 
+      DECLARATIONS declarations
+      PATTERNS patterns
        ;
 
+registers
+    : /* nothing */
+    | registers register ';'
+    | register ';'
+    ;
+
+register
+    : ID                              { $$ = makereg($1); }
+    | register ID                     { $$ = $1; addregclass($1, $2); }
+    ;
+
+declarations
+    : /* nothing */
+    | declarations declaration ';'
+    | declaration ';'
+    ;
+
+declaration
+    : ID                              { $$ = nonterm($1, true); }
+    | declaration FRAGMENT            { $$ = $1; $$->is_fragment = true; }
+    | allocates                       { $$ = $1; }
+    ;
+
+allocates
+    : declaration ALLOCATES '(' ID ')'
+        {
+            $$ = $1;
+            if ($$->allocate)
+                yyerror("pattern type is defined to already allocate a register");
+            $$->allocate = getregclass($4);
+        }
+    ;
+
 patterns
     : /* nothing */
        | patterns pattern ';'
@@ -57,11 +97,9 @@ patterns
        ;
 
 pattern
-    : ID '=' rhs                      { nonterm($1); $$ = rule($1, $3, nextern++); }
-    | rhs                             {              $$ = rule("stmt", $1, nextern++); }
+    : ID '=' rhs                      { nonterm($1, false); $$ = rule($1,     $3, nextern++); }
+    | rhs                             {                     $$ = rule("stmt", $1, nextern++); }
     | pattern WHEN cfragments         { $$ = $1; stringlist_addall(&$$->when, $3); }
-    | pattern INS ins                 { $$ = $1; }
-    | pattern OUTS outs               { $$ = $1; }
     | emit                            { $$ = $1; }
     | pattern COST INT                { $$ = $1; $$->cost = $3; }
     ;
@@ -82,42 +120,18 @@ cfragments
     | cfragments CFRAGMENT            { $$ = $1; stringlist_add($$, $2); }
     ;
     
-ins
-    : ins ',' in
-    | in
-    ;
-
-in
-    : ID ':' ID
-    ;
-
-outs
-    : outs ',' out
-    | out
-    ;
-
-out
-    : ID
-    | ID ':' ID
-    ;
-
 emit
     : pattern EMIT qfragments           {
                                             $$ = $1;
-                                            stringlist_add($3, "\n");
+                                            if (!$$->lhs->is_fragment)
+                                                stringlist_add($3, "\n");
                                             stringlist_addall(&$$->code, $3);
-                                            $$->is_fragment = false;
-                                        }
-    | pattern FRAGMENT qfragments       {
-                                            $$ = $1;
-                                            stringlist_addall(&$$->code, $3);
-                                            $$->is_fragment = true;
                                         }
     ;
 
 qfragments
-    : /* nothing */                   { $$ = calloc(1, sizeof *$$); }
-    | qfragments QFRAGMENT            { $$ = $1; stringlist_add($$, $2); }
+    : /* nothing */                     { $$ = calloc(1, sizeof *$$); }
+    | qfragments QFRAGMENT              { $$ = $1; stringlist_add($$, $2); }
     ;
 
 %%
index 399ebdd..9ac77ed 100644 (file)
@@ -20,6 +20,8 @@ static char* prefix = "burm";
 static int Tflag = 1; /* tracing */
 static int ntnumber = 0;
 static Nonterm start = 0;
+static struct reg* regs = NULL;
+static struct regclass* regclasses = NULL;
 static Term terms;
 static Nonterm nts;
 static Rule rules;
@@ -34,14 +36,16 @@ static void emitcostcalc(Rule r);
 static void emitdefs(Nonterm nts, int ntnumber);
 static void emitfuncs(void);
 static void emitheader(void);
+static void emitinsndata(Rule rules);
 static void emitkids(Rule rules, int nrules);
 static void emitlabel(Nonterm start);
 static void emitleaf(Term p, int ntnumber);
 static void emitnts(Rule rules, int nrules);
+static void emitpredicatedefinitions(Rule rules);
 static void emitrecord(char* pre, Rule r, int cost);
+static void emitregisterclasses(struct regclass* rc);
+static void emitregisters(struct reg* regs);
 static void emitrule(Nonterm nts);
-static void emitpredicatedefinitions(Rule rules);
-static void emitinsndata(Rule rules);
 static void emitstate(Term terms, Nonterm start, int ntnumber);
 static void emitstring(Rule rules);
 static void emitstruct(Nonterm nts, int ntnumber);
@@ -116,7 +120,7 @@ int main(int argc, char* argv[])
        emitheader();
        registerterminals();
 
-       start = nonterm("stmt");
+       start = nonterm("stmt", true);
 
        yyin = infp;
        yyparse();
@@ -127,6 +131,8 @@ int main(int argc, char* argv[])
                if (!p->reached)
                        yyerror("can't reach non-terminal `%s'\n", p->name);
 
+       emitregisterclasses(regclasses);
+       emitregisters(regs);
        emitdefs(nts, ntnumber);
        emitstruct(nts, ntnumber);
        emitnts(rules, nrules);
@@ -203,6 +209,8 @@ struct entry
                const char* name;
                struct term t;
                struct nonterm nt;
+               struct reg r;
+               struct regclass rc;
        } sym;
        struct entry* link;
 } * table[211];
@@ -219,7 +227,7 @@ static unsigned hash(const char* str)
 }
 
 /* lookup - lookup symbol name */
-static void* lookup(const char* name)
+void* lookup(const char* name)
 {
        struct entry* p = table[hash(name) % HASHSIZE];
 
@@ -241,15 +249,69 @@ static void* install(const char* name)
        return &p->sym;
 }
 
+struct reg* makereg(const char* id)
+{
+       struct reg* p = lookup(id);
+       struct reg** q = &regs;
+       static int number = 1;
+
+       if (p)
+               yyerror("redefinition of '%s'", id);
+       p = install(id);
+       p->kind = REG;
+       p->number = number++;
+
+       while (*q && (*q)->number < p->number)
+               q = &(*q)->link;
+       assert(*q == 0 || (*q)->number != p->number);
+       p->link = *q;
+       *q = p;
+       return p;
+}
+
+void addregclass(struct reg* reg, const char* id)
+{
+       struct regclass* p = lookup(id);
+       struct regclass** q = &regclasses;
+       static int number = 1;
+
+       if (p && (p->kind != REGCLASS))
+               yyerror("redefinition of '%s' as something else\n", id);
+       if (!p)
+       {
+               p = install(id);
+               p->kind = REGCLASS;
+               p->number = number++;
+
+               while (*q && (*q)->number < p->number)
+                       q = &(*q)->link;
+               assert(*q == 0 || (*q)->number != p->number);
+               p->link = *q;
+               *q = p;
+       }
+}
+
+struct regclass* getregclass(const char* id)
+{
+       struct regclass* p = lookup(id);
+       if (!p || (p->kind != REGCLASS))
+               yyerror("'%p' is not the name of a register class");
+       return p;
+}
+
 /* nonterm - create a new terminal id, if necessary */
-Nonterm nonterm(const char* id)
+Nonterm nonterm(const char* id, bool allocate)
 {
-       Nonterm p = lookup(id), * q = &nts;
+       Nonterm p = lookup(id);
+       Nonterm* q = &nts;
 
        if (p && p->kind == NONTERM)
                return p;
-       if (p && p->kind == TERM)
-               yyerror("`%s' is a terminal\n", id);
+       if (p)
+               yyerror("redefinition of '%s' as something else\n", id);
+       if (!allocate)
+               yyerror("'%s' has not been declared\n", id);
+
        p = install(id);
        p->kind = NONTERM;
        p->number = ++ntnumber;
@@ -270,12 +332,9 @@ Term term(const char* id, int esn)
        Term* q = &terms;
 
        if (p)
-       {
-               yyerror("redefinition of terminal `%s'\n", id);
-               exit(1);
-       }
-       else
-               p = install(id);
+               yyerror("redefinition of '%s'\n", id);
+
+       p = install(id);
        p->kind = TERM;
        p->esn = esn;
        p->arity = -1;
@@ -309,7 +368,7 @@ Tree tree(const char* id, const char* label, Tree left, Tree right)
                p = term(id, -1);
        }
        else if (p == NULL && arity == 0)
-               p = (Term)nonterm(id);
+               p = (Term)nonterm(id, false);
        else if (p && p->kind == NONTERM && arity > 0)
        {
                yyerror("`%s' is a non-terminal\n", id);
@@ -338,7 +397,7 @@ Rule rule(char* id, Tree pattern, int ern)
 
        nrules++;
        r->lineno = yylineno;
-       r->lhs = nonterm(id);
+       r->lhs = nonterm(id, false);
        r->packed = ++r->lhs->lhscount;
        for (q = &r->lhs->rules; *q; q = &(*q)->decode)
                ;
@@ -452,6 +511,38 @@ static void ckreach(Nonterm p)
                reach(r->pattern);
 }
 
+static void emitregisterclasses(struct regclass* rc)
+{
+       int k = 0;
+       print("const char* %Pregister_class_names[] = {\n");
+       while (rc)
+       {
+               for (; k < rc->number; k++)
+                       print("%1NULL,\n");
+               k++;
+
+               print("%1\"%s\",\n", rc->name);
+               rc = rc->link;
+       }
+       print("};\n\n");
+}
+
+static void emitregisters(struct reg* r)
+{
+       int k = 0;
+       print("const char* %Pregister_names[] = {\n");
+       while (r)
+       {
+               for (; k < r->number; k++)
+                       print("%1NULL,\n");
+               k++;
+
+               print("%1\"%s\",\n", r->name);
+               r = r->link;
+       }
+       print("};\n\n");
+}
+
 /* emitcase - emit one case in function state */
 static void emitcase(Term p, int ntnumber)
 {
@@ -841,6 +932,13 @@ static uint32_t find_label(Tree root, const char* name, uint32_t path)
        return p;
 }
 
+static void label_not_found(Rule rule, const char* label)
+{
+       yylineno = rule->lineno;
+       yyerror("label '%s' not found", label);
+       exit(1);
+}
+
 /* emitinsndata - emit the code generation data */
 static void emitinsndata(Rule rules)
 {
@@ -854,7 +952,7 @@ static void emitinsndata(Rule rules)
                if (f)
                {
                        print("/* %R */\n", r);
-                       print("static void %Pemitter_%d(NODEPTR_TYPE node, struct %Pemitter_data* data) {\n", r->ern);
+                       print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
 
                        while (f)
                        {
@@ -864,20 +962,28 @@ static void emitinsndata(Rule rules)
                                        {
                                                const char* label = f->data + 1;
 
-                                               print("%1data->emit_ir(");
                                                if (strcmp(label, r->lhs->name) == 0)
-                                                       print("node");
+                                                       print("%1data->emit_resultreg();\n");
                                                else
                                                {
                                                        uint32_t path = find_label(r->pattern, label, 0);
+                                                       print("%1data->emit_reg(");
                                                        if (path == PATH_MISSING)
-                                                       {
-                                                               yylineno = r->lineno;
-                                                               yyerror("label '%s' not found", label);
-                                                               exit(1);
-                                                       }
+                                                               label_not_found(r, label);
                                                        print_path(path);
+                                                       print(");\n");
                                                }
+                                               break;
+                                       }
+
+                                       case '$':
+                                       {
+                                               const char* label = f->data + 1;
+                                               uint32_t path = find_label(r->pattern, label, 0);
+                                               print("%1data->emit_value(");
+                                               if (path == PATH_MISSING)
+                                                       label_not_found(r, label);
+                                               print_path(path);
                                                print(");\n");
                                                break;
                                        }
@@ -919,7 +1025,12 @@ static void emitinsndata(Rule rules)
                else
                        print("NULL,\n");
 
-               print("%2%s,\n", r->is_fragment ? "true" : "false");
+               if (r->lhs->allocate)
+                       print("%2%d,\n", r->lhs->allocate->number);
+               else
+                       print("%20,\n");
+
+               print("%2%s,\n", r->lhs->is_fragment ? "true" : "false");
 
                print("%1},\n");
                r = r->link;
index b289758..5709ae1 100644 (file)
@@ -8,10 +8,33 @@ extern char* stringf(char* fmt, ...);
 typedef enum
 {
        TERM = 1,
-       NONTERM
+       NONTERM,
+       REG,
+       REGCLASS
 } Kind;
 typedef struct rule* Rule;
 typedef struct term* Term;
+
+struct reg
+{
+       const char* name;      /* register name */
+       Kind kind;             /* REG */
+       int number;            /* identifying number */
+       struct reg* link;      /* next in list */
+};
+
+struct regclass
+{
+       const char* name;      /* class name */
+       Kind kind;             /* REGCLASS */
+       int number;            /* identifying number */
+       struct regclass* link; /* next in list */
+};
+
+extern struct reg* makereg(const char* name);
+extern void addregclass(struct reg* reg, const char* regclass);
+extern struct regclass* getregclass(const char* name);
+
 struct term
 { /* terminals: */
        char* name; /* terminal name */
@@ -25,16 +48,19 @@ struct term
 typedef struct nonterm* Nonterm;
 struct nonterm
 { /* non-terminals: */
-       char* name; /* non-terminal name */
-       Kind kind; /* NONTERM */
-       int number; /* identifying number */
-       int lhscount; /* # times nt appears in a rule lhs */
-       int reached; /* 1 iff reached from start non-terminal */
-       Rule rules; /* rules w/non-terminal on lhs */
-       Rule chain; /* chain rules w/non-terminal on rhs */
-       Nonterm link; /* next terminal in number order */
+       char* name;       /* non-terminal name */
+       Kind kind;        /* NONTERM */
+       int number;       /* identifying number */
+       int lhscount;     /* # times nt appears in a rule lhs */
+       int reached;      /* 1 iff reached from start non-terminal */
+       Rule rules;       /* rules w/non-terminal on lhs */
+       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 regclass* allocate; /* allocate this kind of register */
 };
-extern Nonterm nonterm(const char* id);
+extern void* lookup(const char* name);
+extern Nonterm nonterm(const char* id, bool allocate);
 extern Term term(const char* id, int esn);
 
 typedef struct tree* Tree;
@@ -62,7 +88,6 @@ struct rule
        Rule kids;               /* next rule with same burm_kids pattern */
        struct stringlist when;  /* C predicate string */
        struct stringlist code;  /* compiler output code strings */
-       bool is_fragment;        /* does this rule generate an instruction fragment? */
 };
 extern Rule rule(char* id, Tree pattern, int ern);
 extern int maxcost; /* maximum cost */
index 1279ee0..9c15eea 100644 (file)
@@ -26,18 +26,20 @@ extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost);
 
 struct burm_emitter_data
 {
-       void* user;
     void (*emit_string)(const char* data);
-    void (*emit_ir)(struct ir* ir);
+    void (*emit_reg)(struct ir* ir);
+    void (*emit_value)(struct ir* ir);
+    void (*emit_resultreg)(void);
     void (*emit_eoi)(void);
 };
 
-typedef void burm_emitter_t(struct ir* ir, struct burm_emitter_data* data);
+typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data);
 
 struct burm_instruction_data
 {
     const char* name;
     burm_emitter_t* emitter;
+    int allocate;
     bool is_fragment;
 };
 
index 479a115..83e0fe3 100644 (file)
@@ -50,12 +50,12 @@ static int braces = 0;
 <INITIAL>"\""               BEGIN(QSTRING);
 <QSTRING>"\""               BEGIN(INITIAL);
 
-<QSTRING>%[a-zA-Z_][a-zA_Z_0-9]+ {
+<QSTRING>[%$][a-zA-Z_][a-zA_Z_0-9]+ {
                                 yylval.string = strdup(yytext);
                                 return QFRAGMENT;
                             }
 
-<QSTRING>[^\r\n%"]+         {
+<QSTRING>[^\r\n%$"]+        {
                                 yylval.string = strdup(yytext);
                                 return QFRAGMENT;
                             }
@@ -65,17 +65,16 @@ static int braces = 0;
 <COMMENT>[^*]*              ;
 <COMMENT>"*"                ;
 
-"%%"                        return PPERCENT;
-"%term"                                                return TERMINAL;
-"%start"                                       return START;
-
+"DECLARATIONS"              return DECLARATIONS;
 "PATTERNS"                  return PATTERNS;
-"when"                      return WHEN;
-"ins"                       return INS;
-"outs"                      return OUTS;
+"REGISTERS"                 return REGISTERS;
+"allocates"                 return ALLOCATES;
+"cost"                      return COST;
 "emit"                      return EMIT;
 "fragment"                  return FRAGMENT;
-"cost"                      return COST;
+"ins"                       return INS;
+"outs"                      return OUTS;
+"when"                      return WHEN;
 
 "//"[^\n]*\n                ;