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);
}
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);
}
@ -61,7 +60,7 @@ void hop_print(char k, struct hop* hop)
if (soi)
{
tracef(k, "%c: %d: ", k, hop->id);
tracef(k, "%c: %d from $%d: ", k, hop->id, hop->ir->id);
soi = false;
}
@ -72,8 +71,8 @@ void hop_print(char k, struct hop* hop)
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:

View file

@ -4,7 +4,7 @@
enum insel_type
{
INSEL_STRING,
INSEL_REG,
INSEL_VREG,
INSEL_VALUE,
INSEL_EOI
};
@ -15,12 +15,7 @@ struct insel
union
{
const char* string;
struct
{
struct ir* ir;
int insn_no;
}
reg;
struct vreg* vreg;
struct ir* value;
}
u;
@ -32,12 +27,13 @@ struct hop
int insn_no;
struct ir* ir;
ARRAYOF(struct insel) insels;
struct vreg* output;
};
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_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_eoi_insel(struct hop* hop);

View file

@ -23,7 +23,7 @@ struct ir
void* state_label; /* used by the iburg instruction selector */
int insn_no; /* the table rule number for this instruction */
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[];

View file

@ -24,6 +24,7 @@
#include "ir.h"
#include "mcgg.h"
#include "hop.h"
#include "vreg.h"
#include "basicblock.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)
{
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)
@ -50,23 +52,30 @@ static void emit_value(struct ir* ir)
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_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 =
{
&emit_string,
&emit_fragment,
&emit_reg,
&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;
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);
@ -102,7 +116,9 @@ static void walk_instructions(struct ir* ir, int goal)
if (!insndata->is_fragment)
{
if (insndata->emitter)
/* 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);

View file

@ -69,6 +69,7 @@ PATTERNS
reg = in:REG4
with (reg == in)
emit "reg %reg"
cost 1;
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 */
static void emitinsndata(Rule rules)
{
@ -964,11 +1007,33 @@ 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. */
{
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])
@ -1024,17 +1089,6 @@ static void emitinsndata(Rule rules)
}
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");
}
}
r = r->link;
}
@ -1051,11 +1105,7 @@ static void emitinsndata(Rule rules)
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);

View file

@ -12,7 +12,6 @@
((size) == 0) ? 0 : \
(size-1)))
#define STATE_TYPE void*
typedef struct ir* NODEPTR_TYPE;
@ -30,9 +29,8 @@ struct burm_emitter_data
void (*emit_fragment)(struct ir* ir, int goal);
void (*emit_reg)(struct ir* ir, int goal);
void (*emit_value)(struct ir* ir);
void (*emit_resultreg)(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);