Create hacky fake basic blocks for data fragments, used to track which
instruction labels descriptor blocks refer to; this allows csa and csb to know where they're going.
This commit is contained in:
parent
dcba03646b
commit
36d7d1ee4e
4 changed files with 134 additions and 82 deletions
|
@ -39,32 +39,4 @@ void bb_alias(struct basicblock* block, const char* name)
|
|||
p->block = block;
|
||||
}
|
||||
|
||||
void bb_wire_outs_to_ins(struct basicblock* inblock, struct basicblock* outblock)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!outblock->is_wired)
|
||||
{
|
||||
for (i=0; i<inblock->outs_count; i++)
|
||||
{
|
||||
struct ir* value = inblock->outs[i];
|
||||
APPEND(outblock->ins,
|
||||
new_phiir(value->size)
|
||||
);
|
||||
}
|
||||
outblock->is_wired = true;
|
||||
}
|
||||
|
||||
assert(inblock->outs_count == outblock->ins_count);
|
||||
for (i=0; i<inblock->outs_count; i++)
|
||||
{
|
||||
struct ir* srcvalue = inblock->outs[i];
|
||||
struct ir* destvalue = outblock->ins[i];
|
||||
assert(srcvalue->size == destvalue->size);
|
||||
assert(destvalue->opcode == IR_PHI);
|
||||
|
||||
APPENDU(destvalue->u.phivalue.srcs, srcvalue);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
|
@ -82,7 +82,7 @@ struct basicblock
|
|||
ARRAY(struct basicblock, outblocks);
|
||||
ARRAY(struct ir, outs);
|
||||
ARRAY(struct ir, ins);
|
||||
bool is_wired : 1;
|
||||
bool is_root : 1;
|
||||
bool is_terminated : 1;
|
||||
};
|
||||
|
||||
|
@ -105,7 +105,6 @@ extern void data_bss(arith size, int init);
|
|||
extern void bb_init(void);
|
||||
extern struct basicblock* bb_get(const char* name);
|
||||
extern void bb_alias(struct basicblock* block, const char* name);
|
||||
extern void bb_wire_outs_to_ins(struct basicblock* outblock, struct basicblock* inblock);
|
||||
|
||||
extern void tb_filestart(void);
|
||||
extern void tb_fileend(void);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
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);
|
||||
|
||||
|
@ -61,8 +62,8 @@ static const char* dlabel_to_str(label l)
|
|||
|
||||
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)
|
||||
|
@ -76,7 +77,7 @@ static void queue_insn_simple(int opcode)
|
|||
{
|
||||
struct insn* insn = new_insn(opcode);
|
||||
insn->paramtype = PARAM_NONE;
|
||||
APPEND(current_bb->insns, insn);
|
||||
APPEND(code_bb->insns, insn);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
|
@ -88,29 +89,17 @@ static void queue_insn_simple(int 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,7 +109,14 @@ static void queue_insn_label(int opcode, const char* label, arith offset)
|
|||
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)
|
||||
|
@ -129,12 +125,15 @@ static void queue_insn_block(int opcode, struct basicblock* left, struct basicbl
|
|||
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();
|
||||
}
|
||||
|
@ -169,10 +168,10 @@ static void change_basicblock(struct basicblock* newbb)
|
|||
{
|
||||
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)
|
||||
|
@ -242,8 +241,21 @@ static void parse_pseu(void)
|
|||
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");
|
||||
|
@ -270,15 +282,16 @@ static void parse_pseu(void)
|
|||
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:
|
||||
|
@ -338,8 +351,12 @@ void parse_em(void)
|
|||
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));
|
||||
|
@ -350,7 +367,7 @@ void parse_em(void)
|
|||
break;
|
||||
|
||||
case EM_MNEM:
|
||||
if (current_bb)
|
||||
if (code_bb)
|
||||
{
|
||||
int flags = em_flag[insn.em_opcode - sp_fmnem];
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ static void materialise_stack(void)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i=stackptr-1; i>=0; i--)
|
||||
for (i=0; i<stackptr; i++)
|
||||
{
|
||||
struct ir* ir = stack[i];
|
||||
appendir(
|
||||
|
@ -122,6 +122,20 @@ static struct ir* address_of_local(int index)
|
|||
);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -153,7 +167,7 @@ static struct ir* tristate_compare(int size, int opcode)
|
|||
);
|
||||
}
|
||||
|
||||
static void simple_convert(opcode)
|
||||
static void simple_convert(int opcode)
|
||||
{
|
||||
struct ir* destsize = pop(EM_wordsize);
|
||||
struct ir* srcsize = pop(EM_wordsize);
|
||||
|
@ -513,6 +527,42 @@ static void insn_ivalue(int opcode, arith value)
|
|||
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]);
|
||||
|
@ -525,11 +575,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
{
|
||||
case op_lae:
|
||||
push(
|
||||
new_ir2(
|
||||
IR_ADD, EM_pointersize,
|
||||
new_labelir(label),
|
||||
new_wordir(offset)
|
||||
)
|
||||
address_of_external(label, offset)
|
||||
);
|
||||
break;
|
||||
|
||||
|
@ -537,11 +583,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
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;
|
||||
|
@ -550,11 +592,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
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)
|
||||
)
|
||||
);
|
||||
|
@ -570,6 +608,17 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
|
|||
)
|
||||
);
|
||||
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'",
|
||||
|
@ -582,6 +631,13 @@ static void generate_tree(struct basicblock* bb)
|
|||
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();
|
||||
|
||||
|
@ -623,6 +679,14 @@ static void generate_tree(struct basicblock* bb)
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue