From 6ce2495aeb46fc703c321a9817a2bf17540873ee Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 19 Sep 2016 23:06:59 +0200 Subject: [PATCH] Store the EM code up front and build the basic block graph *before* generating the IR code. Lots more IR code. --- mach/proto/mcg/build.lua | 5 +- mach/proto/mcg/ir.c | 54 +--- mach/proto/mcg/ir.dat | 25 +- mach/proto/mcg/ir.h | 8 +- mach/proto/mcg/mcg.h | 49 +++- mach/proto/mcg/parse_em.c | 196 ++++++++++---- mach/proto/mcg/treebuilder.c | 509 ++++++++++++++++++++++++----------- 7 files changed, 577 insertions(+), 269 deletions(-) diff --git a/mach/proto/mcg/build.lua b/mach/proto/mcg/build.lua index 5db304b46..c94d44ece 100644 --- a/mach/proto/mcg/build.lua +++ b/mach/proto/mcg/build.lua @@ -29,7 +29,10 @@ cprogram { "./*.h", }, vars = { - ["+cflags"] = {"-Werror-implicit-function-declaration"} + ["+cflags"] = { + "-Werror-implicit-function-declaration", + "-Wint-conversion" + } } } diff --git a/mach/proto/mcg/ir.c b/mach/proto/mcg/ir.c index 8973bfc73..814171586 100644 --- a/mach/proto/mcg/ir.c +++ b/mach/proto/mcg/ir.c @@ -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; ichildren)/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; ichildren)/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"); diff --git a/mach/proto/mcg/ir.dat b/mach/proto/mcg/ir.dat index 044f9c0f3..ea47cb0a0 100644 --- a/mach/proto/mcg/ir.dat +++ b/mach/proto/mcg/ir.dat @@ -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 diff --git a/mach/proto/mcg/ir.h b/mach/proto/mcg/ir.h index 33b892528..6574ecb80 100644 --- a/mach/proto/mcg/ir.h +++ b/mach/proto/mcg/ir.h @@ -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); diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 06e8160eb..ce332fff9 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -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 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 { +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 : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index 22ac92e81..9310dda40 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -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; - - case nof_ptyp: - tb_insn_label(insn.em_opcode, flags, - 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 pro_ptyp: - tb_insn_label(insn.em_opcode, flags, - 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; - - default: - unknown_type("instruction"); + switch (insn.em_argtype) + { + case ilb_ptyp: + queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + break; + + case nof_ptyp: + queue_insn_label(insn.em_opcode, + dlabel_to_str(insn.em_dlb), insn.em_off); + break; + + case sof_ptyp: + queue_insn_label(insn.em_opcode, + strdup(insn.em_dnam), insn.em_off); + 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) + queue_insn_ilabel(insn.em_opcode, insn.em_ilb); + else + queue_insn_value(insn.em_opcode, insn.em_cst); + break; + + 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); diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index c7abd5cc8..acd8f30cd 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -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,132 +19,92 @@ static void push(struct ir* ir) if (stackptr == sizeof(stack)/sizeof(*stack)) fatal("stack overflow"); - stack[stackptr++] = ir; -} + /* If we try to push something which is too small, convert it to a word + * first. */ -static struct ir* pop(void) -{ - if (stackptr == 0) - fatal("stack underflow"); + if (ir->size < EM_wordsize) + ir = convert(ir, EM_wordsize, IR_FROMU1); - return stack[--stackptr]; + stack[stackptr++] = ir; } -static struct ir* appendir(struct ir* ir) +static struct ir* pop(int size) { - assert(currentbb != NULL); - ir->sequence = true; - APPEND(currentbb->irs, ir); + if (stackptr == 0) + { + /* Nothing in our fake stack, so we have to read from the real stack. */ - ir_print(ir); - return ir; -} + if (size < EM_wordsize) + size = EM_wordsize; + return + new_ir0( + IR_POP, size + ); + } + else + { + struct ir* ir = stack[--stackptr]; -void tb_filestart(void) -{ -} + /* 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); -void tb_fileend(void) -{ + if (ir->size != size) + fatal("expected an item on stack of size %d, but got %d\n", size, ir->size); + return ir; + } } -static void materialise(void) +static void print_stack(void) { int i; + printf("\t; stack:"); for (i=0; iid, ir->size); + } + printf(" (top)\n"); } -static void changeblock(struct basicblock* bb) +static struct ir* appendir(struct ir* ir) { int i; - if (stackptr > 0) - { - printf("\t; block exiting with %d on stack:\n", stackptr); - for (i=0; iid, ir->size); - APPENDU(currentbb->outs, ir); - } - } - - for (i=0; ioutblocks_count; i++) - bb_wire_outs_to_ins(currentbb, currentbb->outblocks[i]); + assert(current_bb != NULL); + ir->is_sequence = true; + APPEND(current_bb->irs, ir); - 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; iins_count; i++) - { - struct ir* ir = currentbb->ins[i]; - printf("\t; $%d size %d\n", ir->id, ir->size); - push(ir); - } - } + ir_print(ir); + return ir; } -void tb_ilabel(const char* label) +static void materialise_stack(void) { - materialise(); + int i; - #if 0 - if (currentbb->irs_count == 0) + for (i=stackptr-1; i>=0; i--) { - /* Current BB has no instructions, so just alias it to the - * new name. - */ - bb_alias(currentbb, label); + struct ir* ir = stack[i]; + appendir( + new_ir1( + IR_PUSH, ir->size, + ir + ) + ); } - 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); - } + reset_stack(); } -void tb_procstart(const char* label, size_t nlocals) +void tb_filestart(void) { - assert(currentproc == NULL); - - currentproc = symbol_get(label); - currentproc->section = SECTION_TEXT; - - rootbb = calloc(sizeof(struct basicblock), 1); - currentbb = rootbb; - - resetstack(); } -void tb_procend(void) +void tb_fileend(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) @@ -160,115 +122,171 @@ static struct ir* address_of_local(int index) ); } -static struct ir* tristate_compare(int size, int opcode) +static struct ir* convert(struct ir* src, int destsize, int opcode) { - struct ir* right = pop(); - struct ir* left = pop(); - - return - new_ir2( - opcode, size, - left, right - ); -} - -static struct ir* convert(int destsize, int srcsize, int opcode) -{ - switch (srcsize) + 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", srcsize); + fatal("can't convert from things of size %d", src->size); } return new_ir1( opcode, destsize, - pop() + src + ); +} + +static struct ir* tristate_compare(int size, int opcode) +{ + struct ir* right = pop(size); + struct ir* left = pop(size); + + return + new_ir2( + opcode, size, + left, right ); } -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); - switch (opcode) - { - case op_zne: - { - struct basicblock* truebb = bb_get(label); - struct basicblock* falsebb = bb_get(NULL); + 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) + ) + ) + ); +} - APPENDU(currentbb->outblocks, truebb); - APPENDU(currentbb->outblocks, falsebb); +static void compare0_branch2(int opcode, + struct basicblock* truebb, struct basicblock* falsebb, + int irop) +{ + push( + new_wordir(0) + ); - appendir( - new_ir3( - IR_CJUMP, 0, - pop(), - new_bbir(truebb), - new_bbir(falsebb) - ) - ); + simple_branch2(opcode, EM_wordsize, truebb, falsebb, irop); +} - changeblock(falsebb); - break; - } +static void insn_bvalue(int opcode, struct basicblock* leftbb, struct basicblock* rightbb) +{ + switch (opcode) + { + 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; + + 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* val = pop(size); + + push( + new_ir1( + irop, size, + val + ) + ); +} + +static void simple_alu2(int opcode, int size, int irop) { - struct ir* left; - struct ir* right; + 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; iinsns_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; iblocks_count; i++) + generate_tree(current_proc->blocks[i]); +} + /* vim: set sw=4 ts=4 expandtab : */ -- 2.34.1