Get quite a long way towards basic output-register equality constraints (needed

to make special nodes like NOP work properly). Realise that the way I'm dealing
with the instruction selector is all wrong; I need to physically copy chunks of
tree to give to burg (so I can terminate them correctly).
This commit is contained in:
David Given 2016-10-02 23:25:54 +02:00
parent 3aa30e50d1
commit 288ee56203
10 changed files with 177 additions and 94 deletions

View file

@ -28,11 +28,10 @@ void hop_add_string_insel(struct hop* hop, const char* string)
array_append(&hop->insels, insel); 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); struct insel* insel = new_insel(INSEL_VREG);
insel->u.reg.ir = ir; insel->u.vreg = vreg;
insel->u.reg.insn_no = insn_no;
array_append(&hop->insels, insel); array_append(&hop->insels, insel);
} }
@ -61,7 +60,7 @@ void hop_print(char k, struct hop* hop)
if (soi) if (soi)
{ {
tracef(k, "%c: %d: ", k, hop->id); tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id);
soi = false; soi = false;
} }
@ -72,8 +71,8 @@ void hop_print(char k, struct hop* hop)
soi = true; soi = true;
break; break;
case INSEL_REG: case INSEL_VREG:
tracef(k, "$%d.%d", insel->u.reg.ir->id, insel->u.reg.insn_no); tracef(k, "%%%d", insel->u.vreg->id);
break; break;
case INSEL_STRING: case INSEL_STRING:

View file

@ -4,7 +4,7 @@
enum insel_type enum insel_type
{ {
INSEL_STRING, INSEL_STRING,
INSEL_REG, INSEL_VREG,
INSEL_VALUE, INSEL_VALUE,
INSEL_EOI INSEL_EOI
}; };
@ -15,12 +15,7 @@ struct insel
union union
{ {
const char* string; const char* string;
struct struct vreg* vreg;
{
struct ir* ir;
int insn_no;
}
reg;
struct ir* value; struct ir* value;
} }
u; u;
@ -32,12 +27,13 @@ struct hop
int insn_no; int insn_no;
struct ir* ir; struct ir* ir;
ARRAYOF(struct insel) insels; ARRAYOF(struct insel) insels;
struct vreg* output;
}; };
extern struct hop* new_hop(int insn_no, struct ir* ir); extern struct hop* new_hop(int insn_no, struct ir* ir);
extern void hop_add_string_insel(struct hop* hop, const char* string); extern void hop_add_string_insel(struct hop* hop, const char* string);
extern void hop_add_reg_insel(struct hop* hop, struct ir* ir, int insn_no); extern void hop_add_vreg_insel(struct hop* hop, struct vreg* vreg);
extern void hop_add_value_insel(struct hop* hop, struct ir* ir); extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
extern void hop_add_eoi_insel(struct hop* hop); extern void hop_add_eoi_insel(struct hop* hop);

View file

@ -23,7 +23,7 @@ struct ir
void* state_label; /* used by the iburg instruction selector */ void* state_label; /* used by the iburg instruction selector */
int insn_no; /* the table rule number for this instruction */ int insn_no; /* the table rule number for this instruction */
int goal_no; /* the semantic type of this instruction; not stmt */ int goal_no; /* the semantic type of this instruction; not stmt */
ARRAYOF(struct hop) hops; /* only for root IRs */ IMAPOF(struct hop) hops; /* only for root IRs; by goal */
}; };
extern const char* ir_names[]; extern const char* ir_names[];

View file

@ -24,6 +24,7 @@
#include "ir.h" #include "ir.h"
#include "mcgg.h" #include "mcgg.h"
#include "hop.h" #include "hop.h"
#include "vreg.h"
#include "basicblock.h" #include "basicblock.h"
#include "procedure.h" #include "procedure.h"

View file

@ -29,7 +29,9 @@ int burm_calculate_label(struct ir* ir)
static void emit_reg(struct ir* ir, int goal) static void emit_reg(struct ir* ir, int goal)
{ {
hop_add_reg_insel(current_hop, ir, goal); struct hop* hop = imap_get(&current_ir->hops, goal);
hop_add_vreg_insel(current_hop, hop->output);
} }
static void emit_string(const char* data) static void emit_string(const char* data)
@ -50,23 +52,30 @@ static void emit_value(struct ir* ir)
hop_add_value_insel(current_hop, ir); hop_add_value_insel(current_hop, ir);
} }
static void emit_resultreg(void)
{
}
static void emit_eoi(void) static void emit_eoi(void)
{ {
hop_add_eoi_insel(current_hop); hop_add_eoi_insel(current_hop);
} }
static void emit_constraint_equals(struct ir* ir, int goal)
{
struct hop* hop;
if (!goal)
goal = 2;
hop = imap_get(&current_ir->hops, goal);
current_hop->output = hop->output;
}
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_reg, &emit_reg,
&emit_value, &emit_value,
&emit_resultreg, &emit_eoi,
&emit_eoi &emit_constraint_equals
}; };
@ -83,6 +92,11 @@ static void walk_instructions(struct ir* ir, int goal)
{ {
parent_hop = current_hop; parent_hop = current_hop;
current_hop = new_hop(insn_no, ir); current_hop = new_hop(insn_no, ir);
if (goal != 1)
{
current_hop->output = new_vreg();
imap_add(&current_ir->hops, goal, current_hop);
}
} }
burm_kids(ir, insn_no, children); burm_kids(ir, insn_no, children);
@ -102,8 +116,10 @@ static void walk_instructions(struct ir* ir, int goal)
if (!insndata->is_fragment) if (!insndata->is_fragment)
{ {
if (insndata->emitter) /* This may cause the vregs to be reassigned for this instruction (and
insndata->emitter(ir, &emitter_data); * fragments contained within it). */
insndata->emitter(ir, &emitter_data);
hop_print('I', current_hop); hop_print('I', current_hop);
array_append(&ir->hops, current_hop); array_append(&ir->hops, current_hop);

View file

@ -69,6 +69,7 @@ PATTERNS
reg = in:REG4 reg = in:REG4
with (reg == in) with (reg == in)
emit "reg %reg"
cost 1; cost 1;
reg = NOP4(in:reg) reg = NOP4(in:reg)

10
mach/proto/mcg/vreg.c Normal file
View file

@ -0,0 +1,10 @@
#include "mcg.h"
static int vreg_count = 1;
struct vreg* new_vreg(void)
{
struct vreg* vreg = calloc(1, sizeof *vreg);
vreg->id = vreg_count++;
return vreg;
}

12
mach/proto/mcg/vreg.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef VREG_H
#define VREG_H
struct vreg
{
int id;
};
extern struct vreg* new_vreg(void);
#endif

View file

@ -954,6 +954,49 @@ 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)
{ {
@ -964,68 +1007,8 @@ static void emitinsndata(Rule rules)
while (r) while (r)
{ {
struct stringfragment* f = r->code.first; struct stringfragment* f = r->code.first;
if (f)
{
print("/* %R */\n", r);
print("static void %Pemitter_%d(NODEPTR_TYPE node, const struct %Pemitter_data* data) {\n", r->ern);
while (f) if (!f)
{
switch (f->data[0])
{
case '%':
{
const char* label = f->data + 1;
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;
}
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;
}
case '\n':
assert(f->data[1] == 0);
print("%1data->emit_eoi();\n");
break;
default:
print("%1data->emit_string(\"%s\");\n", f->data);
}
f = f->next;
}
print("}\n\n");
}
else
{ {
/* This instruction has no code; make sure it's not a fragment. */ /* This instruction has no code; make sure it's not a fragment. */
if (r->lhs->is_fragment) if (r->lhs->is_fragment)
@ -1035,6 +1018,77 @@ 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);
}
}
while (f)
{
switch (f->data[0])
{
case '%':
{
const char* label = f->data + 1;
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;
}
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;
}
case '\n':
assert(f->data[1] == 0);
print("%1data->emit_eoi();\n");
break;
default:
print("%1data->emit_string(\"%s\");\n", f->data);
}
f = f->next;
}
print("}\n\n");
r = r->link; r = r->link;
} }
@ -1051,11 +1105,7 @@ static void emitinsndata(Rule rules)
print("%2\"%R\",\n", r); print("%2\"%R\",\n", r);
print("%2"); print("%2&%Pemitter_%d,\n", r->ern);
if (r->code.first)
print("&%Pemitter_%d,\n", r->ern);
else
print("NULL,\n");
if (r->lhs->allocate) if (r->lhs->allocate)
print("%2%d,\n", r->lhs->allocate->number); print("%2%d,\n", r->lhs->allocate->number);

View file

@ -12,7 +12,6 @@
((size) == 0) ? 0 : \ ((size) == 0) ? 0 : \
(size-1))) (size-1)))
#define STATE_TYPE void* #define STATE_TYPE void*
typedef struct ir* NODEPTR_TYPE; typedef struct ir* NODEPTR_TYPE;
@ -30,9 +29,8 @@ struct burm_emitter_data
void (*emit_fragment)(struct ir* ir, int goal); void (*emit_fragment)(struct ir* ir, int goal);
void (*emit_reg)(struct ir* ir, int goal); void (*emit_reg)(struct ir* ir, int goal);
void (*emit_value)(struct ir* ir); void (*emit_value)(struct ir* ir);
void (*emit_resultreg)(void);
void (*emit_eoi)(void); void (*emit_eoi)(void);
void (*emit_usereg)(struct ir* ir); void (*emit_constraint_equals)(struct ir* rightir, int rightgoal);
}; };
typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data); typedef void burm_emitter_t(struct ir* ir, const struct burm_emitter_data* data);