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:
parent
3aa30e50d1
commit
288ee56203
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "ir.h"
|
||||
#include "mcgg.h"
|
||||
#include "hop.h"
|
||||
#include "vreg.h"
|
||||
#include "basicblock.h"
|
||||
#include "procedure.h"
|
||||
|
||||
|
|
|
@ -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(¤t_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(¤t_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(¤t_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);
|
||||
|
|
|
@ -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
10
mach/proto/mcg/vreg.c
Normal 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
12
mach/proto/mcg/vreg.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef VREG_H
|
||||
#define VREG_H
|
||||
|
||||
struct vreg
|
||||
{
|
||||
int id;
|
||||
};
|
||||
|
||||
extern struct vreg* new_vreg(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue