Actually, I don't need vregs: hops work just as well. Particularly if I
restructure things so that I don't need to walk the blasted ir / burg tree every time I look at an instruction.
This commit is contained in:
parent
e77c5164cf
commit
4572f1b774
8 changed files with 166 additions and 94 deletions
|
@ -28,7 +28,6 @@ cprogram {
|
||||||
vars = {
|
vars = {
|
||||||
["+cflags"] = {
|
["+cflags"] = {
|
||||||
"-Werror-implicit-function-declaration",
|
"-Werror-implicit-function-declaration",
|
||||||
"-Wint-conversion"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
static char outbuf[256];
|
static int hop_count = 1;
|
||||||
static struct hop* current_hop;
|
static struct hop* current_hop;
|
||||||
|
|
||||||
static const struct burm_emitter_data emitter_data;
|
static const struct burm_emitter_data emitter_data;
|
||||||
|
@ -8,85 +8,97 @@ static const struct burm_emitter_data emitter_data;
|
||||||
struct hop* new_hop(int insn_no, struct ir* ir)
|
struct hop* new_hop(int insn_no, struct ir* ir)
|
||||||
{
|
{
|
||||||
struct hop* hop = calloc(1, sizeof *hop);
|
struct hop* hop = calloc(1, sizeof *hop);
|
||||||
|
hop->id = hop_count++;
|
||||||
hop->insn_no = insn_no;
|
hop->insn_no = insn_no;
|
||||||
hop->ir = ir;
|
hop->ir = ir;
|
||||||
return hop;
|
return hop;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append(const char* fmt, ...)
|
static struct insel* new_insel(enum insel_type type)
|
||||||
{
|
{
|
||||||
va_list ap;
|
struct insel* insel = calloc(1, sizeof(*insel));
|
||||||
|
insel->type = type;
|
||||||
va_start(ap, fmt);
|
return insel;
|
||||||
vsprintf(outbuf + strlen(outbuf), fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_reg(struct ir* ir)
|
void hop_add_string_insel(struct hop* hop, const char* string)
|
||||||
{
|
{
|
||||||
struct hop* hop = ir->hop;
|
struct insel* insel = new_insel(INSEL_STRING);
|
||||||
if (hop)
|
insel->u.string = string;
|
||||||
{
|
array_append(&hop->insels, insel);
|
||||||
/* Reference to another hop must be its result register. */
|
|
||||||
append("%%%d", hop->resultvreg->id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* ...if there is no hop, it's a fragment. */
|
|
||||||
const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no];
|
|
||||||
insndata->emitter(ir, &emitter_data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_string(const char* data)
|
void hop_add_reg_insel(struct hop* hop, struct hop* reg)
|
||||||
{
|
{
|
||||||
append("%s", data);
|
struct insel* insel = new_insel(INSEL_REG);
|
||||||
|
insel->u.reg = reg;
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_value(struct ir* ir)
|
void hop_add_value_insel(struct hop* hop, struct ir* ir)
|
||||||
{
|
{
|
||||||
append("(val)");
|
struct insel* insel = new_insel(INSEL_VALUE);
|
||||||
|
insel->u.value = ir;
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_resultreg(void)
|
void hop_add_eoi_insel(struct hop* hop)
|
||||||
{
|
{
|
||||||
append("%%%d", current_hop->resultvreg->id);
|
struct insel* insel = new_insel(INSEL_EOI);
|
||||||
|
array_append(&hop->insels, insel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_eoi(void)
|
|
||||||
{
|
|
||||||
append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct burm_emitter_data emitter_data =
|
|
||||||
{
|
|
||||||
&emit_string,
|
|
||||||
&emit_reg,
|
|
||||||
&emit_value,
|
|
||||||
&emit_resultreg,
|
|
||||||
&emit_eoi
|
|
||||||
};
|
|
||||||
|
|
||||||
void hop_print(char k, struct hop* hop)
|
void hop_print(char k, struct hop* hop)
|
||||||
{
|
{
|
||||||
char* s;
|
int i;
|
||||||
const struct burm_instruction_data* insndata = &burm_instruction_data[hop->insn_no];
|
bool soi = true;
|
||||||
|
|
||||||
current_hop = hop;
|
i = 0;
|
||||||
outbuf[0] = 0;
|
for (i=0; i<hop->insels.count; i++)
|
||||||
if (insndata->emitter)
|
|
||||||
{
|
{
|
||||||
insndata->emitter(hop->ir, &emitter_data);
|
struct insel* insel = hop->insels.item[i];
|
||||||
|
|
||||||
s = strtok(outbuf, "\n");
|
if (soi)
|
||||||
do
|
|
||||||
{
|
{
|
||||||
tracef(k, "%c: %p: %s\n", k, hop, s);
|
tracef(k, "%c: %d: ", k, hop->id);
|
||||||
s = strtok(NULL, "\n");
|
soi = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (insel->type)
|
||||||
|
{
|
||||||
|
case INSEL_EOI:
|
||||||
|
tracef(k, "\n");
|
||||||
|
soi = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSEL_REG:
|
||||||
|
tracef(k, "%%%d", insel->u.reg->id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSEL_STRING:
|
||||||
|
tracef(k, "%s", insel->u.string);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INSEL_VALUE:
|
||||||
|
{
|
||||||
|
struct ir* ir = insel->u.value;
|
||||||
|
switch (ir->opcode)
|
||||||
|
{
|
||||||
|
case IR_BLOCK:
|
||||||
|
tracef(k, "%s", ir->u.bvalue->name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IR_LOCAL:
|
||||||
|
case IR_CONST:
|
||||||
|
tracef(k, "0x%d", ir->u.ivalue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (s);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
tracef(k, "%c: %p: (empty)\n", k, hop);
|
if (!soi)
|
||||||
|
tracef(k, "\n", k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,43 @@
|
||||||
#ifndef HOP_H
|
#ifndef HOP_H
|
||||||
#define HOP_H
|
#define HOP_H
|
||||||
|
|
||||||
|
enum insel_type
|
||||||
|
{
|
||||||
|
INSEL_STRING,
|
||||||
|
INSEL_REG,
|
||||||
|
INSEL_VALUE,
|
||||||
|
INSEL_EOI
|
||||||
|
};
|
||||||
|
|
||||||
|
struct insel
|
||||||
|
{
|
||||||
|
enum insel_type type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
const char* string;
|
||||||
|
struct hop* reg;
|
||||||
|
struct ir* value;
|
||||||
|
}
|
||||||
|
u;
|
||||||
|
};
|
||||||
|
|
||||||
struct hop
|
struct hop
|
||||||
{
|
{
|
||||||
|
int id;
|
||||||
int insn_no;
|
int insn_no;
|
||||||
struct ir* ir;
|
struct ir* ir;
|
||||||
struct vreg* resultvreg;
|
struct hop* result;
|
||||||
ARRAYOF(struct vreg) invregs;
|
ARRAYOF(struct hop) params;
|
||||||
ARRAYOF(struct vreg) outvregs;
|
ARRAYOF(struct insel) insels;
|
||||||
ARRAYOF(struct vreg) newvregs;
|
|
||||||
ARRAYOF(struct vreg) deadvregs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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_reg_insel(struct hop* hop, struct hop* reg);
|
||||||
|
extern void hop_add_value_insel(struct hop* hop, struct ir* ir);
|
||||||
|
extern void hop_add_eoi_insel(struct hop* hop);
|
||||||
|
|
||||||
extern void hop_print(char k, struct hop* hop);
|
extern void hop_print(char k, struct hop* hop);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
#include "ir.h"
|
#include "ir.h"
|
||||||
#include "mcgg.h"
|
#include "mcgg.h"
|
||||||
#include "vreg.h"
|
|
||||||
#include "hop.h"
|
#include "hop.h"
|
||||||
|
|
||||||
extern char em_pseu[][4];
|
extern char em_pseu[][4];
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "mcg.h"
|
#include "mcg.h"
|
||||||
|
|
||||||
static struct basicblock* current_bb;
|
static struct basicblock* current_bb;
|
||||||
|
static struct hop* current_hop;
|
||||||
|
|
||||||
|
static const struct burm_emitter_data emitter_data;
|
||||||
|
|
||||||
void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) {
|
void burm_trace(struct ir* p, int ruleno, int cost, int bestcost) {
|
||||||
const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
|
const struct burm_instruction_data* insndata = &burm_instruction_data[ruleno];
|
||||||
|
@ -16,28 +19,67 @@ void burm_panic_cannot_match(struct ir* ir)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void walk_instructions(struct hop* hop, struct ir* ir, int goal)
|
static void emit_reg(struct ir* ir)
|
||||||
|
{
|
||||||
|
if (ir->hop)
|
||||||
|
hop_add_reg_insel(current_hop, ir->hop);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const struct burm_instruction_data* insndata = &burm_instruction_data[ir->insn_no];
|
||||||
|
if (insndata->emitter)
|
||||||
|
insndata->emitter(ir, &emitter_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_string(const char* data)
|
||||||
|
{
|
||||||
|
hop_add_string_insel(current_hop, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_value(struct ir* ir)
|
||||||
|
{
|
||||||
|
hop_add_value_insel(current_hop, ir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_resultreg(void)
|
||||||
|
{
|
||||||
|
hop_add_reg_insel(current_hop, current_hop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_eoi(void)
|
||||||
|
{
|
||||||
|
hop_add_eoi_insel(current_hop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct burm_emitter_data emitter_data =
|
||||||
|
{
|
||||||
|
&emit_string,
|
||||||
|
&emit_reg,
|
||||||
|
&emit_value,
|
||||||
|
&emit_resultreg,
|
||||||
|
&emit_eoi
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void walk_instructions(struct ir* ir, int goal)
|
||||||
{
|
{
|
||||||
struct ir* children[10];
|
struct ir* children[10];
|
||||||
int insn_no = burm_rule(ir->state_label, goal);
|
int insn_no = burm_rule(ir->state_label, goal);
|
||||||
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
|
const struct burm_instruction_data* insndata = &burm_instruction_data[insn_no];
|
||||||
const short* nts = burm_nts[insn_no];
|
const short* nts = burm_nts[insn_no];
|
||||||
|
struct hop* parent_hop = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ir->insn_no = insn_no;
|
ir->insn_no = insn_no;
|
||||||
if (!insndata->is_fragment)
|
if (!insndata->is_fragment)
|
||||||
hop = ir->hop = new_hop(insn_no, ir);;
|
|
||||||
|
|
||||||
if (insndata->allocate)
|
|
||||||
{
|
{
|
||||||
hop->resultvreg = new_vreg();
|
parent_hop = current_hop;
|
||||||
array_append(&hop->newvregs, hop->resultvreg);
|
current_hop = ir->hop = new_hop(insn_no, ir);
|
||||||
array_append(&hop->outvregs, hop->resultvreg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
burm_kids(ir, insn_no, children);
|
burm_kids(ir, insn_no, children);
|
||||||
for (i=0; nts[i]; i++)
|
for (i=0; nts[i]; i++)
|
||||||
walk_instructions(hop, children[i], nts[i]);
|
walk_instructions(children[i], nts[i]);
|
||||||
|
|
||||||
ir->is_generated = true;
|
ir->is_generated = true;
|
||||||
|
|
||||||
|
@ -50,8 +92,12 @@ static void walk_instructions(struct hop* hop, struct ir* ir, int goal)
|
||||||
|
|
||||||
if (!insndata->is_fragment)
|
if (!insndata->is_fragment)
|
||||||
{
|
{
|
||||||
array_append(¤t_bb->hops, hop);
|
if (insndata->emitter)
|
||||||
hop_print('I', hop);
|
insndata->emitter(ir, &emitter_data);
|
||||||
|
|
||||||
|
hop_print('I', current_hop);
|
||||||
|
array_append(¤t_bb->hops, current_hop);
|
||||||
|
current_hop = parent_hop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +119,7 @@ static void select_instructions(void)
|
||||||
burm_panic_cannot_match(ir);
|
burm_panic_cannot_match(ir);
|
||||||
|
|
||||||
ir_print('I', ir);
|
ir_print('I', ir);
|
||||||
walk_instructions(NULL, ir, 1);
|
walk_instructions(ir, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ DECLARATIONS
|
||||||
aluparam fragment;
|
aluparam fragment;
|
||||||
reg allocates(GPR);
|
reg allocates(GPR);
|
||||||
tristate allocates(CC);
|
tristate allocates(CC);
|
||||||
|
bistate allocates(CC);
|
||||||
|
|
||||||
PATTERNS
|
PATTERNS
|
||||||
|
|
||||||
|
@ -105,6 +106,11 @@ PATTERNS
|
||||||
emit "b $false"
|
emit "b $false"
|
||||||
cost 8;
|
cost 8;
|
||||||
|
|
||||||
|
CJUMPEQ(value:bistate, PAIR(true:BLOCK4, false:BLOCK4))
|
||||||
|
emit "beq $true"
|
||||||
|
emit "b $false"
|
||||||
|
cost 8;
|
||||||
|
|
||||||
|
|
||||||
/* Comparisons */
|
/* Comparisons */
|
||||||
|
|
||||||
|
@ -112,12 +118,21 @@ PATTERNS
|
||||||
emit "cmp %left, %right"
|
emit "cmp %left, %right"
|
||||||
cost 4;
|
cost 4;
|
||||||
|
|
||||||
|
bistate = COMPARES4(COMPARES4(left:reg, right:aluparam), CONST4)
|
||||||
|
emit "cmp %left, %right"
|
||||||
|
cost 4;
|
||||||
|
|
||||||
reg = tristate
|
reg = tristate
|
||||||
emit "mov %reg, #0"
|
emit "mov %reg, #0"
|
||||||
emit "movlt %reg, #-1"
|
emit "movlt %reg, #-1"
|
||||||
emit "movgt %reg, #1"
|
emit "movgt %reg, #1"
|
||||||
cost 12;
|
cost 12;
|
||||||
|
|
||||||
|
reg = bistate
|
||||||
|
emit "moveq %reg, #1"
|
||||||
|
emit "movne %reg, #0"
|
||||||
|
cost 8;
|
||||||
|
|
||||||
|
|
||||||
/* Conversions */
|
/* Conversions */
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#include "mcg.h"
|
|
||||||
|
|
||||||
static int vreg_count = 0;
|
|
||||||
|
|
||||||
struct vreg* new_vreg(void)
|
|
||||||
{
|
|
||||||
struct vreg* vreg = calloc(1, sizeof *vreg);
|
|
||||||
vreg->id = vreg_count++;
|
|
||||||
return vreg;
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef VREG_H
|
|
||||||
#define VREG_H
|
|
||||||
|
|
||||||
struct vreg
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct vreg* new_vreg(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue