array_append(&hop->insels, insel);
}
-void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no)
+void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg)
{
- struct insel* insel = new_insel(INSEL_REG);
- insel->u.reg.ir = ir;
- insel->u.reg.insn_no = insn_no;
+ struct insel* insel = new_insel(INSEL_VREG);
+ insel->u.vreg = vreg;
array_append(&hop->insels, insel);
}
if (soi)
{
- tracef(k, "%c: %d: ", k, hop->id);
+ tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id);
soi = false;
}
soi = true;
break;
- case INSEL_REG:
- tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no);
+ case INSEL_VREG:
+ tracef(k, "%%%d", insel->u.vreg->id);
break;
case INSEL_STRING:
static void emit_reg(struct ir* ir, int goal)
{
- hop_add_reg_insel(current_hop, ir, goal);
+ struct hop* hop = imap_get(¤t_ir->hops, goal);
+
+ hop_add_vreg_insel(current_hop, hop->output);
}
static void emit_string(const char* data)
hop_add_value_insel(current_hop, ir);
}
-static void emit_resultreg(void)
+static void emit_eoi(void)
{
+ hop_add_eoi_insel(current_hop);
}
-static void emit_eoi(void)
+static void emit_constraint_equals(struct ir* ir, int goal)
{
- hop_add_eoi_insel(current_hop);
+ struct hop* hop;
+
+ if (!goal)
+ goal = 2;
+ hop = imap_get(¤t_ir->hops, goal);
+
+ current_hop->output = hop->output;
}
static const struct burm_emitter_data emitter_data =
&emit_fragment,
&emit_reg,
&emit_value,
- &emit_resultreg,
- &emit_eoi
+ &emit_eoi,
+ &emit_constraint_equals
};
{
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);
+ }
}
burm_kids(ir, insn_no, children);
if (!insndata->is_fragment)
{
- if (insndata->emitter)
- insndata->emitter(ir, &emitter_data);
+ /* This may cause the vregs to be reassigned for this instruction (and
+ * fragments contained within it). */
+
+ insndata->emitter(ir, &emitter_data);
hop_print('I', current_hop);
array_append(&ir->hops, current_hop);
}
}
+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;
- if (f)
+
+ if (!f)
+ {
+ /* This instruction has no code; make sure it's not a fragment. */
+ if (r->lhs->is_fragment)
+ {
+ yylineno = r->lineno;
+ yyerror("rule is a fragment, but doesn't emit anything");
+ }
+ }
+
+ 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. */
+
{
- print("/* %R */\n", r);
- print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
+ int i;
- while (f)
+ for (i=0; i<r->constraints.count; i++)
{
- switch (f->data[0])
- {
- case '%':
- {
- const char* label = f->data + 1;
+ struct constraint* c = r->constraints.item[i];
+ emit_constraint(r, c);
+ }
+ }
- if (strcmp(label, r->lhs->name) == 0)
- print("%1data->emit_reg(node, %P%s_NT);\n", label);
- else
- {
- Tree node;
- uint32_t path = find_label(r->pattern, label, 0, &node);
- Nonterm nt = node->op;
-
- if (path == PATH_MISSING)
- label_not_found(r, label);
-
- if (nt->is_fragment)
- print("%1data->emit_fragment(");
- else
- print("%1data->emit_reg(");
-
- print_path(path);
- print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
- }
- break;
- }
+ while (f)
+ {
+ switch (f->data[0])
+ {
+ case '%':
+ {
+ const char* label = f->data + 1;
- case '$':
+ if (strcmp(label, r->lhs->name) == 0)
+ print("%1data->emit_reg(node, %P%s_NT);\n", label);
+ else
{
- const char* label = f->data + 1;
- uint32_t path = find_label(r->pattern, label, 0, NULL);
- print("%1data->emit_value(");
+ Tree node;
+ uint32_t path = find_label(r->pattern, label, 0, &node);
+ Nonterm nt = node->op;
+
if (path == PATH_MISSING)
label_not_found(r, label);
+
+ if (nt->is_fragment)
+ print("%1data->emit_fragment(");
+ else
+ print("%1data->emit_reg(");
+
print_path(path);
- print(");\n");
- break;
+ print(", %P%s_NT);\n", ((Nonterm)node->op)->name);
}
+ break;
+ }
- case '\n':
- assert(f->data[1] == 0);
- print("%1data->emit_eoi();\n");
- break;
-
- default:
- print("%1data->emit_string(\"%s\");\n", f->data);
+ 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)
+ label_not_found(r, label);
+ print_path(path);
+ print(");\n");
+ break;
}
- f = f->next;
+ case '\n':
+ assert(f->data[1] == 0);
+ print("%1data->emit_eoi();\n");
+ break;
+
+ default:
+ print("%1data->emit_string(\"%s\");\n", f->data);
}
- print("}\n\n");
- }
- else
- {
- /* This instruction has no code; make sure it's not a fragment. */
- if (r->lhs->is_fragment)
- {
- yylineno = r->lineno;
- yyerror("rule is a fragment, but doesn't emit anything");
- }
+ f = f->next;
}
+ print("}\n\n");
r = r->link;
}
print("%2\"%R\",\n", r);
- print("%2");
- if (r->code.first)
- print("&%Pemitter_%d,\n", r->ern);
- else
- print("NULL,\n");
+ print("%2&%Pemitter_%d,\n", r->ern);
if (r->lhs->allocate)
print("%2%d,\n", r->lhs->allocate->number);