diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index eaf031475..5868551db 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -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; diff --git a/mach/proto/mcg/mcgg_generated_header.h b/mach/proto/mcg/mcgg_generated_header.h index 36e394b6c..fbe0603dd 100644 --- a/mach/proto/mcg/mcgg_generated_header.h +++ b/mach/proto/mcg/mcgg_generated_header.h @@ -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); } diff --git a/mach/proto/mcg/pass_instructionselection.c b/mach/proto/mcg/pass_instructionselection.c index bfdaa77bd..dd386a77b 100644 --- a/mach/proto/mcg/pass_instructionselection.c +++ b/mach/proto/mcg/pass_instructionselection.c @@ -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; - - burm_kids(ir, ruleno, children); - for (i=0; nts[i]; i++) - queue_instructions(children[i], nts[i]); - - tracef('I', "I: $%d selected %s %d: %s\n", - ir->id, - insndata->is_fragment ? "fragment" : "instruction", - ruleno, - insndata->name); + 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, insn_no, children); + for (i=0; nts[i]; i++) + walk_instructions(children[i], nts[i]); + + tracef('I', "I: $%d %s selected %s %d: %s\n", + ir->id, + ir->is_sequence ? "S" : " ", + insndata->is_fragment ? "fragment" : "instruction", + 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 : */ diff --git a/mach/proto/mcg/table b/mach/proto/mcg/table index 9146f6339..d450842aa 100644 --- a/mach/proto/mcg/table +++ b/mach/proto/mcg/table @@ -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; diff --git a/util/mcgg/gram.y b/util/mcgg/gram.y index e24859851..177f33d72 100644 --- a/util/mcgg/gram.y +++ b/util/mcgg/gram.y @@ -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 INT %token ID %token CFRAGMENT %token QFRAGMENT -%type pattern +%type allocates +%type declaration +%type register %type emit +%type pattern %type cfragments %type qfragments -%type rhs %type labelledid +%type 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); } ; %% diff --git a/util/mcgg/iburg.c b/util/mcgg/iburg.c index 399ebdd85..9ac77edef 100644 --- a/util/mcgg/iburg.c +++ b/util/mcgg/iburg.c @@ -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 emitrecord(char* pre, Rule r, int cost); -static void emitrule(Nonterm nts); static void emitpredicatedefinitions(Rule rules); -static void emitinsndata(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 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; } -/* nonterm - create a new terminal id, if necessary */ -Nonterm nonterm(const char* id) +struct reg* makereg(const char* id) { - Nonterm p = lookup(id), * q = &nts; + struct reg* p = lookup(id); + struct reg** q = ®s; + 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 = ®classes; + 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, bool allocate) +{ + 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; diff --git a/util/mcgg/iburg.h b/util/mcgg/iburg.h index b2897587a..5709ae13e 100644 --- a/util/mcgg/iburg.h +++ b/util/mcgg/iburg.h @@ -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 */ diff --git a/util/mcgg/mcgg.h b/util/mcgg/mcgg.h index 1279ee0ec..9c15eea82 100644 --- a/util/mcgg/mcgg.h +++ b/util/mcgg/mcgg.h @@ -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; }; diff --git a/util/mcgg/scan.l b/util/mcgg/scan.l index 479a115fc..83e0fe3cf 100644 --- a/util/mcgg/scan.l +++ b/util/mcgg/scan.l @@ -50,12 +50,12 @@ static int braces = 0; "\"" BEGIN(QSTRING); "\"" BEGIN(INITIAL); -%[a-zA-Z_][a-zA_Z_0-9]+ { +[%$][a-zA-Z_][a-zA_Z_0-9]+ { yylval.string = strdup(yytext); return QFRAGMENT; } -[^\r\n%"]+ { +[^\r\n%$"]+ { yylval.string = strdup(yytext); return QFRAGMENT; } @@ -65,17 +65,16 @@ static int braces = 0; [^*]* ; "*" ; -"%%" 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 ;