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);
|
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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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[];
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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(¤t_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(¤t_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(¤t_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);
|
||||||
|
|
|
@ -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
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 */
|
/* 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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue