ARRAYOF(struct ir) phivalue;
} u;
+ struct vreg* result; /* vreg containing IR result */
IMAPOF(struct hop) hops; /* only for root IRs; by goal */
};
#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];
exit(1);
}
-static void emit_reg(struct burm_node* node, int goal)
+static void emit_return_reg(void)
+{
+ hop_add_vreg_insel(current_hop, current_hop->output);
+}
+
+static void emit_reg(int child)
{
- struct hop* hop = imap_get(¤t_ir->hops, goal);
+ struct insn* insn = current_insn->children[child];
+ struct vreg* vreg;
- hop_add_vreg_insel(current_hop, hop->output);
+ 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)
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)
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 emit(struct insn* insn)
+{
+ struct insn* old = current_insn;
+ current_insn = insn;
+
+ insn->insndata->emitter(&emitter_data);
+
+ current_insn = old;
+}
-static void walk_instructions(struct burm_node* node, int goal)
+static struct insn* walk_instructions(struct burm_node* node, int goal)
{
- 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* 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};
- burm_kids(node, insn_no, children);
- for (i=0; nts[i]; i++)
- walk_instructions(children[i], nts[i]);
+ insn->insndata = &burm_instruction_data[insn_no];
- tracef('I', "I: $%d goal %d selected %s %d: %s\n",
- ir->id,
- goal,
- insndata->is_fragment ? "fragment" : "instruction",
- insn_no,
- insndata->name);
+ burm_kids(node, insn_no, children);
- if (!insndata->is_fragment)
- {
- /* This may cause the vregs to be reassigned for this instruction (and
- * fragments contained within it). */
+ i = 0;
+ for (;;)
+ {
+ if (!children[i])
+ break;
+
+ insn->children[i] = walk_instructions(children[i], nts[i]);
+ insn->num_children++;
+ i++;
+ }
- insndata->emitter(node, &emitter_data);
+ 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);
- hop_print('I', current_hop);
- array_append(&ir->hops, current_hop);
- current_hop = parent_hop;
+ 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)
cost 4;
reg = POP4
+ with int reg
emit "pop %reg"
cost 4;
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;
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;
/* Locals */
reg = in:LOCAL4
+ with int reg
emit "add %reg, fp, #$in"
cost 4;
/* 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"
/* 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;
/* 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;
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;
}
%term ALLOCATES
+%term COPY
%term COST
%term DECLARATIONS
%term EMIT
;
pattern
- : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); }
- | rhs { $$ = rule("stmt", $1, nextern++); }
- | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); }
- | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); }
- | pattern COST INT { $$ = $1; $$->cost = $3; }
- | pattern_constraints { $$ = $1; }
- | pattern_emit { $$ = $1; }
+ : ID '=' rhs { nonterm($1, false); $$ = rule($1, $3, nextern++); }
+ | rhs { $$ = rule("stmt", $1, nextern++); }
+ | pattern PREFERS predicate { $$ = $1; array_append(&$$->prefers, $3); }
+ | pattern WHEN predicate { $$ = $1; array_append(&$$->requires, $3); }
+ | pattern COST INT { $$ = $1; $$->cost = $3; }
+ | pattern_constraints { $$ = $1; }
+ | pattern_emit { $$ = $1; }
;
rhs
- : terminfo { $$ = tree(&$1, NULL, NULL); }
- | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); }
- | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); }
+ : terminfo { $$ = tree(&$1, NULL, NULL); }
+ | terminfo '(' rhs ')' { $$ = tree(&$1, $3, NULL); }
+ | terminfo '(' rhs ',' rhs ')' { $$ = tree(&$1, $3, $5); }
;
terminfo
- : ID { $$.name = $1; }
- | ID ':' ID { $$.label = $1; $$.name = $3; }
+ : ID { $$.name = $1; }
+ | ID ':' ID { $$.label = $1; $$.name = $3; }
;
pattern_emit
}
/* 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;
}
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)
{
}
}
-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)
{
while (r)
{
struct stringfragment* f = r->code.first;
+ yylineno = r->lineno;
if (!f)
{
}
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)
{
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);
- Nonterm nt = node->op;
-
- if (path == PATH_MISSING)
+ int index = 0;
+ if (!find_child_index(r->pattern, label, &index, &node))
label_not_found(r, label);
+ Nonterm nt = node->op;
- if (nt->is_fragment)
- print("%1data->emit_fragment(");
+ 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;
}
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;
}
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
{