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)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 : */
|
||||||
|
|
|
@ -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(¤t_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(¤t_hop->outs, vreg);
|
||||||
|
|
||||||
emit(insn);
|
emit(insn);
|
||||||
hop_print('I', current_hop);
|
hop_print('I', current_hop);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 : */
|
||||||
|
|
||||||
|
|
|
@ -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 : */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(®, NULL, NULL))->cost = 1;
|
||||||
|
rule(®, tree(®, NULL, NULL))->cost = 1;
|
||||||
|
rule(®, tree(&NOP, tree(®, 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(®isterattrs, 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(®isterattrs, 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");
|
||||||
|
|
|
@ -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: */
|
||||||
|
|
|
@ -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 : */
|
||||||
|
|
Loading…
Reference in a new issue