static struct e_instr insn;
static struct procedure* current_proc;
-static struct basicblock* current_bb;
+static struct basicblock* code_bb;
+static struct basicblock* data_bb;
static void queue_insn_label(int opcode, const char* label, arith offset);
static void terminate_block(void)
{
- current_bb->is_terminated = true;
- current_bb = NULL;
+ code_bb->is_terminated = true;
+ code_bb = NULL;
}
static struct insn* new_insn(int opcode)
{
struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_NONE;
- APPEND(current_bb->insns, insn);
+ APPEND(code_bb->insns, insn);
switch (opcode)
{
static void queue_insn_value(int opcode, arith value)
{
+ struct insn* insn = new_insn(opcode);
+ insn->paramtype = PARAM_IVALUE;
+ insn->u.ivalue = value;
+ APPEND(code_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);
+ terminate_block();
break;
- }
-
- default:
- {
- struct insn* insn = new_insn(opcode);
- insn->paramtype = PARAM_IVALUE;
- insn->u.ivalue = value;
- APPEND(current_bb->insns, insn);
- }
}
}
insn->paramtype = PARAM_LVALUE;
insn->u.lvalue.label = label;
insn->u.lvalue.offset = offset;
- APPEND(current_bb->insns, insn);
+ APPEND(code_bb->insns, insn);
+
+ switch (opcode)
+ {
+ case op_bra:
+ terminate_block();
+ break;
+ }
}
static void queue_insn_block(int opcode, struct basicblock* left, struct basicblock* right)
insn->paramtype = PARAM_BVALUE;
insn->u.bvalue.left = left;
insn->u.bvalue.right = right;
- APPEND(current_bb->insns, insn);
+ APPEND(code_bb->insns, insn);
- APPENDU(current_bb->outblocks, left);
+ APPENDU(code_bb->outblocks, left);
+ APPENDU(left->inblocks, code_bb);
if (right)
- APPENDU(current_bb->outblocks, right);
- APPENDU(current_bb->inblocks, current_bb);
+ {
+ APPENDU(code_bb->outblocks, right);
+ APPENDU(right->inblocks, code_bb);
+ }
terminate_block();
}
{
APPENDU(current_proc->blocks, newbb);
- if (current_bb && !current_bb->is_terminated)
+ if (code_bb && !code_bb->is_terminated)
queue_insn_block(op_bra, newbb, NULL);
- current_bb = newbb;
+ code_bb = newbb;
}
static void queue_ilabel(arith label)
break;
case ilb_ptyp:
- data_offset(ilabel_to_str(insn.em_ilb), 0, ro);
+ {
+ const char* label = ilabel_to_str(insn.em_ilb);
+
+ /* This is really hacky; to handle basic block flow
+ * descriptor blocks, we need to track which bbs a descriptor
+ * can exit to. So we create fake bb objects for each
+ * block, purely to track this.
+ */
+
+ if (data_bb)
+ APPENDU(data_bb->outblocks, bb_get(label));
+
+ data_offset(label, 0, ro);
break;
+ }
default:
unknown_type("con, rom");
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);
+ code_bb = current_proc->root_bb;
+ code_bb->is_root = true;
+ APPEND(current_proc->blocks, code_bb);
break;
case ps_end: /* procedure end */
tb_procedure(current_proc);
current_proc = NULL;
- current_bb = NULL;
+ code_bb = NULL;
break;
default:
break;
case EM_DEFDLB:
- data_label(dlabel_to_str(insn.em_dlb));
+ {
+ const char* label = dlabel_to_str(insn.em_dlb);
+ data_label(label);
+ data_bb = bb_get(label);
break;
+ }
case EM_DEFDNAM:
data_label(strdup(insn.em_dnam));
break;
case EM_MNEM:
- if (current_bb)
+ if (code_bb)
{
int flags = em_flag[insn.em_opcode - sp_fmnem];
{
int i;
- for (i=stackptr-1; i>=0; i--)
+ for (i=0; i<stackptr; i++)
{
struct ir* ir = stack[i];
appendir(
);
}
+static struct ir* address_of_external(const char* label, arith offset)
+{
+ if (offset != 0)
+ return
+ new_ir2(
+ IR_ADD, EM_pointersize,
+ new_labelir(label),
+ new_wordir(offset)
+ );
+ else
+ return
+ new_labelir(label);
+}
+
static struct ir* convert(struct ir* src, int destsize, int opcode)
{
switch (src->size)
);
}
-static void simple_convert(opcode)
+static void simple_convert(int opcode)
{
struct ir* destsize = pop(EM_wordsize);
struct ir* srcsize = pop(EM_wordsize);
break;
}
+ case op_csa:
+ case op_csb:
+ {
+ struct basicblock* data_bb;
+ int i;
+ const char* helper = aprintf(".%s%d",
+ (opcode == op_csa) ? "csa" : "csb",
+ value);
+ struct ir* descriptor = pop(EM_pointersize);
+
+ if (descriptor->opcode != IR_LABEL)
+ fatal("csa/csb are only supported if they refer "
+ "directly to a descriptor block");
+
+ /* Splice the outgoing bbs in the data block into our own. */
+
+ data_bb = bb_get(descriptor->u.lvalue);
+ for (i=0; i<data_bb->outblocks_count; i++)
+ {
+ struct basicblock* bb = data_bb->outblocks[i];
+ printf("\t; may jump to %s\n", bb->name);
+ APPENDU(current_bb->outblocks, bb);
+ APPENDU(bb->inblocks, current_bb);
+ }
+
+ push(descriptor);
+ materialise_stack();
+ appendir(
+ new_ir1(
+ IR_JUMP, 0,
+ new_labelir(helper)
+ )
+ );
+ break;
+ }
+
default:
fatal("treebuilder: unknown ivalue instruction '%s'",
em_mnem[opcode - sp_fmnem]);
{
case op_lae:
push(
- new_ir2(
- IR_ADD, EM_pointersize,
- new_labelir(label),
- new_wordir(offset)
- )
+ address_of_external(label, offset)
);
break;
push(
new_ir1(
IR_LOAD, EM_wordsize,
- new_ir2(
- IR_ADD, EM_pointersize,
- new_labelir(label),
- new_wordir(offset)
- )
+ address_of_external(label, offset)
)
);
break;
appendir(
new_ir2(
IR_STORE, EM_wordsize,
- new_ir2(
- IR_ADD, EM_pointersize,
- new_labelir(label),
- new_wordir(offset)
- ),
+ address_of_external(label, offset),
pop(EM_wordsize)
)
);
)
);
break;
+
+ case op_bra:
+ assert(offset == 0);
+ materialise_stack();
+ appendir(
+ new_ir1(
+ IR_JUMP, 0,
+ new_labelir(label)
+ )
+ );
+ break;
default:
fatal("treebuilder: unknown lvalue instruction '%s'",
int i;
printf("; BLOCK %s\n", bb->name);
+ if (bb->inblocks_count > 0)
+ {
+ printf("; Entered from:\n");
+ for (i=0; i<bb->inblocks_count; i++)
+ printf("; %s\n", bb->inblocks[i]->name);
+ }
+
current_bb = bb;
reset_stack();
}
assert(stackptr == 0);
+
+ if (bb->outblocks_count > 0)
+ {
+ printf("; Exiting to:\n");
+ for (i=0; i<bb->outblocks_count; i++)
+ printf("; %s\n", bb->outblocks[i]->name);
+ }
+ printf("\n");
}
void tb_procedure(struct procedure* current_proc)