Store the EM code up front and build the basic block graph *before*

generating the IR code. Lots more IR code.
This commit is contained in:
David Given 2016-09-19 23:06:59 +02:00
parent 176cd7365c
commit 6ce2495aeb
7 changed files with 589 additions and 281 deletions

View file

@ -29,7 +29,10 @@ cprogram {
"./*.h",
},
vars = {
["+cflags"] = {"-Werror-implicit-function-declaration"}
["+cflags"] = {
"-Werror-implicit-function-declaration",
"-Wint-conversion"
}
}
}

View file

@ -8,42 +8,23 @@ struct ir* new_ir0(int opcode, int size)
ir->id = next_id++;
ir->opcode = opcode;
ir->size = size;
switch (ir->opcode)
{
case IR_JUMP:
case IR_CJUMP:
ir->terminates = true;
break;
}
return ir;
}
struct ir* new_ir1(int opcode, int size,
struct ir* c1)
struct ir* left)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
ir->left = left;
return ir;
}
struct ir* new_ir2(int opcode, int size,
struct ir* c1, struct ir* c2)
struct ir* left, struct ir* right)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
ir->children[1] = c2;
return ir;
}
struct ir* new_ir3(int opcode, int size,
struct ir* c1, struct ir* c2, struct ir* c3)
{
struct ir* ir = new_ir0(opcode, size);
ir->children[0] = c1;
ir->children[1] = c2;
ir->children[2] = c3;
ir->left = left;
ir->right = right;
return ir;
}
@ -87,15 +68,13 @@ struct ir* new_phiir(int size)
void ir_print(const struct ir* ir)
{
int i;
for (i=0; i<sizeof(ir->children)/sizeof(*ir->children); i++)
{
if (ir->children[i])
ir_print(ir->children[i]);
}
if (ir->left)
ir_print(ir->left);
if (ir->right)
ir_print(ir->right);
printf("\t; %c ",
ir->sequence ? 'S' : ' ');
ir->is_sequence ? 'S' : ' ');
printf("$%d = ", ir->id);
printf("%s%d(",
ir_names[ir->opcode],
@ -120,15 +99,10 @@ void ir_print(const struct ir* ir)
break;
default:
for (i=0; i<sizeof(ir->children)/sizeof(*ir->children); i++)
{
if (ir->children[i])
{
if (i > 0)
printf(", ");
printf("$%d", ir->children[i]->id);
}
}
if (ir->left)
printf("$%d", ir->left->id);
if (ir->right)
printf(", $%d", ir->right->id);
}
printf(")\n");

View file

@ -3,15 +3,26 @@ ICONST
REG
LABEL
BLOCK
PAIR
ANY
PHI
# Magic stack operations
PUSH
POP
# Memory operations
LOAD
STORE
# Arithemetic operations
ADD
SUB
MUL
DIV
MOD
NEG
NOT
# Conversions
FROMI1
@ -19,15 +30,27 @@ FROMI2
FROMI4
FROMI8
# Comparisons
FROMU1
FROMU2
FROMU4
FROMU8
# Tristate comparisons
COMPARES
COMPAREU
# Boolean comparisons
IFEQ
IFLT
IFLE
# Flow control
CALL
JUMP
CJUMP
RET
# Special
SETREG
GETREG

View file

@ -16,7 +16,8 @@ struct ir
int id;
int opcode;
int size;
struct ir* children[3];
struct ir* left;
struct ir* right;
union {
arith ivalue;
int rvalue;
@ -26,8 +27,7 @@ struct ir
ARRAY(struct ir, srcs);
} phivalue;
} u;
bool sequence : 1;
bool terminates : 1;
bool is_sequence : 1;
};
extern const char* ir_names[];
@ -37,8 +37,6 @@ extern struct ir* new_ir1(int opcode, int size,
struct ir* c1);
extern struct ir* new_ir2(int opcode, int size,
struct ir* c1, struct ir* c2);
extern struct ir* new_ir3(int opcode, int size,
struct ir* c1, struct ir* c2, struct ir* c3);
extern struct ir* new_labelir(const char* label);
extern struct ir* new_regir(int reg);

View file

@ -31,7 +31,8 @@ enum {
SECTION_TEXT
};
struct symbol {
struct symbol
{
const char* name;
int section;
bool is_defined : 1;
@ -39,20 +40,50 @@ struct symbol {
bool is_proc : 1;
};
enum {
enum
{
PARAM_NONE,
PARAM_VALUE,
PARAM_LABEL
PARAM_IVALUE,
PARAM_LVALUE,
PARAM_BVALUE,
};
struct basicblock {
struct insn
{
int opcode;
int paramtype;
union {
arith ivalue;
struct {
const char* label;
arith offset;
} lvalue;
struct {
struct basicblock* left;
struct basicblock* right;
} bvalue;
} u;
};
struct procedure
{
const char* name;
struct basicblock* root_bb;
size_t nlocals;
ARRAY(struct basicblock, blocks);
};
struct basicblock
{
const char* name;
ARRAY(struct insn, insns);
ARRAY(struct ir, irs);
ARRAY(struct basicblock, inblocks);
ARRAY(struct basicblock, outblocks);
ARRAY(struct ir, outs);
ARRAY(struct ir, ins);
bool is_wired : 1;
bool is_terminated : 1;
};
extern void fatal(const char* s, ...);
@ -78,15 +109,9 @@ extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock*
extern void tb_filestart(void);
extern void tb_fileend(void);
extern void tb_ilabel(const char* label);
extern void tb_procstart(const char* label, size_t nlocals);
extern void tb_procend(void);
extern void tb_procedure(struct procedure* proc);
extern void tb_regvar(arith offset, int size, int type, int priority);
extern void tb_insn_simple(int opcode, int flags);
extern void tb_insn_label(int opcode, int flags, const char* label, arith offset);
extern void tb_insn_value(int opcode, int flags, arith value);
#endif
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -1,7 +1,8 @@
#include "mcg.h"
static struct e_instr insn;
static const char* current_proc;
static struct procedure* current_proc;
static struct basicblock* current_bb;
static const char* type_to_str(int type)
{
@ -48,7 +49,7 @@ static void unknown_type(const char* s)
static const char* ilabel_to_str(label l)
{
assert(current_proc != NULL);
return aprintf("__%s_I%d", current_proc, l);
return aprintf("__%s_I%d", current_proc->name, l);
}
static const char* dlabel_to_str(label l)
@ -56,6 +57,103 @@ static const char* dlabel_to_str(label l)
return aprintf("__D%d", l);
}
static struct insn* new_insn(int opcode)
{
struct insn* insn = calloc(sizeof(struct insn), 1);
insn->opcode = opcode;
return insn;
}
static void queue_insn_simple(int opcode)
{
struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_NONE;
APPEND(current_bb->insns, insn);
switch (opcode)
{
case op_ret:
current_bb->is_terminated = true;
current_bb = NULL;
break;
}
}
static void queue_insn_value(int opcode, arith value)
{
struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_IVALUE;
insn->u.ivalue = value;
APPEND(current_bb->insns, insn);
}
static void queue_insn_label(int opcode, const char* label, arith offset)
{
struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_LVALUE;
insn->u.lvalue.label = label;
insn->u.lvalue.offset = offset;
APPEND(current_bb->insns, insn);
}
static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right)
{
struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_BVALUE;
insn->u.bvalue.left = left;
insn->u.bvalue.right = right;
APPEND(current_bb->insns, insn);
APPENDU(current_bb->outblocks, left);
if (right)
APPENDU(current_bb->outblocks, right);
APPENDU(current_bb->inblocks, current_bb);
current_bb->is_terminated = true;
current_bb = NULL;
}
static void queue_insn_ilabel(int opcode, int label)
{
const char* name = ilabel_to_str(insn.em_ilb);
struct basicblock* left = bb_get(name);
switch (opcode)
{
case op_bra:
queue_insn_block(insn.em_opcode, left, NULL);
break;
case op_zeq:
case op_zne:
case op_zlt:
case op_zle:
case op_zgt:
case op_zge:
queue_insn_block(insn.em_opcode, left, bb_get(NULL));
break;
default:
fatal("parse_em: unhandled conditional '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
static void change_basicblock(struct basicblock* newbb)
{
APPENDU(current_proc->blocks, newbb);
if (current_bb && !current_bb->is_terminated)
queue_insn_block(op_bra, newbb, NULL);
current_bb = newbb;
}
static void queue_ilabel(arith label)
{
change_basicblock(bb_get(ilabel_to_str(label)));
}
static void parse_pseu(void)
{
switch (insn.em_opcode)
@ -142,16 +240,19 @@ static void parse_pseu(void)
}
case ps_pro: /* procedure start */
if (insn.em_nlocals == -1)
fatal("procedures with unspecified number of locals are not supported yet");
current_proc = strdup(insn.em_pnam);
tb_procstart(current_proc, insn.em_nlocals);
current_proc = calloc(sizeof(struct procedure), 1);
current_proc->name = strdup(insn.em_pnam);
current_proc->root_bb = bb_get(current_proc->name);
current_proc->nlocals = insn.em_nlocals;
current_bb = current_proc->root_bb;
APPEND(current_proc->blocks, current_bb);
break;
case ps_end: /* procedure end */
tb_procend();
tb_procedure(current_proc);
current_proc = NULL;
current_bb = NULL;
break;
default:
@ -207,7 +308,7 @@ void parse_em(void)
break;
case EM_DEFILB:
tb_ilabel(ilabel_to_str(insn.em_ilb));
queue_ilabel(insn.em_ilb);
break;
case EM_DEFDLB:
@ -223,51 +324,48 @@ void parse_em(void)
break;
case EM_MNEM:
{
int flags = em_flag[insn.em_opcode - sp_fmnem];
if (flags & EM_PAR)
if (current_bb)
{
switch (insn.em_argtype)
int flags = em_flag[insn.em_opcode - sp_fmnem];
if (flags & EM_PAR)
{
case ilb_ptyp:
tb_insn_label(insn.em_opcode, flags,
ilabel_to_str(insn.em_ilb), 0);
break;
switch (insn.em_argtype)
{
case ilb_ptyp:
queue_insn_ilabel(insn.em_opcode, insn.em_ilb);
break;
case nof_ptyp:
tb_insn_label(insn.em_opcode, flags,
dlabel_to_str(insn.em_dlb), insn.em_off);
break;
case nof_ptyp:
queue_insn_label(insn.em_opcode,
dlabel_to_str(insn.em_dlb), insn.em_off);
break;
case sof_ptyp:
tb_insn_label(insn.em_opcode, flags,
strdup(insn.em_dnam), insn.em_off);
break;
case sof_ptyp:
queue_insn_label(insn.em_opcode,
strdup(insn.em_dnam), insn.em_off);
break;
case pro_ptyp:
tb_insn_label(insn.em_opcode, flags,
strdup(insn.em_pnam), 0);
break;
case pro_ptyp:
queue_insn_label(insn.em_opcode,
strdup(insn.em_pnam), 0);
break;
case cst_ptyp:
if ((flags & EM_PAR) == PAR_B)
tb_insn_label(insn.em_opcode, flags,
ilabel_to_str(insn.em_ilb), 0);
else
tb_insn_value(insn.em_opcode, flags,
insn.em_cst);
break;
case cst_ptyp:
if ((flags & EM_PAR) == PAR_B)
queue_insn_ilabel(insn.em_opcode, insn.em_ilb);
else
queue_insn_value(insn.em_opcode, insn.em_cst);
break;
default:
unknown_type("instruction");
default:
unknown_type("instruction");
}
}
else
queue_insn_simple(insn.em_opcode);
}
else
tb_insn_simple(insn.em_opcode, flags);
break;
}
default:
fatal("unrecognised instruction type '%d'", insn.em_type);

View file

@ -1,13 +1,15 @@
#include "mcg.h"
static struct symbol* currentproc;
static struct basicblock* rootbb;
static struct basicblock* currentbb;
static struct basicblock* current_bb;
static int stackptr;
static struct ir* stack[64];
static void resetstack(void)
static struct ir* convert(struct ir* src, int destsize, int opcode);
static struct ir* appendir(struct ir* ir);
static void reset_stack(void)
{
stackptr = 0;
}
@ -17,27 +19,86 @@ static void push(struct ir* ir)
if (stackptr == sizeof(stack)/sizeof(*stack))
fatal("stack overflow");
/* If we try to push something which is too small, convert it to a word
* first. */
if (ir->size < EM_wordsize)
ir = convert(ir, EM_wordsize, IR_FROMU1);
stack[stackptr++] = ir;
}
static struct ir* pop(void)
static struct ir* pop(int size)
{
if (stackptr == 0)
fatal("stack underflow");
{
/* Nothing in our fake stack, so we have to read from the real stack. */
return stack[--stackptr];
if (size < EM_wordsize)
size = EM_wordsize;
return
new_ir0(
IR_POP, size
);
}
else
{
struct ir* ir = stack[--stackptr];
/* If we try to pop something which is smaller than a word, convert it first. */
if (size < EM_wordsize)
ir = convert(ir, size, IR_FROMU1);
if (ir->size != size)
fatal("expected an item on stack of size %d, but got %d\n", size, ir->size);
return ir;
}
}
static void print_stack(void)
{
int i;
printf("\t; stack:");
for (i=0; i<stackptr; i++)
{
struct ir* ir = stack[i];
printf(" $%d.%d", ir->id, ir->size);
}
printf(" (top)\n");
}
static struct ir* appendir(struct ir* ir)
{
assert(currentbb != NULL);
ir->sequence = true;
APPEND(currentbb->irs, ir);
int i;
assert(current_bb != NULL);
ir->is_sequence = true;
APPEND(current_bb->irs, ir);
ir_print(ir);
return ir;
}
static void materialise_stack(void)
{
int i;
for (i=stackptr-1; i>=0; i--)
{
struct ir* ir = stack[i];
appendir(
new_ir1(
IR_PUSH, ir->size,
ir
)
);
}
reset_stack();
}
void tb_filestart(void)
{
}
@ -46,105 +107,6 @@ void tb_fileend(void)
{
}
static void materialise(void)
{
int i;
for (i=0; i<stackptr; i++)
appendir(stack[i]);
}
static void changeblock(struct basicblock* bb)
{
int i;
if (stackptr > 0)
{
printf("\t; block exiting with %d on stack:\n", stackptr);
for (i=0; i<stackptr; i++)
{
struct ir* ir = stack[i];
printf("\t; $%d size %d\n", ir->id, ir->size);
APPENDU(currentbb->outs, ir);
}
}
for (i=0; i<currentbb->outblocks_count; i++)
bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]);
currentbb = bb;
printf("; new block: %s\n", currentbb->name);
resetstack();
if (currentbb->ins_count > 0)
{
printf("\t; block entering with %d on stack:\n", currentbb->ins_count);
for (i=0; i<currentbb->ins_count; i++)
{
struct ir* ir = currentbb->ins[i];
printf("\t; $%d size %d\n", ir->id, ir->size);
push(ir);
}
}
}
void tb_ilabel(const char* label)
{
materialise();
#if 0
if (currentbb->irs_count == 0)
{
/* Current BB has no instructions, so just alias it to the
* new name.
*/
bb_alias(currentbb, label);
}
else
#endif
{
struct basicblock* newbb = bb_get(label);
if ((currentbb->irs_count == 0) ||
!currentbb->irs[currentbb->irs_count-1]->terminates)
{
APPEND(currentbb->outblocks, newbb);
appendir(
new_ir1(
IR_JUMP, 0,
new_labelir(label)
)
);
}
changeblock(newbb);
}
}
void tb_procstart(const char* label, size_t nlocals)
{
assert(currentproc == NULL);
currentproc = symbol_get(label);
currentproc->section = SECTION_TEXT;
rootbb = calloc(sizeof(struct basicblock), 1);
currentbb = rootbb;
resetstack();
}
void tb_procend(void)
{
assert(currentproc != NULL);
printf("\n.text\n");
printf("%s:\n", currentproc->name);
currentproc = NULL;
}
void tb_regvar(arith offset, int size, int type, int priority)
{
/* ignored */
@ -160,10 +122,29 @@ static struct ir* address_of_local(int index)
);
}
static struct ir* convert(struct ir* src, int destsize, int opcode)
{
switch (src->size)
{
case 1: opcode += 0; break;
case 2: opcode += 1; break;
case 4: opcode += 2; break;
case 8: opcode += 3; break;
default:
fatal("can't convert from things of size %d", src->size);
}
return
new_ir1(
opcode, destsize,
src
);
}
static struct ir* tristate_compare(int size, int opcode)
{
struct ir* right = pop();
struct ir* left = pop();
struct ir* right = pop(size);
struct ir* left = pop(size);
return
new_ir2(
@ -172,103 +153,140 @@ static struct ir* tristate_compare(int size, int opcode)
);
}
static struct ir* convert(int destsize, int srcsize, int opcode)
{
switch (srcsize)
{
case 1: opcode += 0; break;
case 2: opcode += 1; break;
case 4: opcode += 2; break;
case 8: opcode += 3; break;
default:
fatal("can't convert from things of size %d", srcsize);
}
return
new_ir1(
opcode, destsize,
pop()
);
}
void tb_insn_simple(int opcode, int flags)
static void insn_simple(int opcode)
{
switch (opcode)
{
case op_cii:
{
struct ir* destsize = pop();
struct ir* srcsize = pop();
struct ir* destsize = pop(EM_wordsize);
struct ir* srcsize = pop(EM_wordsize);
struct ir* value;
assert(srcsize->opcode == IR_ICONST);
assert(destsize->opcode == IR_ICONST);
value = pop(srcsize->u.ivalue);
push(
convert(destsize->u.ivalue, srcsize->u.ivalue, IR_FROMI1)
convert(value, destsize->u.ivalue, IR_FROMI1)
);
break;
}
case op_cmp:
push(
tristate_compare(EM_pointersize, IR_COMPAREU)
);
break;
default:
fatal("unknown insn_simple instruction '%s'",
fatal("treebuilder: unknown simple instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
void tb_insn_label(int opcode, int flags, const char* label, arith offset)
static void simple_branch2(int opcode, int size,
struct basicblock* truebb, struct basicblock* falsebb,
int irop)
{
materialise();
struct ir* right = pop(size);
struct ir* left = pop(size);
materialise_stack();
appendir(
new_ir2(
IR_CJUMP, 0,
new_ir2(
irop, size,
left, right
),
new_ir2(
IR_PAIR, 0,
new_bbir(truebb),
new_bbir(falsebb)
)
)
);
}
static void compare0_branch2(int opcode,
struct basicblock* truebb, struct basicblock* falsebb,
int irop)
{
push(
new_wordir(0)
);
simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop);
}
static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock* rightbb)
{
switch (opcode)
{
case op_zne:
{
struct basicblock* truebb = bb_get(label);
struct basicblock* falsebb = bb_get(NULL);
case op_zeq: compare0_branch2(opcode, leftbb, rightbb, IR_IFEQ); break;
case op_zlt: compare0_branch2(opcode, leftbb, rightbb, IR_IFLT); break;
case op_zle: compare0_branch2(opcode, leftbb, rightbb, IR_IFLE); break;
APPENDU(currentbb->outblocks, truebb);
APPENDU(currentbb->outblocks, falsebb);
appendir(
new_ir3(
IR_CJUMP, 0,
pop(),
new_bbir(truebb),
new_bbir(falsebb)
)
);
changeblock(falsebb);
break;
}
case op_zne: compare0_branch2(opcode, rightbb, leftbb, IR_IFEQ); break;
case op_zge: compare0_branch2(opcode, rightbb, leftbb, IR_IFLT); break;
case op_zgt: compare0_branch2(opcode, rightbb, leftbb, IR_IFLE); break;
case op_bra:
{
struct basicblock* destbb = bb_get(label);
APPENDU(currentbb->outblocks, destbb);
materialise_stack();
appendir(
new_ir1(
IR_JUMP, 0,
new_bbir(destbb)
new_bbir(leftbb)
)
);
break;
}
default:
fatal("unknown insn_label instruction '%s'",
fatal("treebuilder: unknown bvalue instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
void tb_insn_value(int opcode, int flags, arith value)
static void simple_alu1(int opcode, int size, int irop)
{
struct ir* left;
struct ir* right;
struct ir* val = pop(size);
push(
new_ir1(
irop, size,
val
)
);
}
static void simple_alu2(int opcode, int size, int irop)
{
struct ir* right = pop(size);
struct ir* left = pop(size);
push(
new_ir2(
irop, size,
left, right
)
);
}
static void insn_ivalue(int opcode, arith value)
{
switch (opcode)
{
case op_adi: simple_alu2(opcode, value, IR_ADD); break;
case op_sbi: simple_alu2(opcode, value, IR_SUB); break;
case op_mli: simple_alu2(opcode, value, IR_MUL); break;
case op_dvi: simple_alu2(opcode, value, IR_DIV); break;
case op_rmi: simple_alu2(opcode, value, IR_MOD); break;
case op_ngi: simple_alu1(opcode, value, IR_NEG); break;
case op_lol:
push(
new_ir1(
@ -283,11 +301,17 @@ void tb_insn_value(int opcode, int flags, arith value)
new_ir2(
IR_STORE, EM_wordsize,
address_of_local(value),
pop()
pop(EM_wordsize)
)
);
break;
case op_lal:
push(
address_of_local(value)
);
break;
case op_loc:
push(
new_wordir(value)
@ -298,22 +322,24 @@ void tb_insn_value(int opcode, int flags, arith value)
push(
new_ir1(
IR_LOAD, value,
pop()
pop(EM_pointersize)
)
);
break;
case op_sti:
right = pop();
left = pop();
{
struct ir* ptr = pop(EM_pointersize);
struct ir* val = pop(value);
appendir(
new_ir2(
IR_STORE, value,
right, left
ptr, val
)
);
break;
}
case op_cmi:
push(
@ -328,24 +354,59 @@ void tb_insn_value(int opcode, int flags, arith value)
break;
case op_ads:
right = pop();
left = pop();
{
struct ir* off = pop(value);
struct ir* ptr = pop(EM_pointersize);
if (value != EM_pointersize)
right = convert(EM_pointersize, value, IR_FROMI1);
off = convert(off, EM_pointersize, IR_FROMI1);
push(
new_ir2(
IR_ADD, EM_wordsize,
left, right
IR_ADD, EM_pointersize,
ptr, off
)
);
break;
}
case op_adp:
{
struct ir* ptr = pop(EM_pointersize);
push(
new_ir2(
IR_ADD, EM_pointersize,
ptr,
new_wordir(value)
)
);
break;
}
case op_sbs:
{
struct ir* right = pop(EM_pointersize);
struct ir* left = pop(EM_pointersize);
struct ir* delta =
new_ir2(
IR_SUB, EM_pointersize,
left, right
);
if (value != EM_pointersize)
delta = convert(delta, value, IR_FROMI1);
push(delta);
break;
}
case op_dup:
{
struct ir* v = pop();
appendir(v);
struct ir* v = pop(value);
if (!v->is_sequence)
appendir(v);
push(v);
push(v);
break;
@ -386,13 +447,12 @@ void tb_insn_value(int opcode, int flags, arith value)
{
if (value > 0)
{
left = pop();
assert(left->size == value);
struct ir* retval = pop(value);
appendir(
new_ir2(
IR_SETREG, value,
new_regir(IRR_RR),
left
retval
)
);
}
@ -405,11 +465,138 @@ void tb_insn_value(int opcode, int flags, arith value)
break;
}
case op_lfr:
{
push(
appendir(
new_ir1(
IR_GETREG, value,
new_regir(IRR_RR)
)
)
);
break;
}
default:
fatal("unknown insn_value instruction '%s'",
fatal("treebuilder: unknown ivalue instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
static void insn_lvalue(int opcode, const char* label, arith offset)
{
switch (opcode)
{
case op_lae:
push(
new_ir2(
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
)
);
break;
case op_loe:
push(
new_ir1(
IR_LOAD, EM_wordsize,
new_ir2(
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
)
)
);
break;
case op_ste:
appendir(
new_ir2(
IR_STORE, EM_wordsize,
new_ir2(
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
),
pop(EM_wordsize)
)
);
break;
case op_cal:
assert(offset == 0);
materialise_stack();
appendir(
new_ir1(
IR_CALL, 0,
new_labelir(label)
)
);
break;
default:
fatal("treebuilder: unknown lvalue instruction '%s'",
em_mnem[opcode - sp_fmnem]);
}
}
static void generate_tree(struct basicblock* bb)
{
int i;
printf("; BLOCK %s\n", bb->name);
current_bb = bb;
reset_stack();
for (i=0; i<bb->insns_count; i++)
{
struct insn* insn = bb->insns[i];
printf("\t; EM: %s ", em_mnem[insn->opcode - sp_fmnem]);
switch (insn->paramtype)
{
case PARAM_NONE:
printf("\n");
insn_simple(insn->opcode);
break;
case PARAM_IVALUE:
printf("value=%d\n", insn->u.ivalue);
insn_ivalue(insn->opcode, insn->u.ivalue);
break;
case PARAM_LVALUE:
printf("label=%s offset=%d\n",
insn->u.lvalue.label, insn->u.lvalue.offset);
insn_lvalue(insn->opcode, insn->u.lvalue.label, insn->u.lvalue.offset);
break;
case PARAM_BVALUE:
printf("true=%s", insn->u.bvalue.left->name);
if (insn->u.bvalue.right)
printf(" false=%s", insn->u.bvalue.right->name);
printf("\n");
insn_bvalue(insn->opcode, insn->u.bvalue.left, insn->u.bvalue.right);
break;
default:
assert(0);
}
print_stack();
}
assert(stackptr == 0);
}
void tb_procedure(struct procedure* current_proc)
{
int i;
for (i=0; i<current_proc->blocks_count; i++)
generate_tree(current_proc->blocks[i]);
}
/* vim: set sw=4 ts=4 expandtab : */