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:
David Given 2016-09-20 00:19:39 +02:00
parent dcba03646b
commit 36d7d1ee4e
4 changed files with 134 additions and 82 deletions

View file

@ -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 : */

View file

@ -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);

View file

@ -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];

View file

@ -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)