Sort of keep track of registers and register classes. Start walking the
generated instruction tree --- holy cow, they look like instructions!
This commit is contained in:
parent
bde5792b1a
commit
39aa672422
|
@ -35,6 +35,7 @@ struct ir
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
void* state_label; /* used by the iburg instruction selector */
|
void* state_label; /* used by the iburg instruction selector */
|
||||||
|
int insn_no;
|
||||||
|
|
||||||
bool is_sequence : 1;
|
bool is_sequence : 1;
|
||||||
bool is_generated : 1;
|
bool is_generated : 1;
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
static int OP_LABEL(struct ir* ir)
|
static int OP_LABEL(struct ir* ir)
|
||||||
{
|
{
|
||||||
if (ir->is_generated)
|
if (ir->is_generated)
|
||||||
|
{
|
||||||
|
assert(ir->is_sequence);
|
||||||
return ir_to_esn(IR_REG, ir->size);
|
return ir_to_esn(IR_REG, ir->size);
|
||||||
|
}
|
||||||
return ir_to_esn(ir->opcode, ir->size);
|
return ir_to_esn(ir->opcode, ir->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,25 +38,75 @@ void burm_panic_cannot_match(struct ir* ir)
|
||||||
exit(1);
|
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];
|
tracef('I', "I: emit: %s\n", data);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
static void select_instructions(struct basicblock* bb)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -73,7 +123,7 @@ static void select_instructions(struct basicblock* bb)
|
||||||
if (!insnno)
|
if (!insnno)
|
||||||
burm_panic_cannot_match(ir);
|
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];
|
struct basicblock* bb = proc->blocks[i];
|
||||||
select_instructions(bb);
|
select_instructions(bb);
|
||||||
}
|
}
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set sw=4 ts=4 expandtab : */
|
/* vim: set sw=4 ts=4 expandtab : */
|
||||||
|
|
|
@ -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
|
PATTERNS
|
||||||
|
|
||||||
/* Special */
|
/* Special */
|
||||||
|
|
||||||
reg;
|
reg;
|
||||||
|
|
||||||
|
reg = REG4;
|
||||||
|
|
||||||
PAIR(BLOCK4, BLOCK4);
|
PAIR(BLOCK4, BLOCK4);
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +51,7 @@ PATTERNS
|
||||||
emit "mov r0, %in"
|
emit "mov r0, %in"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
|
||||||
/* Memory operations */
|
/* Memory operations */
|
||||||
|
|
||||||
STORE4(addr:address, value:reg)
|
STORE4(addr:address, value:reg)
|
||||||
|
@ -55,16 +82,16 @@ PATTERNS
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
address = in:LOCAL4
|
address = in:LOCAL4
|
||||||
fragment "[fp, #$in]";
|
emit "[fp, #$in]";
|
||||||
|
|
||||||
|
|
||||||
/* Memory addressing modes */
|
/* Memory addressing modes */
|
||||||
|
|
||||||
address = ADD4(addr:reg, offset:CONST)
|
address = ADD4(addr:reg, offset:CONST4)
|
||||||
fragment "[%addr, #$offset]";
|
emit "[%addr, #$offset]";
|
||||||
|
|
||||||
address = addr:reg
|
address = addr:reg
|
||||||
fragment "[%addr]";
|
emit "[%addr]";
|
||||||
|
|
||||||
|
|
||||||
/* Branches */
|
/* Branches */
|
||||||
|
@ -82,7 +109,6 @@ PATTERNS
|
||||||
/* Comparisons */
|
/* Comparisons */
|
||||||
|
|
||||||
tristate = COMPARES4(left:reg, right:aluparam)
|
tristate = COMPARES4(left:reg, right:aluparam)
|
||||||
outs CC
|
|
||||||
emit "cmp %left, %right"
|
emit "cmp %left, %right"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
@ -115,7 +141,7 @@ PATTERNS
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
aluparam = value:CONST4
|
aluparam = value:CONST4
|
||||||
fragment "#$value";
|
emit "#$value";
|
||||||
|
|
||||||
aluparam = reg;
|
aluparam = reg;
|
||||||
|
|
||||||
|
|
|
@ -16,40 +16,80 @@ static int nextern = 1;
|
||||||
%union {
|
%union {
|
||||||
int n;
|
int n;
|
||||||
char* string;
|
char* string;
|
||||||
|
Nonterm nonterm;
|
||||||
Tree tree;
|
Tree tree;
|
||||||
Rule rule;
|
Rule rule;
|
||||||
|
struct reg* reg;
|
||||||
struct stringlist* stringlist;
|
struct stringlist* stringlist;
|
||||||
char* stringpair[2];
|
char* stringpair[2];
|
||||||
}
|
}
|
||||||
%term TERMINAL
|
|
||||||
%term START
|
|
||||||
%term PPERCENT
|
|
||||||
|
|
||||||
%term PATTERNS
|
%term ALLOCATES
|
||||||
%term WHEN
|
%term COST
|
||||||
|
%term DECLARATIONS
|
||||||
%term EMIT
|
%term EMIT
|
||||||
%term FRAGMENT
|
%term FRAGMENT
|
||||||
%term COST
|
|
||||||
%term INS
|
%term INS
|
||||||
%term OUTS
|
%term OUTS
|
||||||
|
%term PATTERNS
|
||||||
|
%term REGISTERS
|
||||||
|
%term WHEN
|
||||||
|
|
||||||
%token <n> INT
|
%token <n> INT
|
||||||
%token <string> ID
|
%token <string> ID
|
||||||
%token <string> CFRAGMENT
|
%token <string> CFRAGMENT
|
||||||
%token <string> QFRAGMENT
|
%token <string> QFRAGMENT
|
||||||
|
|
||||||
%type <rule> pattern
|
%type <nonterm> allocates
|
||||||
|
%type <nonterm> declaration
|
||||||
|
%type <reg> register
|
||||||
%type <rule> emit
|
%type <rule> emit
|
||||||
|
%type <rule> pattern
|
||||||
%type <stringlist> cfragments
|
%type <stringlist> cfragments
|
||||||
%type <stringlist> qfragments
|
%type <stringlist> qfragments
|
||||||
%type <tree> rhs
|
|
||||||
%type <stringpair> labelledid
|
%type <stringpair> labelledid
|
||||||
|
%type <tree> rhs
|
||||||
%%
|
%%
|
||||||
|
|
||||||
spec
|
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
|
patterns
|
||||||
: /* nothing */
|
: /* nothing */
|
||||||
| patterns pattern ';'
|
| patterns pattern ';'
|
||||||
|
@ -57,11 +97,9 @@ patterns
|
||||||
;
|
;
|
||||||
|
|
||||||
pattern
|
pattern
|
||||||
: ID '=' rhs { nonterm($1); $$ = rule($1, $3, nextern++); }
|
: ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); }
|
||||||
| rhs { $$ = rule("stmt", $1, nextern++); }
|
| rhs { $$ = rule("stmt", $1, nextern++); }
|
||||||
| pattern WHEN cfragments { $$ = $1; stringlist_addall(&$$->when, $3); }
|
| pattern WHEN cfragments { $$ = $1; stringlist_addall(&$$->when, $3); }
|
||||||
| pattern INS ins { $$ = $1; }
|
|
||||||
| pattern OUTS outs { $$ = $1; }
|
|
||||||
| emit { $$ = $1; }
|
| emit { $$ = $1; }
|
||||||
| pattern COST INT { $$ = $1; $$->cost = $3; }
|
| pattern COST INT { $$ = $1; $$->cost = $3; }
|
||||||
;
|
;
|
||||||
|
@ -82,42 +120,18 @@ cfragments
|
||||||
| cfragments CFRAGMENT { $$ = $1; stringlist_add($$, $2); }
|
| cfragments CFRAGMENT { $$ = $1; stringlist_add($$, $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
ins
|
|
||||||
: ins ',' in
|
|
||||||
| in
|
|
||||||
;
|
|
||||||
|
|
||||||
in
|
|
||||||
: ID ':' ID
|
|
||||||
;
|
|
||||||
|
|
||||||
outs
|
|
||||||
: outs ',' out
|
|
||||||
| out
|
|
||||||
;
|
|
||||||
|
|
||||||
out
|
|
||||||
: ID
|
|
||||||
| ID ':' ID
|
|
||||||
;
|
|
||||||
|
|
||||||
emit
|
emit
|
||||||
: pattern EMIT qfragments {
|
: pattern EMIT qfragments {
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
stringlist_add($3, "\n");
|
if (!$$->lhs->is_fragment)
|
||||||
|
stringlist_add($3, "\n");
|
||||||
stringlist_addall(&$$->code, $3);
|
stringlist_addall(&$$->code, $3);
|
||||||
$$->is_fragment = false;
|
|
||||||
}
|
|
||||||
| pattern FRAGMENT qfragments {
|
|
||||||
$$ = $1;
|
|
||||||
stringlist_addall(&$$->code, $3);
|
|
||||||
$$->is_fragment = true;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
qfragments
|
qfragments
|
||||||
: /* nothing */ { $$ = calloc(1, sizeof *$$); }
|
: /* nothing */ { $$ = calloc(1, sizeof *$$); }
|
||||||
| qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); }
|
| qfragments QFRAGMENT { $$ = $1; stringlist_add($$, $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -20,6 +20,8 @@ static char* prefix = "burm";
|
||||||
static int Tflag = 1; /* tracing */
|
static int Tflag = 1; /* tracing */
|
||||||
static int ntnumber = 0;
|
static int ntnumber = 0;
|
||||||
static Nonterm start = 0;
|
static Nonterm start = 0;
|
||||||
|
static struct reg* regs = NULL;
|
||||||
|
static struct regclass* regclasses = NULL;
|
||||||
static Term terms;
|
static Term terms;
|
||||||
static Nonterm nts;
|
static Nonterm nts;
|
||||||
static Rule rules;
|
static Rule rules;
|
||||||
|
@ -34,14 +36,16 @@ static void emitcostcalc(Rule r);
|
||||||
static void emitdefs(Nonterm nts, int ntnumber);
|
static void emitdefs(Nonterm nts, int ntnumber);
|
||||||
static void emitfuncs(void);
|
static void emitfuncs(void);
|
||||||
static void emitheader(void);
|
static void emitheader(void);
|
||||||
|
static void emitinsndata(Rule rules);
|
||||||
static void emitkids(Rule rules, int nrules);
|
static void emitkids(Rule rules, int nrules);
|
||||||
static void emitlabel(Nonterm start);
|
static void emitlabel(Nonterm start);
|
||||||
static void emitleaf(Term p, int ntnumber);
|
static void emitleaf(Term p, int ntnumber);
|
||||||
static void emitnts(Rule rules, int nrules);
|
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 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 emitstate(Term terms, Nonterm start, int ntnumber);
|
||||||
static void emitstring(Rule rules);
|
static void emitstring(Rule rules);
|
||||||
static void emitstruct(Nonterm nts, int ntnumber);
|
static void emitstruct(Nonterm nts, int ntnumber);
|
||||||
|
@ -116,7 +120,7 @@ int main(int argc, char* argv[])
|
||||||
emitheader();
|
emitheader();
|
||||||
registerterminals();
|
registerterminals();
|
||||||
|
|
||||||
start = nonterm("stmt");
|
start = nonterm("stmt", true);
|
||||||
|
|
||||||
yyin = infp;
|
yyin = infp;
|
||||||
yyparse();
|
yyparse();
|
||||||
|
@ -127,6 +131,8 @@ int main(int argc, char* argv[])
|
||||||
if (!p->reached)
|
if (!p->reached)
|
||||||
yyerror("can't reach non-terminal `%s'\n", p->name);
|
yyerror("can't reach non-terminal `%s'\n", p->name);
|
||||||
|
|
||||||
|
emitregisterclasses(regclasses);
|
||||||
|
emitregisters(regs);
|
||||||
emitdefs(nts, ntnumber);
|
emitdefs(nts, ntnumber);
|
||||||
emitstruct(nts, ntnumber);
|
emitstruct(nts, ntnumber);
|
||||||
emitnts(rules, nrules);
|
emitnts(rules, nrules);
|
||||||
|
@ -203,6 +209,8 @@ struct entry
|
||||||
const char* name;
|
const char* name;
|
||||||
struct term t;
|
struct term t;
|
||||||
struct nonterm nt;
|
struct nonterm nt;
|
||||||
|
struct reg r;
|
||||||
|
struct regclass rc;
|
||||||
} sym;
|
} sym;
|
||||||
struct entry* link;
|
struct entry* link;
|
||||||
} * table[211];
|
} * table[211];
|
||||||
|
@ -219,7 +227,7 @@ static unsigned hash(const char* str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lookup - lookup symbol name */
|
/* lookup - lookup symbol name */
|
||||||
static void* lookup(const char* name)
|
void* lookup(const char* name)
|
||||||
{
|
{
|
||||||
struct entry* p = table[hash(name) % HASHSIZE];
|
struct entry* p = table[hash(name) % HASHSIZE];
|
||||||
|
|
||||||
|
@ -241,15 +249,69 @@ static void* install(const char* name)
|
||||||
return &p->sym;
|
return &p->sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nonterm - create a new terminal id, if necessary */
|
struct reg* makereg(const char* id)
|
||||||
Nonterm nonterm(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)
|
if (p && p->kind == NONTERM)
|
||||||
return p;
|
return p;
|
||||||
if (p && p->kind == TERM)
|
if (p)
|
||||||
yyerror("`%s' is a terminal\n", id);
|
yyerror("redefinition of '%s' as something else\n", id);
|
||||||
|
if (!allocate)
|
||||||
|
yyerror("'%s' has not been declared\n", id);
|
||||||
|
|
||||||
p = install(id);
|
p = install(id);
|
||||||
p->kind = NONTERM;
|
p->kind = NONTERM;
|
||||||
p->number = ++ntnumber;
|
p->number = ++ntnumber;
|
||||||
|
@ -270,12 +332,9 @@ Term term(const char* id, int esn)
|
||||||
Term* q = &terms;
|
Term* q = &terms;
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
{
|
yyerror("redefinition of '%s'\n", id);
|
||||||
yyerror("redefinition of terminal `%s'\n", id);
|
|
||||||
exit(1);
|
p = install(id);
|
||||||
}
|
|
||||||
else
|
|
||||||
p = install(id);
|
|
||||||
p->kind = TERM;
|
p->kind = TERM;
|
||||||
p->esn = esn;
|
p->esn = esn;
|
||||||
p->arity = -1;
|
p->arity = -1;
|
||||||
|
@ -309,7 +368,7 @@ Tree tree(const char* id, const char* label, Tree left, Tree right)
|
||||||
p = term(id, -1);
|
p = term(id, -1);
|
||||||
}
|
}
|
||||||
else if (p == NULL && arity == 0)
|
else if (p == NULL && arity == 0)
|
||||||
p = (Term)nonterm(id);
|
p = (Term)nonterm(id, false);
|
||||||
else if (p && p->kind == NONTERM && arity > 0)
|
else if (p && p->kind == NONTERM && arity > 0)
|
||||||
{
|
{
|
||||||
yyerror("`%s' is a non-terminal\n", id);
|
yyerror("`%s' is a non-terminal\n", id);
|
||||||
|
@ -338,7 +397,7 @@ Rule rule(char* id, Tree pattern, int ern)
|
||||||
|
|
||||||
nrules++;
|
nrules++;
|
||||||
r->lineno = yylineno;
|
r->lineno = yylineno;
|
||||||
r->lhs = nonterm(id);
|
r->lhs = nonterm(id, false);
|
||||||
r->packed = ++r->lhs->lhscount;
|
r->packed = ++r->lhs->lhscount;
|
||||||
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
|
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
|
||||||
;
|
;
|
||||||
|
@ -452,6 +511,38 @@ static void ckreach(Nonterm p)
|
||||||
reach(r->pattern);
|
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 */
|
/* emitcase - emit one case in function state */
|
||||||
static void emitcase(Term p, int ntnumber)
|
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;
|
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 */
|
/* emitinsndata - emit the code generation data */
|
||||||
static void emitinsndata(Rule rules)
|
static void emitinsndata(Rule rules)
|
||||||
{
|
{
|
||||||
|
@ -854,7 +952,7 @@ static void emitinsndata(Rule rules)
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
print("/* %R */\n", r);
|
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)
|
while (f)
|
||||||
{
|
{
|
||||||
|
@ -864,20 +962,28 @@ static void emitinsndata(Rule rules)
|
||||||
{
|
{
|
||||||
const char* label = f->data + 1;
|
const char* label = f->data + 1;
|
||||||
|
|
||||||
print("%1data->emit_ir(");
|
|
||||||
if (strcmp(label, r->lhs->name) == 0)
|
if (strcmp(label, r->lhs->name) == 0)
|
||||||
print("node");
|
print("%1data->emit_resultreg();\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t path = find_label(r->pattern, label, 0);
|
uint32_t path = find_label(r->pattern, label, 0);
|
||||||
|
print("%1data->emit_reg(");
|
||||||
if (path == PATH_MISSING)
|
if (path == PATH_MISSING)
|
||||||
{
|
label_not_found(r, label);
|
||||||
yylineno = r->lineno;
|
|
||||||
yyerror("label '%s' not found", label);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
print_path(path);
|
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");
|
print(");\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -919,7 +1025,12 @@ static void emitinsndata(Rule rules)
|
||||||
else
|
else
|
||||||
print("NULL,\n");
|
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");
|
print("%1},\n");
|
||||||
r = r->link;
|
r = r->link;
|
||||||
|
|
|
@ -8,10 +8,33 @@ extern char* stringf(char* fmt, ...);
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
TERM = 1,
|
TERM = 1,
|
||||||
NONTERM
|
NONTERM,
|
||||||
|
REG,
|
||||||
|
REGCLASS
|
||||||
} Kind;
|
} Kind;
|
||||||
typedef struct rule* Rule;
|
typedef struct rule* Rule;
|
||||||
typedef struct term* Term;
|
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
|
struct term
|
||||||
{ /* terminals: */
|
{ /* terminals: */
|
||||||
char* name; /* terminal name */
|
char* name; /* terminal name */
|
||||||
|
@ -25,16 +48,19 @@ struct term
|
||||||
typedef struct nonterm* Nonterm;
|
typedef struct nonterm* Nonterm;
|
||||||
struct nonterm
|
struct nonterm
|
||||||
{ /* non-terminals: */
|
{ /* non-terminals: */
|
||||||
char* name; /* non-terminal name */
|
char* name; /* non-terminal name */
|
||||||
Kind kind; /* NONTERM */
|
Kind kind; /* NONTERM */
|
||||||
int number; /* identifying number */
|
int number; /* identifying number */
|
||||||
int lhscount; /* # times nt appears in a rule lhs */
|
int lhscount; /* # times nt appears in a rule lhs */
|
||||||
int reached; /* 1 iff reached from start non-terminal */
|
int reached; /* 1 iff reached from start non-terminal */
|
||||||
Rule rules; /* rules w/non-terminal on lhs */
|
Rule rules; /* rules w/non-terminal on lhs */
|
||||||
Rule chain; /* chain rules w/non-terminal on rhs */
|
Rule chain; /* chain rules w/non-terminal on rhs */
|
||||||
Nonterm link; /* next terminal in number order */
|
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);
|
extern Term term(const char* id, int esn);
|
||||||
|
|
||||||
typedef struct tree* Tree;
|
typedef struct tree* Tree;
|
||||||
|
@ -62,7 +88,6 @@ struct rule
|
||||||
Rule kids; /* next rule with same burm_kids pattern */
|
Rule kids; /* next rule with same burm_kids pattern */
|
||||||
struct stringlist when; /* C predicate string */
|
struct stringlist when; /* C predicate string */
|
||||||
struct stringlist code; /* compiler output code strings */
|
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 Rule rule(char* id, Tree pattern, int ern);
|
||||||
extern int maxcost; /* maximum cost */
|
extern int maxcost; /* maximum cost */
|
||||||
|
|
|
@ -26,18 +26,20 @@ extern void burm_trace(struct ir* p, int ruleno, int cost, int bestcost);
|
||||||
|
|
||||||
struct burm_emitter_data
|
struct burm_emitter_data
|
||||||
{
|
{
|
||||||
void* user;
|
|
||||||
void (*emit_string)(const char* data);
|
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);
|
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
|
struct burm_instruction_data
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
burm_emitter_t* emitter;
|
burm_emitter_t* emitter;
|
||||||
|
int allocate;
|
||||||
bool is_fragment;
|
bool is_fragment;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,12 @@ static int braces = 0;
|
||||||
<INITIAL>"\"" BEGIN(QSTRING);
|
<INITIAL>"\"" BEGIN(QSTRING);
|
||||||
<QSTRING>"\"" BEGIN(INITIAL);
|
<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);
|
yylval.string = strdup(yytext);
|
||||||
return QFRAGMENT;
|
return QFRAGMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
<QSTRING>[^\r\n%"]+ {
|
<QSTRING>[^\r\n%$"]+ {
|
||||||
yylval.string = strdup(yytext);
|
yylval.string = strdup(yytext);
|
||||||
return QFRAGMENT;
|
return QFRAGMENT;
|
||||||
}
|
}
|
||||||
|
@ -65,17 +65,16 @@ static int braces = 0;
|
||||||
<COMMENT>[^*]* ;
|
<COMMENT>[^*]* ;
|
||||||
<COMMENT>"*" ;
|
<COMMENT>"*" ;
|
||||||
|
|
||||||
"%%" return PPERCENT;
|
"DECLARATIONS" return DECLARATIONS;
|
||||||
"%term" return TERMINAL;
|
|
||||||
"%start" return START;
|
|
||||||
|
|
||||||
"PATTERNS" return PATTERNS;
|
"PATTERNS" return PATTERNS;
|
||||||
"when" return WHEN;
|
"REGISTERS" return REGISTERS;
|
||||||
"ins" return INS;
|
"allocates" return ALLOCATES;
|
||||||
"outs" return OUTS;
|
"cost" return COST;
|
||||||
"emit" return EMIT;
|
"emit" return EMIT;
|
||||||
"fragment" return FRAGMENT;
|
"fragment" return FRAGMENT;
|
||||||
"cost" return COST;
|
"ins" return INS;
|
||||||
|
"outs" return OUTS;
|
||||||
|
"when" return WHEN;
|
||||||
|
|
||||||
"//"[^\n]*\n ;
|
"//"[^\n]*\n ;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue