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:
parent
7a6fc7a72b
commit
88fb231d6e
|
@ -50,7 +50,7 @@ void hop_add_eoi_insel(struct hop* hop)
|
|||
|
||||
void hop_print(char k, struct hop* hop)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
bool soi = true;
|
||||
|
||||
i = 0;
|
||||
|
@ -61,6 +61,13 @@ void hop_print(char k, struct hop* hop)
|
|||
if (soi)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ struct hop
|
|||
struct ir* ir;
|
||||
ARRAYOF(struct insel) insels;
|
||||
struct vreg* output;
|
||||
|
||||
ARRAYOF(struct vreg) ins;
|
||||
ARRAYOF(struct vreg) outs;
|
||||
PMAPOF(struct vreg, struct hreg) registers;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_split_critical_edges(struct procedure* proc);
|
||||
|
||||
extern void register_allocator(struct procedure* proc);
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -37,15 +37,19 @@ static void emit_return_reg(void)
|
|||
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 vreg* vreg;
|
||||
|
||||
if (insn->hop)
|
||||
vreg = insn->hop->output;
|
||||
return insn->hop->output;
|
||||
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)
|
||||
hop_add_vreg_insel(current_hop, vreg);
|
||||
|
@ -71,6 +75,18 @@ static void emit_eoi(void)
|
|||
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(¤t_hop->ins, vreg);
|
||||
}
|
||||
|
||||
static void constrain_output_reg(int attr)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct burm_emitter_data emitter_data =
|
||||
{
|
||||
&emit_string,
|
||||
|
@ -79,6 +95,8 @@ static const struct burm_emitter_data emitter_data =
|
|||
&emit_reg,
|
||||
&emit_value,
|
||||
&emit_eoi,
|
||||
&constrain_input_reg,
|
||||
&constrain_output_reg
|
||||
};
|
||||
|
||||
static void emit(struct insn* insn)
|
||||
|
@ -142,11 +160,16 @@ static struct insn* walk_instructions(struct burm_node* node, int goal)
|
|||
break;
|
||||
|
||||
default:
|
||||
/* FIXME: some instructions don't emit anything, so
|
||||
* allocating a register for them is a waste of time. */
|
||||
vreg = new_vreg();
|
||||
}
|
||||
|
||||
insn->hop = current_hop = new_hop(0, insn->ir);
|
||||
insn->hop->output = vreg;
|
||||
if (vreg)
|
||||
array_appendu(¤t_hop->outs, vreg);
|
||||
|
||||
emit(insn);
|
||||
hop_print('I', current_hop);
|
||||
|
||||
|
|
|
@ -61,8 +61,9 @@ void procedure_compile(struct procedure* proc)
|
|||
pass_promote_float_ops(proc);
|
||||
print_blocks('6', proc);
|
||||
|
||||
|
||||
pass_instruction_selector(proc);
|
||||
|
||||
register_allocator(proc);
|
||||
}
|
||||
|
||||
static bool collect_outputs_cb(struct ir* ir, void* user)
|
||||
|
|
|
@ -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 : */
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ REGISTERS
|
|||
|
||||
DECLARATIONS
|
||||
|
||||
reg;
|
||||
cc;
|
||||
|
||||
address fragment;
|
||||
|
@ -40,28 +39,24 @@ PATTERNS
|
|||
|
||||
/* Special */
|
||||
|
||||
reg;
|
||||
|
||||
PAIR(BLOCK4, BLOCK4);
|
||||
|
||||
|
||||
/* Miscellaneous special things */
|
||||
|
||||
PUSH4(in:reg)
|
||||
PUSH4(in:(int)reg)
|
||||
emit "push %in"
|
||||
cost 4;
|
||||
|
||||
reg = POP4
|
||||
with int reg
|
||||
emit "pop %reg"
|
||||
out:(int)reg = POP4
|
||||
emit "pop %out"
|
||||
cost 4;
|
||||
|
||||
RET
|
||||
emit "ret"
|
||||
cost 4;
|
||||
|
||||
SETRET4(in:reg)
|
||||
with ret reg
|
||||
SETRET4(in:(ret)reg)
|
||||
emit "mov r0, %in"
|
||||
cost 4;
|
||||
|
||||
|
@ -69,51 +64,38 @@ PATTERNS
|
|||
emit "add sp, sp, %delta"
|
||||
cost 4;
|
||||
|
||||
reg = in:REG
|
||||
cost 1;
|
||||
|
||||
reg = NOP(in:reg)
|
||||
cost 1;
|
||||
|
||||
|
||||
/* Memory operations */
|
||||
|
||||
STORE4(addr:address, value:reg)
|
||||
with int value
|
||||
STORE4(addr:address, value:(int)reg)
|
||||
emit "str %value, %addr"
|
||||
cost 4;
|
||||
|
||||
STORE1(addr:address, value:reg)
|
||||
with int value
|
||||
STORE1(addr:address, value:(int)reg)
|
||||
emit "strb %value, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = LOAD4(addr:address)
|
||||
with int reg
|
||||
emit "ldr %reg, %addr"
|
||||
out:(int)reg = LOAD4(addr:address)
|
||||
emit "ldr %out, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = LOAD1(addr:address)
|
||||
with int reg
|
||||
emit "ldrb %reg, %addr"
|
||||
out:(int)reg = LOAD1(addr:address)
|
||||
emit "ldrb %out, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = CIU14(LOAD1(addr:address))
|
||||
with int reg
|
||||
emit "ldrb %reg, %addr"
|
||||
out:(int)reg = CIU14(LOAD1(addr:address))
|
||||
emit "ldrb %out, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
|
||||
with int reg
|
||||
emit "ldrsb %reg, %addr"
|
||||
out:(int)reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
|
||||
emit "ldrsb %out, %addr"
|
||||
cost 4;
|
||||
|
||||
|
||||
/* Locals */
|
||||
|
||||
reg = in:LOCAL4
|
||||
with int reg
|
||||
emit "add %reg, fp, #$in"
|
||||
out:(int)reg = in:LOCAL4
|
||||
emit "add %out, fp, #$in"
|
||||
cost 4;
|
||||
|
||||
address = in:LOCAL4
|
||||
|
@ -122,16 +104,13 @@ PATTERNS
|
|||
|
||||
/* Memory addressing modes */
|
||||
|
||||
address = ADD4(addr:reg, offset:CONST4)
|
||||
with int addr
|
||||
address = ADD4(addr:(int)reg, offset:CONST4)
|
||||
emit "[%addr, #$offset]";
|
||||
|
||||
address = ADD4(addr1:reg, addr2:reg)
|
||||
with int addr1, int addr2
|
||||
address = ADD4(addr1:(int)reg, addr2:(int)reg)
|
||||
emit "[%addr1, %addr2]";
|
||||
|
||||
address = addr:reg
|
||||
with int addr
|
||||
address = addr:(int)reg
|
||||
emit "[%addr]";
|
||||
|
||||
|
||||
|
@ -142,17 +121,17 @@ PATTERNS
|
|||
emit "b $addr"
|
||||
cost 4;
|
||||
|
||||
CJUMPEQ(value:cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
CJUMPEQ(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
emit "beq $true"
|
||||
emit "b $false"
|
||||
cost 8;
|
||||
|
||||
CJUMPLE(value:cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
CJUMPLE(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
emit "ble $true"
|
||||
emit "b $false"
|
||||
cost 8;
|
||||
|
||||
CJUMPLT(value:cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
CJUMPLT(value:(cc)cc, PAIR(true:BLOCK4, false:BLOCK4))
|
||||
emit "blt $true"
|
||||
emit "b $false"
|
||||
cost 8;
|
||||
|
@ -164,96 +143,81 @@ PATTERNS
|
|||
|
||||
/* Comparisons */
|
||||
|
||||
cc = COMPARES4(left:reg, right:aluparam)
|
||||
with cc cc
|
||||
(cc)cc = COMPARES4(left:(int)reg, right:aluparam)
|
||||
emit "cmp %left, %right"
|
||||
cost 4;
|
||||
|
||||
cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4)
|
||||
with cc cc
|
||||
(cc)cc = COMPARES4(COMPARES4(left:(int)reg, right:aluparam), CONST4)
|
||||
emit "cmp %left, %right"
|
||||
cost 4;
|
||||
|
||||
reg = cc
|
||||
with int reg
|
||||
emit "mov %reg, #0"
|
||||
emit "movlt %reg, #-1"
|
||||
emit "movgt %reg, #1"
|
||||
out:(int)reg = (cc)cc
|
||||
emit "mov %out, #0"
|
||||
emit "movlt %out, #-1"
|
||||
emit "movgt %out, #1"
|
||||
cost 12;
|
||||
|
||||
|
||||
/* Conversions */
|
||||
|
||||
reg = CII14(CIU41(value:reg))
|
||||
with int reg
|
||||
emit "sxtb %reg, %value"
|
||||
out:(int)reg = CII14(CIU41(value:(int)reg))
|
||||
emit "sxtb %out, %value"
|
||||
cost 4;
|
||||
|
||||
reg = CIU41(in:reg)
|
||||
with int reg
|
||||
emit "and %reg, %in, #0xff"
|
||||
out:(int)reg = CIU41(in:(int)reg)
|
||||
emit "and %out, %in, #0xff"
|
||||
cost 4;
|
||||
|
||||
|
||||
/* ALU operations */
|
||||
|
||||
reg = ADD4(left:reg, right:aluparam)
|
||||
with int reg
|
||||
emit "add %reg, %left, %right"
|
||||
out:(int)reg = ADD4(left:(int)reg, right:aluparam)
|
||||
emit "add %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
reg = ADD4(left:aluparam, right:reg)
|
||||
with int reg
|
||||
emit "add %reg, %right, %left"
|
||||
out:(int)reg = ADD4(left:aluparam, right:(int)reg)
|
||||
emit "add %out, %right, %left"
|
||||
cost 4;
|
||||
|
||||
reg = MOD4(left:reg, right:reg)
|
||||
with int reg
|
||||
emit "udiv %reg, %left, %right"
|
||||
emit "mls %reg, %reg, %right, %left"
|
||||
out:(int)reg = MOD4(left:(int)reg, right:(int)reg)
|
||||
emit "udiv %out, %left, %right"
|
||||
emit "mls %out, %out, %right, %left"
|
||||
cost 8;
|
||||
|
||||
reg = DIV4(left:reg, right:aluparam)
|
||||
with int reg
|
||||
emit "div %reg, %left, %right"
|
||||
out:(int)reg = DIV4(left:(int)reg, right:aluparam)
|
||||
emit "div %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
aluparam = value:CONST4
|
||||
emit "#$value";
|
||||
|
||||
aluparam = value:reg
|
||||
aluparam = value:(int)reg
|
||||
emit "%value";
|
||||
|
||||
reg = value:aluparam
|
||||
with int reg
|
||||
emit "mov %reg, %value"
|
||||
out:(int)reg = value:aluparam
|
||||
emit "mov %out, %value"
|
||||
cost 4;
|
||||
|
||||
reg = value:LABEL4
|
||||
with int reg
|
||||
emit "adr %reg, $value"
|
||||
out:(int)reg = value:LABEL4
|
||||
emit "adr %out, $value"
|
||||
cost 4;
|
||||
|
||||
reg = value:BLOCK4
|
||||
with int reg
|
||||
emit "adr %reg, $value"
|
||||
out:(int)reg = value:BLOCK4
|
||||
emit "adr %out, $value"
|
||||
cost 4;
|
||||
|
||||
reg = value:CONST4
|
||||
with int reg
|
||||
emit "ldr %reg, address-containing-$value"
|
||||
out:(int)reg = value:CONST4
|
||||
emit "ldr %out, address-containing-$value"
|
||||
cost 8;
|
||||
|
||||
reg = value:CONSTF4
|
||||
with int reg
|
||||
emit "vldr %reg, address-containing-$value"
|
||||
out:(int)reg = value:CONSTF4
|
||||
emit "vldr %out, address-containing-$value"
|
||||
cost 8;
|
||||
|
||||
/* FPU operations */
|
||||
|
||||
reg = ADDF4(left:reg, right:reg)
|
||||
with int reg
|
||||
emit "fadds %reg, %left, %right"
|
||||
out:(float)reg = ADDF4(left:(float)reg, right:(float)reg)
|
||||
emit "fadds %out, %left, %right"
|
||||
cost 4;
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
extern int yylex(void);
|
||||
|
||||
static int nextern = 1;
|
||||
|
||||
%}
|
||||
%union {
|
||||
int n;
|
||||
|
@ -86,17 +84,6 @@ declarations
|
|||
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 = getregattr($4);
|
||||
}
|
||||
;
|
||||
|
||||
patterns
|
||||
|
@ -106,8 +93,8 @@ patterns
|
|||
;
|
||||
|
||||
pattern
|
||||
: ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); }
|
||||
| rhs { $$ = rule("stmt", $1, nextern++); }
|
||||
: terminfo '=' rhs { nonterm($1.name, false); $$ = rule(&$1, $3); }
|
||||
| rhs { $$ = rule(NULL, $1); }
|
||||
| pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); }
|
||||
| pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); }
|
||||
| pattern COST INT { $$ = $1; $$->cost = $3; }
|
||||
|
@ -123,7 +110,9 @@ rhs
|
|||
|
||||
terminfo
|
||||
: ID { $$.name = $1; }
|
||||
| '(' ID ')' ID { $$.attr = $2; $$.name = $4; }
|
||||
| ID ':' ID { $$.label = $1; $$.name = $3; }
|
||||
| ID ':' '(' ID ')' ID { $$.label = $1; $$.attr = $4; $$.name = $6; }
|
||||
;
|
||||
|
||||
pattern_emit
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "ircodes.h"
|
||||
#include "astring.h"
|
||||
#include "smap.h"
|
||||
#include "mcgg.h"
|
||||
|
||||
static char rcsid[] = "$Id$";
|
||||
|
||||
|
@ -131,6 +132,20 @@ int main(int argc, char* argv[])
|
|||
makeregattr("bytes4");
|
||||
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(®, NULL, NULL))->cost = 1;
|
||||
rule(®, tree(®, NULL, NULL))->cost = 1;
|
||||
rule(®, tree(&NOP, tree(®, NULL, NULL), NULL))->cost = 1;
|
||||
}
|
||||
|
||||
yyin = infp;
|
||||
yyparse();
|
||||
|
||||
|
@ -336,7 +351,7 @@ Term term(const char* id, int esn)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
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)
|
||||
yyerror("inconsistent arity for terminal `%s'\n", ti->name);
|
||||
t->op = p;
|
||||
t->label = ti->label;
|
||||
t->nterms = p->kind == TERM;
|
||||
if (t->left = left)
|
||||
t->nterms += left->nterms;
|
||||
if (t->right = right)
|
||||
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(®isterattrs, ti->attr);
|
||||
if (!nt->attr)
|
||||
yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* 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 *q;
|
||||
Term p = pattern->op;
|
||||
|
||||
if (!ti)
|
||||
ti = &stmt;
|
||||
|
||||
nrules++;
|
||||
r->lineno = yylineno;
|
||||
r->lhs = nonterm(id, false);
|
||||
r->lhs = nonterm(ti->name, false);
|
||||
r->packed = ++r->lhs->lhscount;
|
||||
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
|
||||
;
|
||||
*q = r;
|
||||
r->pattern = pattern;
|
||||
r->ern = ern;
|
||||
r->ern = number++;
|
||||
if (p->kind == TERM)
|
||||
{
|
||||
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);
|
||||
r->link = *q;
|
||||
*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(®isterattrs, ti->attr);
|
||||
if (!r->attr)
|
||||
yyerror("'%s' doesn't seem to be a known register attribute", ti->attr);
|
||||
}
|
||||
|
||||
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 */
|
||||
static void emitinsndata(Rule rules)
|
||||
{
|
||||
|
@ -1011,6 +1091,14 @@ static void emitinsndata(Rule rules)
|
|||
print("/* %R */\n", r);
|
||||
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)
|
||||
{
|
||||
switch (f->data[0])
|
||||
|
@ -1019,7 +1107,7 @@ static void emitinsndata(Rule rules)
|
|||
{
|
||||
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);
|
||||
else
|
||||
{
|
||||
|
@ -1086,11 +1174,6 @@ static void emitinsndata(Rule rules)
|
|||
|
||||
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("%1},\n");
|
||||
|
|
|
@ -41,6 +41,7 @@ struct terminfo
|
|||
{
|
||||
const char* name;
|
||||
const char* label;
|
||||
const char* attr;
|
||||
};
|
||||
|
||||
struct reg
|
||||
|
@ -82,7 +83,7 @@ struct nonterm
|
|||
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 regattr* allocate; /* allocate this kind of register */
|
||||
struct regattr* attr; /* input register attribute */
|
||||
};
|
||||
extern void* lookup(const char* name);
|
||||
extern Nonterm nonterm(const char* id, bool allocate);
|
||||
|
@ -96,7 +97,7 @@ struct tree
|
|||
Tree left, right; /* operands */
|
||||
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
|
||||
{ /* rules: */
|
||||
|
@ -106,6 +107,8 @@ struct rule
|
|||
int ern; /* external rule number */
|
||||
int packed; /* packed external rule number */
|
||||
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 next; /* next rule with same pattern root */
|
||||
Rule chain; /* next chain rule with same rhs */
|
||||
|
@ -116,7 +119,7 @@ struct rule
|
|||
ARRAYOF(struct constraint) constraints; /* register constraints */
|
||||
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 */
|
||||
|
||||
/* gram.y: */
|
||||
|
|
|
@ -44,6 +44,8 @@ struct burm_emitter_data
|
|||
void (*emit_reg)(int child);
|
||||
void (*emit_value)(int child);
|
||||
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);
|
||||
|
@ -52,7 +54,6 @@ struct burm_instruction_data
|
|||
{
|
||||
const char* name;
|
||||
burm_emitter_t* emitter;
|
||||
int allocate;
|
||||
bool is_fragment;
|
||||
};
|
||||
|
||||
|
@ -75,6 +76,11 @@ enum
|
|||
REGATTR_BYTES8
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
NONTERM_STMT = 1
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
Loading…
Reference in a new issue