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:
David Given 2016-10-04 00:16:06 +02:00
parent 68f98cbad7
commit bd28bddb92
6 changed files with 175 additions and 160 deletions

View file

@ -20,6 +20,7 @@ struct ir
ARRAYOF(struct ir) phivalue; ARRAYOF(struct ir) phivalue;
} u; } u;
struct vreg* result; /* vreg containing IR result */
IMAPOF(struct hop) hops; /* only for root IRs; by goal */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */
}; };

View file

@ -1,10 +1,22 @@
#include "mcg.h" #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 basicblock* current_bb;
static struct hop* current_hop; static struct hop* current_hop;
static struct ir* current_ir; 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) { void burm_trace(struct burm_node* p, int ruleno, int cost, int bestcost) {
const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno]; 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); exit(1);
} }
static void emit_reg(struct burm_node* node, int goal) static void emit_return_reg(void)
{ {
struct hop* hop = imap_get(&current_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) 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); 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); emit(current_insn->children[child]);
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
if (insndata->emitter)
insndata->emitter(node, &emitter_data);
} }
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) static void emit_eoi(void)
@ -50,73 +71,75 @@ static void emit_eoi(void)
hop_add_eoi_insel(current_hop); 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(&current_ir->hops, goal);
current_hop->output = hop->output;
#endif
}
static const struct burm_emitter_data emitter_data = static const struct burm_emitter_data emitter_data =
{ {
&emit_string, &emit_string,
&emit_fragment, &emit_fragment,
&emit_return_reg,
&emit_reg, &emit_reg,
&emit_value, &emit_value,
&emit_eoi, &emit_eoi,
&emit_constraint_equals
}; };
static void emit(struct insn* insn)
static void walk_instructions(struct burm_node* node, int goal)
{ {
struct burm_node* children[10]; struct insn* old = current_insn;
int insn_no = burm_rule(node->state_label, goal); current_insn = insn;
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
const short* nts = burm_nts[insn_no]; insn->insndata->emitter(&emitter_data);
struct hop* parent_hop = NULL;
struct ir* ir = node->ir; current_insn = old;
}
static struct insn* walk_instructions(struct burm_node* node, int goal)
{
struct insn* insn = calloc(1, sizeof(*insn));
int i; int i;
if (!insndata->is_fragment) insn->ir = node->ir;
insn->num_children = 0;
if (goal)
{ {
parent_hop = current_hop; int insn_no = burm_rule(node->state_label, goal);
current_hop = new_hop(insn_no, ir); const short* nts = burm_nts[insn_no];
if (goal != 1) struct burm_node* children[MAX_CHILDREN] = {0};
{
current_hop->output = new_vreg(); insn->insndata = &burm_instruction_data[insn_no];
imap_add(&current_ir->hops, goal, current_hop);
}
}
burm_kids(node, insn_no, children); 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", i = 0;
ir->id, for (;;)
goal,
insndata->is_fragment ? "fragment" : "instruction",
insn_no,
insndata->name);
if (!insndata->is_fragment)
{ {
/* This may cause the vregs to be reassigned for this instruction (and if (!children[i])
* fragments contained within it). */ break;
insndata->emitter(node, &emitter_data); insn->children[i] = walk_instructions(children[i], nts[i]);
insn->num_children++;
hop_print('I', current_hop); i++;
array_append(&ir->hops, current_hop);
current_hop = parent_hop;
} }
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) static struct burm_node* build_shadow_tree(struct ir* root, struct ir* ir)

View file

@ -52,6 +52,7 @@ PATTERNS
cost 4; cost 4;
reg = POP4 reg = POP4
with int reg
emit "pop %reg" emit "pop %reg"
cost 4; cost 4;
@ -68,12 +69,11 @@ PATTERNS
cost 4; cost 4;
reg = in:REG reg = in:REG
with (reg == in) emit "mov %reg, %in"
emit "reg %reg"
cost 1; cost 1;
reg = NOP(in:reg) reg = NOP(in:reg)
with (reg == in) emit "mov %reg, %in"
cost 1; cost 1;
@ -90,18 +90,22 @@ PATTERNS
cost 4; cost 4;
reg = LOAD4(addr:address) reg = LOAD4(addr:address)
with int reg
emit "ldr %reg, %addr" emit "ldr %reg, %addr"
cost 4; cost 4;
reg = LOAD1(addr:address) reg = LOAD1(addr:address)
with int reg
emit "ldrb %reg, %addr" emit "ldrb %reg, %addr"
cost 4; cost 4;
reg = CIU14(LOAD1(addr:address)) reg = CIU14(LOAD1(addr:address))
with int reg
emit "ldrb %reg, %addr" emit "ldrb %reg, %addr"
cost 4; cost 4;
reg = CII14(CIU41(CIU14(LOAD1(addr:address)))) reg = CII14(CIU41(CIU14(LOAD1(addr:address))))
with int reg
emit "ldrsb %reg, %addr" emit "ldrsb %reg, %addr"
cost 4; cost 4;
@ -109,6 +113,7 @@ PATTERNS
/* Locals */ /* Locals */
reg = in:LOCAL4 reg = in:LOCAL4
with int reg
emit "add %reg, fp, #$in" emit "add %reg, fp, #$in"
cost 4; cost 4;
@ -161,14 +166,17 @@ PATTERNS
/* Comparisons */ /* Comparisons */
cc = COMPARES4(left:reg, right:aluparam) cc = COMPARES4(left: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 = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4)
with cc cc
emit "cmp %left, %right" emit "cmp %left, %right"
cost 4; cost 4;
reg = cc reg = cc
with int reg
emit "mov %reg, #0" emit "mov %reg, #0"
emit "movlt %reg, #-1" emit "movlt %reg, #-1"
emit "movgt %reg, #1" emit "movgt %reg, #1"
@ -178,10 +186,12 @@ PATTERNS
/* Conversions */ /* Conversions */
reg = CII14(CIU41(value:reg)) reg = CII14(CIU41(value:reg))
with int reg
emit "sxtb %reg, %value" emit "sxtb %reg, %value"
cost 4; cost 4;
reg = CIU41(in:reg) reg = CIU41(in:reg)
with int reg
emit "and %reg, %in, #0xff" emit "and %reg, %in, #0xff"
cost 4; cost 4;
@ -189,19 +199,23 @@ PATTERNS
/* ALU operations */ /* ALU operations */
reg = ADD4(left:reg, right:aluparam) reg = ADD4(left:reg, right:aluparam)
with int reg
emit "add %reg, %left, %right" emit "add %reg, %left, %right"
cost 4; cost 4;
reg = ADD4(left:aluparam, right:reg) reg = ADD4(left:aluparam, right:reg)
with int reg
emit "add %reg, %right, %left" emit "add %reg, %right, %left"
cost 4; cost 4;
reg = MOD4(left:reg, right:reg) reg = MOD4(left:reg, right:reg)
with int reg
emit "udiv %reg, %left, %right" emit "udiv %reg, %left, %right"
emit "mls %reg, %reg, %right, %left" emit "mls %reg, %reg, %right, %left"
cost 8; cost 8;
reg = DIV4(left:reg, right:aluparam) reg = DIV4(left:reg, right:aluparam)
with int reg
emit "div %reg, %left, %right" emit "div %reg, %left, %right"
cost 4; cost 4;
@ -212,28 +226,34 @@ PATTERNS
emit "%value"; emit "%value";
reg = value:aluparam reg = value:aluparam
with int reg
emit "mov %reg, %value" emit "mov %reg, %value"
cost 4; cost 4;
reg = value:LABEL4 reg = value:LABEL4
with int reg
emit "adr %reg, $value" emit "adr %reg, $value"
cost 4; cost 4;
reg = value:BLOCK4 reg = value:BLOCK4
with int reg
emit "adr %reg, $value" emit "adr %reg, $value"
cost 4; cost 4;
reg = value:CONST4 reg = value:CONST4
with int reg
emit "ldr %reg, address-containing-$value" emit "ldr %reg, address-containing-$value"
cost 8; cost 8;
reg = value:CONSTF4 reg = value:CONSTF4
with int reg
emit "vldr %reg, address-containing-$value" emit "vldr %reg, address-containing-$value"
cost 8; cost 8;
/* FPU operations */ /* FPU operations */
reg = ADDF4(left:reg, right:reg) reg = ADDF4(left:reg, right:reg)
with int reg
emit "fadds %reg, %left, %right" emit "fadds %reg, %left, %right"
cost 4; cost 4;

View file

@ -28,6 +28,7 @@ static int nextern = 1;
} }
%term ALLOCATES %term ALLOCATES
%term COPY
%term COST %term COST
%term DECLARATIONS %term DECLARATIONS
%term EMIT %term EMIT

View file

@ -679,20 +679,22 @@ static void emitheader(void)
} }
/* computekids - compute paths to kids in tree t */ /* 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); sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
bp += strlen(bp); bp += strlen(bp);
} }
else if (p->arity > 0)
if (t->kind == TERM)
{ {
bp = computekids(t->left, aprintf("LEFT_CHILD(%s)", v), bp, ip); if (t->arity >= 1)
if (p->arity == 2) bp = computekids(node->left, aprintf("LEFT_CHILD(%s)", v), bp, ip);
bp = computekids(t->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip); if (t->arity == 2)
bp = computekids(node->right, aprintf("RIGHT_CHILD(%s)", v), bp, ip);
} }
return bp; return bp;
} }
@ -910,6 +912,27 @@ static void label_not_found(Rule rule, const char* label)
exit(1); 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 */ /* emitpredicates - emit predicates for rules */
static void emitpredicatedefinitions(Rule r) 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 */ /* emitinsndata - emit the code generation data */
static void emitinsndata(Rule rules) static void emitinsndata(Rule rules)
{ {
@ -1007,6 +987,7 @@ static void emitinsndata(Rule rules)
while (r) while (r)
{ {
struct stringfragment* f = r->code.first; struct stringfragment* f = r->code.first;
yylineno = r->lineno;
if (!f) if (!f)
{ {
@ -1019,20 +1000,7 @@ static void emitinsndata(Rule rules)
} }
print("/* %R */\n", r); print("/* %R */\n", r);
print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern); print("static void %Pemitter_%d(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);
}
}
while (f) while (f)
{ {
@ -1043,23 +1011,26 @@ 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 (strcmp(label, r->lhs->name) == 0)
print("%1data->emit_reg(node, %P%s_NT);\n", label); print("%1data->emit_return_reg();\n", label);
else else
{ {
Tree node; 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; Nonterm nt = node->op;
if (path == PATH_MISSING) if (nt->kind == NONTERM)
label_not_found(r, label); {
if (nt->is_fragment) if (nt->is_fragment)
print("%1data->emit_fragment("); print("%1data->emit_fragment(");
else else
print("%1data->emit_reg("); print("%1data->emit_reg(");
}
else
print("%1data->emit_reg(");
print_path(path); print("%d);\n", index);
print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
} }
break; break;
} }
@ -1067,12 +1038,11 @@ static void emitinsndata(Rule rules)
case '$': case '$':
{ {
const char* label = f->data + 1; const char* label = f->data + 1;
uint32_t path = find_label(r->pattern, label, 0, NULL); int index = 0;
print("%1data->emit_value("); if (!find_child_index(r->pattern, label, &index, NULL))
if (path == PATH_MISSING)
label_not_found(r, label); label_not_found(r, label);
print_path(path);
print(");\n"); print("%1data->emit_value(%d);\n", index);
break; break;
} }

View file

@ -39,14 +39,14 @@ extern void burm_trace(NODEPTR_TYPE p, int ruleno, int cost, int bestcost);
struct burm_emitter_data struct burm_emitter_data
{ {
void (*emit_string)(const char* data); void (*emit_string)(const char* data);
void (*emit_fragment)(NODEPTR_TYPE node, int goal); void (*emit_fragment)(int child);
void (*emit_reg)(NODEPTR_TYPE node, int goal); void (*emit_return_reg)(void);
void (*emit_value)(NODEPTR_TYPE node); void (*emit_reg)(int child);
void (*emit_value)(int child);
void (*emit_eoi)(void); 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 struct burm_instruction_data
{ {