Massive rewrite of how emitters and the instruction selector works, after I
realised that the existing approach wasn't working. Now, hopefully, tracks the instruction trees generated during selection properly.
This commit is contained in:
parent
68f98cbad7
commit
bd28bddb92
|
@ -20,6 +20,7 @@ struct ir
|
|||
ARRAYOF(struct ir) phivalue;
|
||||
} u;
|
||||
|
||||
struct vreg* result; /* vreg containing IR result */
|
||||
IMAPOF(struct hop) hops; /* only for root IRs; by goal */
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
#include "mcg.h"
|
||||
|
||||
#define MAX_CHILDREN 10
|
||||
|
||||
struct insn
|
||||
{
|
||||
struct ir* ir;
|
||||
struct hop* hop;
|
||||
const struct burm_instruction_data* insndata;
|
||||
int num_children;
|
||||
struct insn* children[MAX_CHILDREN];
|
||||
};
|
||||
|
||||
static struct basicblock* current_bb;
|
||||
static struct hop* current_hop;
|
||||
static struct ir* current_ir;
|
||||
static struct insn* current_insn;
|
||||
|
||||
static const struct burm_emitter_data emitter_data;
|
||||
static void emit(struct insn* insn);
|
||||
|
||||
void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) {
|
||||
const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
|
||||
|
@ -20,11 +32,23 @@ void burm_panic_cannot_match(struct burm_node* node)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static void emit_reg(struct burm_node* node, int goal)
|
||||
static void emit_return_reg(void)
|
||||
{
|
||||
struct hop* hop = imap_get(¤t_ir->hops, goal);
|
||||
hop_add_vreg_insel(current_hop, current_hop->output);
|
||||
}
|
||||
|
||||
hop_add_vreg_insel(current_hop, hop->output);
|
||||
static void emit_reg(int child)
|
||||
{
|
||||
struct insn* insn = current_insn->children[child];
|
||||
struct vreg* vreg;
|
||||
|
||||
if (insn->hop)
|
||||
vreg = insn->hop->output;
|
||||
else
|
||||
vreg = insn->ir->result;
|
||||
|
||||
if (vreg)
|
||||
hop_add_vreg_insel(current_hop, vreg);
|
||||
}
|
||||
|
||||
static void emit_string(const char* data)
|
||||
|
@ -32,17 +56,14 @@ static void emit_string(const char* data)
|
|||
hop_add_string_insel(current_hop, data);
|
||||
}
|
||||
|
||||
static void emit_fragment(struct burm_node* node, int goal)
|
||||
static void emit_fragment(int child)
|
||||
{
|
||||
int insn_no = burm_rule(node->state_label, goal);
|
||||
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
|
||||
if (insndata->emitter)
|
||||
insndata->emitter(node, &emitter_data);
|
||||
emit(current_insn->children[child]);
|
||||
}
|
||||
|
||||
static void emit_value(struct burm_node* node)
|
||||
static void emit_value(int child)
|
||||
{
|
||||
hop_add_value_insel(current_hop, node->ir);
|
||||
hop_add_value_insel(current_hop, current_insn->children[child]->ir);
|
||||
}
|
||||
|
||||
static void emit_eoi(void)
|
||||
|
@ -50,73 +71,75 @@ static void emit_eoi(void)
|
|||
hop_add_eoi_insel(current_hop);
|
||||
}
|
||||
|
||||
static void emit_constraint_equals(struct burm_node* node, int goal)
|
||||
{
|
||||
#if 0
|
||||
struct hop* hop;
|
||||
|
||||
if (!goal)
|
||||
goal = ir->goal_no;
|
||||
hop = imap_get(¤t_ir->hops, goal);
|
||||
|
||||
current_hop->output = hop->output;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct burm_emitter_data emitter_data =
|
||||
{
|
||||
&emit_string,
|
||||
&emit_fragment,
|
||||
&emit_return_reg,
|
||||
&emit_reg,
|
||||
&emit_value,
|
||||
&emit_eoi,
|
||||
&emit_constraint_equals
|
||||
};
|
||||
|
||||
|
||||
static void walk_instructions(struct burm_node* node, int goal)
|
||||
static void emit(struct insn* insn)
|
||||
{
|
||||
struct burm_node* children[10];
|
||||
int insn_no = burm_rule(node->state_label, goal);
|
||||
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
|
||||
const short* nts = burm_nts[insn_no];
|
||||
struct hop* parent_hop = NULL;
|
||||
struct ir* ir = node->ir;
|
||||
struct insn* old = current_insn;
|
||||
current_insn = insn;
|
||||
|
||||
insn->insndata->emitter(&emitter_data);
|
||||
|
||||
current_insn = old;
|
||||
}
|
||||
|
||||
static struct insn* walk_instructions(struct burm_node* node, int goal)
|
||||
{
|
||||
struct insn* insn = calloc(1, sizeof(*insn));
|
||||
int i;
|
||||
|
||||
if (!insndata->is_fragment)
|
||||
insn->ir = node->ir;
|
||||
insn->num_children = 0;
|
||||
|
||||
if (goal)
|
||||
{
|
||||
parent_hop = current_hop;
|
||||
current_hop = new_hop(insn_no, ir);
|
||||
if (goal != 1)
|
||||
{
|
||||
current_hop->output = new_vreg();
|
||||
imap_add(¤t_ir->hops, goal, current_hop);
|
||||
}
|
||||
}
|
||||
int insn_no = burm_rule(node->state_label, goal);
|
||||
const short* nts = burm_nts[insn_no];
|
||||
struct burm_node* children[MAX_CHILDREN] = {0};
|
||||
|
||||
insn->insndata = &burm_instruction_data[insn_no];
|
||||
|
||||
burm_kids(node, insn_no, children);
|
||||
for (i=0; nts[i]; i++)
|
||||
walk_instructions(children[i], nts[i]);
|
||||
|
||||
tracef('I', "I: $%d goal %d selected %s %d: %s\n",
|
||||
ir->id,
|
||||
goal,
|
||||
insndata->is_fragment ? "fragment" : "instruction",
|
||||
insn_no,
|
||||
insndata->name);
|
||||
|
||||
if (!insndata->is_fragment)
|
||||
i = 0;
|
||||
for (;;)
|
||||
{
|
||||
/* This may cause the vregs to be reassigned for this instruction (and
|
||||
* fragments contained within it). */
|
||||
if (!children[i])
|
||||
break;
|
||||
|
||||
insndata->emitter(node, &emitter_data);
|
||||
|
||||
hop_print('I', current_hop);
|
||||
array_append(&ir->hops, current_hop);
|
||||
current_hop = parent_hop;
|
||||
insn->children[i] = walk_instructions(children[i], nts[i]);
|
||||
insn->num_children++;
|
||||
i++;
|
||||
}
|
||||
|
||||
tracef('I', "I: $%d goal %d %s selected %d: %s\n",
|
||||
node->ir->id,
|
||||
goal,
|
||||
insn->insndata->is_fragment ? "fragment" : "instruction",
|
||||
insn_no,
|
||||
insn->insndata->name);
|
||||
|
||||
if (!insn->insndata->is_fragment)
|
||||
{
|
||||
insn->hop = current_hop = new_hop(0, insn->ir);
|
||||
insn->hop->output = new_vreg();
|
||||
emit(insn);
|
||||
hop_print('I', current_hop);
|
||||
|
||||
if (goal != 1)
|
||||
insn->ir->result = insn->hop->output;
|
||||
}
|
||||
}
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir)
|
||||
|
|
|
@ -52,6 +52,7 @@ PATTERNS
|
|||
cost 4;
|
||||
|
||||
reg = POP4
|
||||
with int reg
|
||||
emit "pop %reg"
|
||||
cost 4;
|
||||
|
||||
|
@ -68,12 +69,11 @@ PATTERNS
|
|||
cost 4;
|
||||
|
||||
reg = in:REG
|
||||
with (reg == in)
|
||||
emit "reg %reg"
|
||||
emit "mov %reg, %in"
|
||||
cost 1;
|
||||
|
||||
reg = NOP(in:reg)
|
||||
with (reg == in)
|
||||
emit "mov %reg, %in"
|
||||
cost 1;
|
||||
|
||||
|
||||
|
@ -90,18 +90,22 @@ PATTERNS
|
|||
cost 4;
|
||||
|
||||
reg = LOAD4(addr:address)
|
||||
with int reg
|
||||
emit "ldr %reg, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = LOAD1(addr:address)
|
||||
with int reg
|
||||
emit "ldrb %reg, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = CIU14(LOAD1(addr:address))
|
||||
with int reg
|
||||
emit "ldrb %reg, %addr"
|
||||
cost 4;
|
||||
|
||||
reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
|
||||
with int reg
|
||||
emit "ldrsb %reg, %addr"
|
||||
cost 4;
|
||||
|
||||
|
@ -109,6 +113,7 @@ PATTERNS
|
|||
/* Locals */
|
||||
|
||||
reg = in:LOCAL4
|
||||
with int reg
|
||||
emit "add %reg, fp, #$in"
|
||||
cost 4;
|
||||
|
||||
|
@ -161,14 +166,17 @@ PATTERNS
|
|||
/* Comparisons */
|
||||
|
||||
cc = COMPARES4(left:reg, right:aluparam)
|
||||
with cc cc
|
||||
emit "cmp %left, %right"
|
||||
cost 4;
|
||||
|
||||
cc = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4)
|
||||
with cc cc
|
||||
emit "cmp %left, %right"
|
||||
cost 4;
|
||||
|
||||
reg = cc
|
||||
with int reg
|
||||
emit "mov %reg, #0"
|
||||
emit "movlt %reg, #-1"
|
||||
emit "movgt %reg, #1"
|
||||
|
@ -178,10 +186,12 @@ PATTERNS
|
|||
/* Conversions */
|
||||
|
||||
reg = CII14(CIU41(value:reg))
|
||||
with int reg
|
||||
emit "sxtb %reg, %value"
|
||||
cost 4;
|
||||
|
||||
reg = CIU41(in:reg)
|
||||
with int reg
|
||||
emit "and %reg, %in, #0xff"
|
||||
cost 4;
|
||||
|
||||
|
@ -189,19 +199,23 @@ PATTERNS
|
|||
/* ALU operations */
|
||||
|
||||
reg = ADD4(left:reg, right:aluparam)
|
||||
with int reg
|
||||
emit "add %reg, %left, %right"
|
||||
cost 4;
|
||||
|
||||
reg = ADD4(left:aluparam, right:reg)
|
||||
with int reg
|
||||
emit "add %reg, %right, %left"
|
||||
cost 4;
|
||||
|
||||
reg = MOD4(left:reg, right:reg)
|
||||
with int reg
|
||||
emit "udiv %reg, %left, %right"
|
||||
emit "mls %reg, %reg, %right, %left"
|
||||
cost 8;
|
||||
|
||||
reg = DIV4(left:reg, right:aluparam)
|
||||
with int reg
|
||||
emit "div %reg, %left, %right"
|
||||
cost 4;
|
||||
|
||||
|
@ -212,28 +226,34 @@ PATTERNS
|
|||
emit "%value";
|
||||
|
||||
reg = value:aluparam
|
||||
with int reg
|
||||
emit "mov %reg, %value"
|
||||
cost 4;
|
||||
|
||||
reg = value:LABEL4
|
||||
with int reg
|
||||
emit "adr %reg, $value"
|
||||
cost 4;
|
||||
|
||||
reg = value:BLOCK4
|
||||
with int reg
|
||||
emit "adr %reg, $value"
|
||||
cost 4;
|
||||
|
||||
reg = value:CONST4
|
||||
with int reg
|
||||
emit "ldr %reg, address-containing-$value"
|
||||
cost 8;
|
||||
|
||||
reg = value:CONSTF4
|
||||
with int reg
|
||||
emit "vldr %reg, address-containing-$value"
|
||||
cost 8;
|
||||
|
||||
/* FPU operations */
|
||||
|
||||
reg = ADDF4(left:reg, right:reg)
|
||||
with int reg
|
||||
emit "fadds %reg, %left, %right"
|
||||
cost 4;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ static int nextern = 1;
|
|||
}
|
||||
|
||||
%term ALLOCATES
|
||||
%term COPY
|
||||
%term COST
|
||||
%term DECLARATIONS
|
||||
%term EMIT
|
||||
|
|
|
@ -679,20 +679,22 @@ static void emitheader(void)
|
|||
}
|
||||
|
||||
/* computekids - compute paths to kids in tree t */
|
||||
static char* computekids(Tree t, const char* v, char* bp, int* ip)
|
||||
static char* computekids(Tree node, const char* v, char* bp, int* ip)
|
||||
{
|
||||
Term p = t->op;
|
||||
Term t = node->op;
|
||||
|
||||
if (p->kind == NONTERM)
|
||||
if (!node->left && !node->right)
|
||||
{
|
||||
sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
|
||||
bp += strlen(bp);
|
||||
}
|
||||
else if (p->arity > 0)
|
||||
|
||||
if (t->kind == TERM)
|
||||
{
|
||||
bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip);
|
||||
if (p->arity == 2)
|
||||
bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip);
|
||||
if (t->arity >= 1)
|
||||
bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip);
|
||||
if (t->arity == 2)
|
||||
bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip);
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
@ -910,6 +912,27 @@ static void label_not_found(Rule rule, const char* label)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static bool find_child_index(Tree node, const char* name, int* index, Tree* found)
|
||||
{
|
||||
/* This must return the same ordering as the burm_kids() function uses. */
|
||||
|
||||
if (node->label && strcmp(node->label, name) == 0)
|
||||
{
|
||||
if (found)
|
||||
*found = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!node->left && !node->right)
|
||||
(*index)++;
|
||||
|
||||
if (node->left && find_child_index(node->left, name, index, found))
|
||||
return true;
|
||||
if (node->right && find_child_index(node->right, name, index, found))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* emitpredicates - emit predicates for rules */
|
||||
static void emitpredicatedefinitions(Rule r)
|
||||
{
|
||||
|
@ -954,49 +977,6 @@ static void emitpredicatedefinitions(Rule r)
|
|||
}
|
||||
}
|
||||
|
||||
static void invalid_equals_constraint(Rule rule)
|
||||
{
|
||||
yylineno = rule->lineno;
|
||||
yyerror("left hand side of an equality constraint must be the output register");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void emit_ir_expr(Rule rule, const char* label)
|
||||
{
|
||||
if (strcmp(label, rule->lhs->name) == 0)
|
||||
print("node, %P%s_NT", label);
|
||||
else
|
||||
{
|
||||
Tree node;
|
||||
uint32_t path = find_label(rule->pattern, label, 0, &node);
|
||||
Nonterm nt = node->op;
|
||||
|
||||
if (path == PATH_MISSING)
|
||||
label_not_found(rule, label);
|
||||
|
||||
print_path(path);
|
||||
if (nt->kind == NONTERM)
|
||||
print(", %P%s_NT", ((Nonterm)node->op)->name);
|
||||
else
|
||||
print(", 0");
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_constraint(Rule rule, struct constraint* c)
|
||||
{
|
||||
switch (c->type)
|
||||
{
|
||||
case CONSTRAINT_EQUALS:
|
||||
if (strcmp(c->left, rule->lhs->name) != 0)
|
||||
invalid_equals_constraint(rule);
|
||||
|
||||
print("%1data->emit_constraint_equals(");
|
||||
emit_ir_expr(rule, c->right);
|
||||
print(");\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* emitinsndata - emit the code generation data */
|
||||
static void emitinsndata(Rule rules)
|
||||
{
|
||||
|
@ -1007,6 +987,7 @@ static void emitinsndata(Rule rules)
|
|||
while (r)
|
||||
{
|
||||
struct stringfragment* f = r->code.first;
|
||||
yylineno = r->lineno;
|
||||
|
||||
if (!f)
|
||||
{
|
||||
|
@ -1019,20 +1000,7 @@ static void emitinsndata(Rule rules)
|
|||
}
|
||||
|
||||
print("/* %R */\n", r);
|
||||
print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
|
||||
|
||||
/* Constraints come first, because they may cause vreg reassignment, which
|
||||
* we want to happen before the instruction emission. */
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<r->constraints.count; i++)
|
||||
{
|
||||
struct constraint* c = r->constraints.item[i];
|
||||
emit_constraint(r, c);
|
||||
}
|
||||
}
|
||||
print("static void %Pemitter_%d(const struct %Pemitter_data* data) {\n", r->ern);
|
||||
|
||||
while (f)
|
||||
{
|
||||
|
@ -1043,23 +1011,26 @@ static void emitinsndata(Rule rules)
|
|||
const char* label = f->data + 1;
|
||||
|
||||
if (strcmp(label, r->lhs->name) == 0)
|
||||
print("%1data->emit_reg(node, %P%s_NT);\n", label);
|
||||
print("%1data->emit_return_reg();\n", label);
|
||||
else
|
||||
{
|
||||
Tree node;
|
||||
uint32_t path = find_label(r->pattern, label, 0, &node);
|
||||
int index = 0;
|
||||
if (!find_child_index(r->pattern, label, &index, &node))
|
||||
label_not_found(r, label);
|
||||
Nonterm nt = node->op;
|
||||
|
||||
if (path == PATH_MISSING)
|
||||
label_not_found(r, label);
|
||||
|
||||
if (nt->kind == NONTERM)
|
||||
{
|
||||
if (nt->is_fragment)
|
||||
print("%1data->emit_fragment(");
|
||||
else
|
||||
print("%1data->emit_reg(");
|
||||
}
|
||||
else
|
||||
print("%1data->emit_reg(");
|
||||
|
||||
print_path(path);
|
||||
print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
|
||||
print("%d);\n", index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1067,12 +1038,11 @@ static void emitinsndata(Rule rules)
|
|||
case '$':
|
||||
{
|
||||
const char* label = f->data + 1;
|
||||
uint32_t path = find_label(r->pattern, label, 0, NULL);
|
||||
print("%1data->emit_value(");
|
||||
if (path == PATH_MISSING)
|
||||
int index = 0;
|
||||
if (!find_child_index(r->pattern, label, &index, NULL))
|
||||
label_not_found(r, label);
|
||||
print_path(path);
|
||||
print(");\n");
|
||||
|
||||
print("%1data->emit_value(%d);\n", index);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,14 +39,14 @@ extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost);
|
|||
struct burm_emitter_data
|
||||
{
|
||||
void (*emit_string)(const char* data);
|
||||
void (*emit_fragment)(NODEPTR_TYPE node, int goal);
|
||||
void (*emit_reg)(NODEPTR_TYPE node, int goal);
|
||||
void (*emit_value)(NODEPTR_TYPE node);
|
||||
void (*emit_fragment)(int child);
|
||||
void (*emit_return_reg)(void);
|
||||
void (*emit_reg)(int child);
|
||||
void (*emit_value)(int child);
|
||||
void (*emit_eoi)(void);
|
||||
void (*emit_constraint_equals)(NODEPTR_TYPE node, int goal);
|
||||
};
|
||||
|
||||
typedef void burm_emitter_t(NODEPTR_TYPE node, const struct burm_emitter_data* data);
|
||||
typedef void burm_emitter_t(const struct burm_emitter_data* data);
|
||||
|
||||
struct burm_instruction_data
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue