} u;
void* state_label; /* used by the iburg instruction selector */
+ int insn_no;
bool is_sequence : 1;
bool is_generated : 1;
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);
}
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;
if (!insnno)
burm_panic_cannot_match(ir);
- queue_instructions(ir, 1);
+ walk_instructions(ir, 1);
}
}
struct basicblock* bb = proc->blocks[i];
select_instructions(bb);
}
- exit(1);
}
/* vim: set sw=4 ts=4 expandtab : */
+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);
emit "mov r0, %in"
cost 4;
+
/* Memory operations */
STORE4(addr:address, value:reg)
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 */
/* Comparisons */
tristate = COMPARES4(left:reg, right:aluparam)
- outs CC
emit "cmp %left, %right"
cost 4;
cost 4;
aluparam = value:CONST4
- fragment "#$value";
+ emit "#$value";
aluparam = reg;
%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 ';'
;
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; }
;
| 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); }
;
%%
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;
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);
emitheader();
registerterminals();
- start = nonterm("stmt");
+ start = nonterm("stmt", true);
yyin = infp;
yyparse();
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);
const char* name;
struct term t;
struct nonterm nt;
+ struct reg r;
+ struct regclass rc;
} sym;
struct entry* link;
} * table[211];
}
/* lookup - lookup symbol name */
-static void* lookup(const char* name)
+void* lookup(const char* name)
{
struct entry* p = table[hash(name) % HASHSIZE];
return &p->sym;
}
+struct reg* makereg(const char* id)
+{
+ 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)
+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;
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;
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);
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)
;
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)
{
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)
{
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)
{
{
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;
}
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;
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 */
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;
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 */
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;
};
<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;
}
<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 ;