static struct procedure* current_proc;
static struct basicblock* current_bb;
+static void queue_insn_label(int opcode, const char* label, arith offset);
+
static const char* type_to_str(int type)
{
switch (type)
return aprintf("__D%d", l);
}
+static void terminate_block(void)
+{
+ current_bb->is_terminated = true;
+ current_bb = NULL;
+}
+
static struct insn* new_insn(int opcode)
{
struct insn* insn = calloc(sizeof(struct insn), 1);
switch (opcode)
{
- case op_ret:
- current_bb->is_terminated = true;
- current_bb = NULL;
+ case op_bra:
+ terminate_block();
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);
+ switch (opcode)
+ {
+ case op_csa:
+ case op_csb:
+ {
+ const char* helper = aprintf(".%s%d",
+ (opcode == op_csa) ? "csa" : "csb",
+ value);
+
+ queue_insn_label(op_cal, helper, 0);
+ queue_insn_value(op_asp, value + EM_pointersize);
+ queue_insn_value(op_lfr, value);
+ queue_insn_simple(op_bra);
+ break;
+ }
+
+ default:
+ {
+ 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)
APPENDU(current_bb->outblocks, right);
APPENDU(current_bb->inblocks, current_bb);
- current_bb->is_terminated = true;
- current_bb = NULL;
+ terminate_block();
}
static void queue_insn_ilabel(int opcode, int label)
* first. */
if (ir->size < EM_wordsize)
- ir = convert(ir, EM_wordsize, IR_FROMU1);
+ ir = convert(ir, EM_wordsize, IR_CIU1);
stack[stackptr++] = ir;
}
/* 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);
+ ir = convert(ir, size, IR_CIU1);
if (ir->size != size)
fatal("expected an item on stack of size %d, but got %d\n", size, ir->size);
);
}
+static void simple_convert(opcode)
+{
+ 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(value, destsize->u.ivalue, opcode)
+ );
+}
+
static void insn_simple(int opcode)
{
switch (opcode)
{
- case op_cii:
+ case op_bra:
{
- 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);
+ struct ir* dest = pop(EM_pointersize);
- value = pop(srcsize->u.ivalue);
- push(
- convert(value, destsize->u.ivalue, IR_FROMI1)
+ materialise_stack();
+ appendir(
+ new_ir1(
+ IR_JUMP, 0,
+ dest
+ )
);
break;
}
+
+ case op_cii: simple_convert(IR_CII1); break;
+ case op_ciu: simple_convert(IR_CIU1); break;
case op_cmp:
push(
);
break;
+ case op_cai:
+ {
+ struct ir* dest = pop(EM_pointersize);
+
+ materialise_stack();
+ appendir(
+ new_ir1(
+ IR_CALL, 0,
+ dest
+ )
+ );
+ break;
+ }
+
default:
fatal("treebuilder: unknown simple instruction '%s'",
em_mnem[opcode - sp_fmnem]);
case op_rmi: simple_alu2(opcode, value, IR_MOD); break;
case op_ngi: simple_alu1(opcode, value, IR_NEG); break;
+ case op_and: simple_alu2(opcode, value, IR_AND); break;
+ case op_ior: simple_alu2(opcode, value, IR_OR); break;
+ case op_xor: simple_alu2(opcode, value, IR_EOR); break;
+ case op_com: simple_alu1(opcode, value, IR_NOT); break;
+
case op_lol:
push(
new_ir1(
struct ir* ptr = pop(EM_pointersize);
if (value != EM_pointersize)
- off = convert(off, EM_pointersize, IR_FROMI1);
+ off = convert(off, EM_pointersize, IR_CII1);
push(
new_ir2(
);
if (value != EM_pointersize)
- delta = convert(delta, value, IR_FROMI1);
+ delta = convert(delta, value, IR_CII1);
push(delta);
break;