Better constraint syntax; mcgg now passes register usage information up to mcg;

mcg can track individual hop inputs and outputs (needed for live range
analysis!); the register allocator now puts the basic blocks into the right
order in preparation for live range analysis.
This commit is contained in:
David Given 2016-10-05 22:56:25 +02:00
parent 7a6fc7a72b
commit 88fb231d6e
11 changed files with 240 additions and 127 deletions

View file

@ -50,7 +50,7 @@ void hop_add_eoi_insel(struct hop* hop)
void hop_print(char k, struct hop* hop) void hop_print(char k, struct hop* hop)
{ {
int i; int i, j;
bool soi = true; bool soi = true;
i = 0; i = 0;
@ -60,7 +60,14 @@ void hop_print(char k, struct hop* hop)
if (soi) if (soi)
{ {
tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id); tracef(k, "%c: %d from $%d:", k, hop->id, hop->ir->id);
for (j=0; j<hop->ins.count; j++)
tracef(k, " <%%%d", hop->ins.item[j]->id);
for (j=0; j<hop->outs.count; j++)
tracef(k, " >%%%d", hop->outs.item[j]->id);
tracef(k, " ");
soi = false; soi = false;
} }

View file

@ -28,6 +28,9 @@ struct hop
struct ir* ir; struct ir* ir;
ARRAYOF(struct insel) insels; ARRAYOF(struct insel) insels;
struct vreg* output; struct vreg* output;
ARRAYOF(struct vreg) ins;
ARRAYOF(struct vreg) outs;
PMAPOF(struct vreg, struct hreg) registers; PMAPOF(struct vreg, struct hreg) registers;
}; };

View file

@ -109,6 +109,8 @@ extern void pass_promote_float_ops(struct procedure* proc);
extern void pass_remove_dead_blocks(struct procedure* proc); extern void pass_remove_dead_blocks(struct procedure* proc);
extern void pass_split_critical_edges(struct procedure* proc); extern void pass_split_critical_edges(struct procedure* proc);
extern void register_allocator(struct procedure* proc);
#endif #endif
/* vim: set sw=4 ts=4 expandtab : */ /* vim: set sw=4 ts=4 expandtab : */

View file

@ -37,15 +37,19 @@ static void emit_return_reg(void)
hop_add_vreg_insel(current_hop, current_hop->output); hop_add_vreg_insel(current_hop, current_hop->output);
} }
static void emit_reg(int child) static struct vreg* find_vreg_of_child(int child)
{ {
struct insn* insn = current_insn->children[child]; struct insn* insn = current_insn->children[child];
struct vreg* vreg;
if (insn->hop) if (insn->hop)
vreg = insn->hop->output; return insn->hop->output;
else else
vreg = insn->ir->result; return insn->ir->result;
}
static void emit_reg(int child)
{
struct vreg* vreg = find_vreg_of_child(child);
if (vreg) if (vreg)
hop_add_vreg_insel(current_hop, vreg); hop_add_vreg_insel(current_hop, vreg);
@ -71,6 +75,18 @@ static void emit_eoi(void)
hop_add_eoi_insel(current_hop); hop_add_eoi_insel(current_hop);
} }
static void constrain_input_reg(int child, int attr)
{
struct vreg* vreg = find_vreg_of_child(child);
if (vreg)
array_appendu(&current_hop->ins, vreg);
}
static void constrain_output_reg(int attr)
{
}
static const struct burm_emitter_data emitter_data = static const struct burm_emitter_data emitter_data =
{ {
&emit_string, &emit_string,
@ -79,6 +95,8 @@ static const struct burm_emitter_data emitter_data =
&emit_reg, &emit_reg,
&emit_value, &emit_value,
&emit_eoi, &emit_eoi,
&constrain_input_reg,
&constrain_output_reg
}; };
static void emit(struct insn* insn) static void emit(struct insn* insn)
@ -142,11 +160,16 @@ static struct insn* walk_instructions(struct burm_node* node, int goal)
break; break;
default: default:
/* FIXME: some instructions don't emit anything, so
* allocating a register for them is a waste of time. */
vreg = new_vreg(); vreg = new_vreg();
} }
insn->hop = current_hop = new_hop(0, insn->ir); insn->hop = current_hop = new_hop(0, insn->ir);
insn->hop->output = vreg; insn->hop->output = vreg;
if (vreg)
array_appendu(&current_hop->outs, vreg);
emit(insn); emit(insn);
hop_print('I', current_hop); hop_print('I', current_hop);

View file

@ -61,8 +61,9 @@ void procedure_compile(struct procedure* proc)
pass_promote_float_ops(proc); pass_promote_float_ops(proc);
print_blocks('6', proc); print_blocks('6', proc);
pass_instruction_selector(proc); pass_instruction_selector(proc);
register_allocator(proc);
} }
static bool collect_outputs_cb(struct ir* ir, void* user) static bool collect_outputs_cb(struct ir* ir, void* user)

View file

@ -1,2 +1,34 @@
#include "mcg.h"
static ARRAYOF(struct basicblock) blocks;
static void recursively_walk_blocks(struct basicblock* bb)
{
int i;
if (array_appendu(&blocks, bb))
return;
tracef('R', "R: considering block %s\n", bb->name);
for (i=0; i<bb->nexts.count; i++)
recursively_walk_blocks(bb->nexts.item[i]);
}
static void order_blocks(struct procedure* proc)
{
/* Put them into preorder; this ensures that when we do the allocation,
* we do all of a block's predecessors before the block (except for
* backward edges). */
blocks.count = 0;
recursively_walk_blocks(proc->blocks.item[0]);
assert(blocks.count == proc->blocks.count);
}
void register_allocator(struct procedure* proc)
{
order_blocks(proc);
}
/* vim: set sw=4 ts=4 expandtab : */ /* vim: set sw=4 ts=4 expandtab : */

View file

@ -29,7 +29,6 @@ REGISTERS
DECLARATIONS DECLARATIONS
reg;
cc; cc;
address fragment; address fragment;
@ -40,28 +39,24 @@ PATTERNS
/* Special */ /* Special */
reg;
PAIR(BLOCK4, BLOCK4); PAIR(BLOCK4, BLOCK4);
/* Miscellaneous special things */ /* Miscellaneous special things */
PUSH4(in:reg) PUSH4(in:(int)reg)
emit "push %in" emit "push %in"
cost 4; cost 4;
reg = POP4 out:(int)reg = POP4
with int reg emit "pop %out"
emit "pop %reg"
cost 4; cost 4;
RET RET
emit "ret" emit "ret"
cost 4; cost 4;
SETRET4(in:reg) SETRET4(in:(ret)reg)
with ret reg
emit "mov r0, %in" emit "mov r0, %in"
cost 4; cost 4;
@ -69,51 +64,38 @@ PATTERNS
emit "add sp, sp, %delta" emit "add sp, sp, %delta"
cost 4; cost 4;
reg = in:REG
cost 1;
reg = NOP(in:reg)
cost 1;
/* Memory operations */ /* Memory operations */
STORE4(addr:address, value:reg) STORE4(addr:address, value:(int)reg)
with int value
emit "str %value, %addr" emit "str %value, %addr"
cost 4; cost 4;
STORE1(addr:address, value:reg) STORE1(addr:address, value:(int)reg)
with int value
emit "strb %value, %addr" emit "strb %value, %addr"
cost 4; cost 4;
reg = LOAD4(addr:address) out:(int)reg = LOAD4(addr:address)
with int reg emit "ldr %out, %addr"
emit "ldr %reg, %addr"
cost 4; cost 4;
reg = LOAD1(addr:address) out:(int)reg = LOAD1(addr:address)
with int reg emit "ldrb %out, %addr"
emit "ldrb %reg, %addr"
cost 4; cost 4;
reg = CIU14(LOAD1(addr:address)) out:(int)reg = CIU14(LOAD1(addr:address))
with int reg emit "ldrb %out, %addr"
emit "ldrb %reg, %addr"
cost 4; cost 4;
reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) out:(int)reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
with int reg emit "ldrsb %out, %addr"
emit "ldrsb %reg, %addr"
cost 4; cost 4;
/* Locals */ /* Locals */
reg = in:LOCAL4 out:(int)reg = in:LOCAL4
with int reg emit "add %out, fp, #$in"
emit "add %reg, fp, #$in"
cost 4; cost 4;
address = in:LOCAL4 address = in:LOCAL4
@ -122,16 +104,13 @@ PATTERNS
/* Memory addressing modes */ /* Memory addressing modes */
address = ADD4(addr:reg, offset:CONST4) address = ADD4(addr:(int)reg, offset:CONST4)
with int addr
emit "[%addr, #$offset]"; emit "[%addr, #$offset]";
address = ADD4(addr1:reg, addr2:reg) address = ADD4(addr1:(int)reg, addr2:(int)reg)
with int addr1, int addr2
emit "[%addr1, %addr2]"; emit "[%addr1, %addr2]";
address = addr:reg address = addr:(int)reg
with int addr
emit "[%addr]"; emit "[%addr]";
@ -142,17 +121,17 @@ PATTERNS
emit "b $addr" emit "b $addr"
cost 4; cost 4;
CJUMPEQ(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) CJUMPEQ(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
emit "beq $true" emit "beq $true"
emit "b $false" emit "b $false"
cost 8; cost 8;
CJUMPLE(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) CJUMPLE(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
emit "ble $true" emit "ble $true"
emit "b $false" emit "b $false"
cost 8; cost 8;
CJUMPLT(value:cc, PAIR(true:BLOCK4, false:BLOCK4)) CJUMPLT(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
emit "blt $true" emit "blt $true"
emit "b $false" emit "b $false"
cost 8; cost 8;
@ -164,96 +143,81 @@ PATTERNS
/* Comparisons */ /* Comparisons */
cc = COMPARES4(left:reg, right:aluparam) (cc)cc = COMPARES4(left:(int)reg, right:aluparam)
with cc cc
emit "cmp %left, %right" emit "cmp %left, %right"
cost 4; cost 4;
cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4) (cc)cc = COMPARES4(COMPARES4(left:(int)reg, right:aluparam), CONST4)
with cc cc
emit "cmp %left, %right" emit "cmp %left, %right"
cost 4; cost 4;
reg = cc out:(int)reg = (cc)cc
with int reg emit "mov %out, #0"
emit "mov %reg, #0" emit "movlt %out, #-1"
emit "movlt %reg, #-1" emit "movgt %out, #1"
emit "movgt %reg, #1"
cost 12; cost 12;
/* Conversions */ /* Conversions */
reg = CII14(CIU41(value:reg)) out:(int)reg = CII14(CIU41(value:(int)reg))
with int reg emit "sxtb %out, %value"
emit "sxtb %reg, %value"
cost 4; cost 4;
reg = CIU41(in:reg) out:(int)reg = CIU41(in:(int)reg)
with int reg emit "and %out, %in, #0xff"
emit "and %reg, %in, #0xff"
cost 4; cost 4;
/* ALU operations */ /* ALU operations */
reg = ADD4(left:reg, right:aluparam) out:(int)reg = ADD4(left:(int)reg, right:aluparam)
with int reg emit "add %out, %left, %right"
emit "add %reg, %left, %right"
cost 4; cost 4;
reg = ADD4(left:aluparam, right:reg) out:(int)reg = ADD4(left:aluparam, right:(int)reg)
with int reg emit "add %out, %right, %left"
emit "add %reg, %right, %left"
cost 4; cost 4;
reg = MOD4(left:reg, right:reg) out:(int)reg = MOD4(left:(int)reg, right:(int)reg)
with int reg emit "udiv %out, %left, %right"
emit "udiv %reg, %left, %right" emit "mls %out, %out, %right, %left"
emit "mls %reg, %reg, %right, %left"
cost 8; cost 8;
reg = DIV4(left:reg, right:aluparam) out:(int)reg = DIV4(left:(int)reg, right:aluparam)
with int reg emit "div %out, %left, %right"
emit "div %reg, %left, %right"
cost 4; cost 4;
aluparam = value:CONST4 aluparam = value:CONST4
emit "#$value"; emit "#$value";
aluparam = value:reg aluparam = value:(int)reg
emit "%value"; emit "%value";
reg = value:aluparam out:(int)reg = value:aluparam
with int reg emit "mov %out, %value"
emit "mov %reg, %value"
cost 4; cost 4;
reg = value:LABEL4 out:(int)reg = value:LABEL4
with int reg emit "adr %out, $value"
emit "adr %reg, $value"
cost 4; cost 4;
reg = value:BLOCK4 out:(int)reg = value:BLOCK4
with int reg emit "adr %out, $value"
emit "adr %reg, $value"
cost 4; cost 4;
reg = value:CONST4 out:(int)reg = value:CONST4
with int reg emit "ldr %out, address-containing-$value"
emit "ldr %reg, address-containing-$value"
cost 8; cost 8;
reg = value:CONSTF4 out:(int)reg = value:CONSTF4
with int reg emit "vldr %out, address-containing-$value"
emit "vldr %reg, address-containing-$value"
cost 8; cost 8;
/* FPU operations */ /* FPU operations */
reg = ADDF4(left:reg, right:reg) out:(float)reg = ADDF4(left:(float)reg, right:(float)reg)
with int reg emit "fadds %out, %left, %right"
emit "fadds %reg, %left, %right"
cost 4; cost 4;
/* vim: set sw=4 ts=4 expandtab : */ /* vim: set sw=4 ts=4 expandtab : */

View file

@ -11,8 +11,6 @@
extern int yylex(void); extern int yylex(void);
static int nextern = 1;
%} %}
%union { %union {
int n; int n;
@ -86,17 +84,6 @@ declarations
declaration declaration
: ID { $$ = nonterm($1, true); } : ID { $$ = nonterm($1, true); }
| declaration FRAGMENT { $$ = $1; $$->is_fragment = 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 = getregattr($4);
}
; ;
patterns patterns
@ -106,8 +93,8 @@ patterns
; ;
pattern pattern
: ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); } : terminfo '=' rhs { nonterm($1.name, false); $$ = rule(&$1, $3); }
| rhs { $$ = rule("stmt", $1, nextern++); } | rhs { $$ = rule(NULL, $1); }
| pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); } | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); }
| pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); } | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); }
| pattern COST INT { $$ = $1; $$->cost = $3; } | pattern COST INT { $$ = $1; $$->cost = $3; }
@ -123,7 +110,9 @@ rhs
terminfo terminfo
: ID { $$.name = $1; } : ID { $$.name = $1; }
| '(' ID ')' ID { $$.attr = $2; $$.name = $4; }
| ID ':' ID { $$.label = $1; $$.name = $3; } | ID ':' ID { $$.label = $1; $$.name = $3; }
| ID ':' '(' ID ')' ID { $$.label = $1; $$.attr = $4; $$.name = $6; }
; ;
pattern_emit pattern_emit

View file

@ -14,6 +14,7 @@
#include "ircodes.h" #include "ircodes.h"
#include "astring.h" #include "astring.h"
#include "smap.h" #include "smap.h"
#include "mcgg.h"
static char rcsid[] = "$Id$"; static char rcsid[] = "$Id$";
@ -131,6 +132,20 @@ int main(int argc, char* argv[])
makeregattr("bytes4"); makeregattr("bytes4");
makeregattr("bytes8"); makeregattr("bytes8");
/* Define some standard terms. */
{
const static struct terminfo reg = { "reg", NULL, "" };
const static struct terminfo REG = { "REG", NULL, NULL };
const static struct terminfo NOP = { "NOP", NULL, NULL };
nonterm("reg", true);
rule(NULL, tree(&reg, NULL, NULL))->cost = 1;
rule(&reg, tree(&REG, NULL, NULL))->cost = 1;
rule(&reg, tree(&NOP, tree(&reg, NULL, NULL), NULL))->cost = 1;
}
yyin = infp; yyin = infp;
yyparse(); yyparse();
@ -336,7 +351,7 @@ Term term(const char* id, int esn)
} }
/* tree - create & initialize a tree node with the given fields */ /* tree - create & initialize a tree node with the given fields */
Tree tree(struct terminfo* ti, Tree left, Tree right) Tree tree(const struct terminfo* ti, Tree left, Tree right)
{ {
Tree t = calloc(1, sizeof *t); Tree t = calloc(1, sizeof *t);
Term p = lookup(ti->name); Term p = lookup(ti->name);
@ -363,31 +378,57 @@ Tree tree(struct terminfo* ti, Tree left, Tree right)
if (p->kind == TERM && arity != p->arity) if (p->kind == TERM && arity != p->arity)
yyerror("inconsistent arity for terminal `%s'\n", ti->name); yyerror("inconsistent arity for terminal `%s'\n", ti->name);
t->op = p; t->op = p;
t->label = ti->label;
t->nterms = p->kind == TERM; t->nterms = p->kind == TERM;
if (t->left = left) if (t->left = left)
t->nterms += left->nterms; t->nterms += left->nterms;
if (t->right = right) if (t->right = right)
t->nterms += right->nterms; t->nterms += right->nterms;
/* Special rules that have no output register attribute use "" as the
* attribute name; these can't be made by the grammar. */
t->label = ti->label;
if ((p->kind == TERM) && (ti->attr))
yyerror("can't specify an input register attribute for terminal '%s'", ti->name);
if (p->kind == NONTERM)
{
Nonterm nt = (Nonterm)p;
if (nt->is_fragment && ti->attr)
yyerror("can't specify an input register attribute for fragment '%s'", ti->name);
if (!nt->is_fragment && !ti->attr)
yyerror("must specify an input register attribute for non-fragment '%s'", ti->name);
if (ti->attr && ti->attr[0])
{
nt->attr = smap_get(&registerattrs, ti->attr);
if (!nt->attr)
yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
}
}
return t; return t;
} }
/* rule - create & initialize a rule with the given fields */ /* rule - create & initialize a rule with the given fields */
Rule rule(char* id, Tree pattern, int ern) Rule rule(const struct terminfo* ti, Tree pattern)
{ {
static int number = 1;
static const struct terminfo stmt = { "stmt", NULL, NULL };
Rule r = calloc(1, sizeof *r); Rule r = calloc(1, sizeof *r);
Rule *q; Rule *q;
Term p = pattern->op; Term p = pattern->op;
if (!ti)
ti = &stmt;
nrules++; nrules++;
r->lineno = yylineno; r->lineno = yylineno;
r->lhs = nonterm(id, false); r->lhs = nonterm(ti->name, 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)
; ;
*q = r; *q = r;
r->pattern = pattern; r->pattern = pattern;
r->ern = ern; r->ern = number++;
if (p->kind == TERM) if (p->kind == TERM)
{ {
r->next = p->rules; r->next = p->rules;
@ -405,6 +446,23 @@ Rule rule(char* id, Tree pattern, int ern)
yyerror("duplicate external rule number `%d'\n", r->ern); yyerror("duplicate external rule number `%d'\n", r->ern);
r->link = *q; r->link = *q;
*q = r; *q = r;
r->label = ti->label;
if (r->lhs->is_fragment && ti->attr)
yyerror("can't specify an output register attribute for a fragment");
if (!r->lhs->is_fragment && !ti->attr && (r->lhs->number != NONTERM_STMT))
yyerror("must specify an output register attribute for non-fragments");
/* Special rules that have no output register attribute use "" as the
* attribute name; these can't be made by the grammar. */
if (ti->attr && ti->attr[0])
{
r->attr = smap_get(&registerattrs, ti->attr);
if (!r->attr)
yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
}
return r; return r;
} }
@ -986,6 +1044,28 @@ static void emitpredicatedefinitions(Rule r)
} }
} }
static void emit_input_regs(Tree node, int* index)
{
/* This must return the same ordering as the burm_kids() function uses. */
Nonterm nt = node->op;
if ((nt->kind == NONTERM) && !nt->is_fragment && !node->left && !node->right)
{
uint32_t attr = 0;
if (nt->attr->number)
attr = 1<<nt->attr->number;
print("%1data->constrain_input_reg(%d, 0x%x);\n", *index, attr);
}
if (!node->left && !node->right)
(*index)++;
if (node->left)
emit_input_regs(node->left, index);
if (node->right)
emit_input_regs(node->right, index);
}
/* emitinsndata - emit the code generation data */ /* emitinsndata - emit the code generation data */
static void emitinsndata(Rule rules) static void emitinsndata(Rule rules)
{ {
@ -1011,6 +1091,14 @@ static void emitinsndata(Rule rules)
print("/* %R */\n", r); print("/* %R */\n", r);
print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern); print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern);
if (r->attr)
print("%1data->constrain_output_reg(0x%x);\n", 1<<r->attr->number);
{
int index = 0;
emit_input_regs(r->pattern, &index);
}
while (f) while (f)
{ {
switch (f->data[0]) switch (f->data[0])
@ -1019,7 +1107,7 @@ static void emitinsndata(Rule rules)
{ {
const char* label = f->data + 1; const char* label = f->data + 1;
if (strcmp(label, r->lhs->name) == 0) if (r->label && (strcmp(label, r->label) == 0))
print("%1data->emit_return_reg();\n", label); print("%1data->emit_return_reg();\n", label);
else else
{ {
@ -1086,11 +1174,6 @@ static void emitinsndata(Rule rules)
print("%2&%Pemitter_%d,\n", r->ern); print("%2&%Pemitter_%d,\n", r->ern);
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("%2%s,\n", r->lhs->is_fragment ? "true" : "false");
print("%1},\n"); print("%1},\n");

View file

@ -41,6 +41,7 @@ struct terminfo
{ {
const char* name; const char* name;
const char* label; const char* label;
const char* attr;
}; };
struct reg struct reg
@ -82,7 +83,7 @@ struct nonterm
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 */ bool is_fragment; /* these instructions are all fragments */
struct regattr* allocate; /* allocate this kind of register */ struct regattr* attr; /* input register attribute */
}; };
extern void* lookup(const char* name); extern void* lookup(const char* name);
extern Nonterm nonterm(const char* id, bool allocate); extern Nonterm nonterm(const char* id, bool allocate);
@ -96,7 +97,7 @@ struct tree
Tree left, right; /* operands */ Tree left, right; /* operands */
int nterms; /* number of terminal nodes in this tree */ int nterms; /* number of terminal nodes in this tree */
}; };
extern Tree tree(struct terminfo* ti, Tree left, Tree right); extern Tree tree(const struct terminfo* ti, Tree left, Tree right);
struct rule struct rule
{ /* rules: */ { /* rules: */
@ -106,6 +107,8 @@ struct rule
int ern; /* external rule number */ int ern; /* external rule number */
int packed; /* packed external rule number */ int packed; /* packed external rule number */
int cost; /* associated cost */ int cost; /* associated cost */
const char* label; /* label for LHS */
struct regattr* attr; /* register attribute of result */
Rule link; /* next rule in ern order */ Rule link; /* next rule in ern order */
Rule next; /* next rule with same pattern root */ Rule next; /* next rule with same pattern root */
Rule chain; /* next chain rule with same rhs */ Rule chain; /* next chain rule with same rhs */
@ -116,7 +119,7 @@ struct rule
ARRAYOF(struct constraint) constraints; /* register constraints */ ARRAYOF(struct constraint) constraints; /* register constraints */
struct stringlist code; /* compiler output code strings */ struct stringlist code; /* compiler output code strings */
}; };
extern Rule rule(char* id, Tree pattern, int ern); extern Rule rule(const struct terminfo* ti, Tree pattern);
extern int maxcost; /* maximum cost */ extern int maxcost; /* maximum cost */
/* gram.y: */ /* gram.y: */

View file

@ -44,6 +44,8 @@ struct burm_emitter_data
void (*emit_reg)(int child); void (*emit_reg)(int child);
void (*emit_value)(int child); void (*emit_value)(int child);
void (*emit_eoi)(void); void (*emit_eoi)(void);
void (*constrain_input_reg)(int child, int attr);
void (*constrain_output_reg)(int attr);
}; };
typedef void burm_emitter_t(const struct burm_emitter_data* data); typedef void burm_emitter_t(const struct burm_emitter_data* data);
@ -52,7 +54,6 @@ 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;
}; };
@ -75,6 +76,11 @@ enum
REGATTR_BYTES8 REGATTR_BYTES8
}; };
enum
{
NONTERM_STMT = 1
};
#endif #endif
/* vim: set sw=4 ts=4 expandtab : */ /* vim: set sw=4 ts=4 expandtab : */