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; 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 : */ /* vim: set sw=4 ts=4 expandtab : */

View file

@ -82,7 +82,7 @@ struct basicblock
ARRAY(struct basicblock, outblocks); ARRAY(struct basicblock, outblocks);
ARRAY(struct ir, outs); ARRAY(struct ir, outs);
ARRAY(struct ir, ins); ARRAY(struct ir, ins);
bool is_wired : 1; bool is_root : 1;
bool is_terminated : 1; bool is_terminated : 1;
}; };
@ -105,7 +105,6 @@ extern void data_bss(arith size, int init);
extern void bb_init(void); extern void bb_init(void);
extern struct basicblock* bb_get(const char* name); extern struct basicblock* bb_get(const char* name);
extern void bb_alias(struct basicblock* block, 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_filestart(void);
extern void tb_fileend(void); extern void tb_fileend(void);

View file

@ -2,7 +2,8 @@
static struct e_instr insn; static struct e_instr insn;
static struct procedure* current_proc; 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 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) static void terminate_block(void)
{ {
current_bb->is_terminated = true; code_bb->is_terminated = true;
current_bb = NULL; code_bb = NULL;
} }
static struct insn* new_insn(int opcode) static struct insn* new_insn(int opcode)
@ -76,7 +77,7 @@ static void queue_insn_simple(int opcode)
{ {
struct insn* insn = new_insn(opcode); struct insn* insn = new_insn(opcode);
insn->paramtype = PARAM_NONE; insn->paramtype = PARAM_NONE;
APPEND(current_bb->insns, insn); APPEND(code_bb->insns, insn);
switch (opcode) switch (opcode)
{ {
@ -88,29 +89,17 @@ static void queue_insn_simple(int opcode)
static void queue_insn_value(int opcode, arith value) 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) switch (opcode)
{ {
case op_csa: case op_csa:
case op_csb: case op_csb:
{ terminate_block();
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; 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->paramtype = PARAM_LVALUE;
insn->u.lvalue.label = label; insn->u.lvalue.label = label;
insn->u.lvalue.offset = offset; 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) 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->paramtype = PARAM_BVALUE;
insn->u.bvalue.left = left; insn->u.bvalue.left = left;
insn->u.bvalue.right = right; 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) 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(); terminate_block();
} }
@ -169,10 +168,10 @@ static void change_basicblock(struct basicblock* newbb)
{ {
APPENDU(current_proc->blocks, 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); queue_insn_block(op_bra, newbb, NULL);
current_bb = newbb; code_bb = newbb;
} }
static void queue_ilabel(arith label) static void queue_ilabel(arith label)
@ -242,8 +241,21 @@ static void parse_pseu(void)
break; break;
case ilb_ptyp: 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; break;
}
default: default:
unknown_type("con, rom"); unknown_type("con, rom");
@ -270,15 +282,16 @@ static void parse_pseu(void)
current_proc->name = strdup(insn.em_pnam); current_proc->name = strdup(insn.em_pnam);
current_proc->root_bb = bb_get(current_proc->name); current_proc->root_bb = bb_get(current_proc->name);
current_proc->nlocals = insn.em_nlocals; current_proc->nlocals = insn.em_nlocals;
current_bb = current_proc->root_bb; code_bb = current_proc->root_bb;
APPEND(current_proc->blocks, current_bb); code_bb->is_root = true;
APPEND(current_proc->blocks, code_bb);
break; break;
case ps_end: /* procedure end */ case ps_end: /* procedure end */
tb_procedure(current_proc); tb_procedure(current_proc);
current_proc = NULL; current_proc = NULL;
current_bb = NULL; code_bb = NULL;
break; break;
default: default:
@ -338,8 +351,12 @@ void parse_em(void)
break; break;
case EM_DEFDLB: 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; break;
}
case EM_DEFDNAM: case EM_DEFDNAM:
data_label(strdup(insn.em_dnam)); data_label(strdup(insn.em_dnam));
@ -350,7 +367,7 @@ void parse_em(void)
break; break;
case EM_MNEM: case EM_MNEM:
if (current_bb) if (code_bb)
{ {
int flags = em_flag[insn.em_opcode - sp_fmnem]; int flags = em_flag[insn.em_opcode - sp_fmnem];

View file

@ -85,7 +85,7 @@ static void materialise_stack(void)
{ {
int i; int i;
for (i=stackptr-1; i>=0; i--) for (i=0; i<stackptr; i++)
{ {
struct ir* ir = stack[i]; struct ir* ir = stack[i];
appendir( 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) static struct ir* convert(struct ir* src, int destsize, int opcode)
{ {
switch (src->size) 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* destsize = pop(EM_wordsize);
struct ir* srcsize = pop(EM_wordsize); struct ir* srcsize = pop(EM_wordsize);
@ -513,6 +527,42 @@ static void insn_ivalue(int opcode, arith value)
break; 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: default:
fatal("treebuilder: unknown ivalue instruction '%s'", fatal("treebuilder: unknown ivalue instruction '%s'",
em_mnem[opcode - sp_fmnem]); em_mnem[opcode - sp_fmnem]);
@ -525,11 +575,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
{ {
case op_lae: case op_lae:
push( push(
new_ir2( address_of_external(label, offset)
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
)
); );
break; break;
@ -537,11 +583,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
push( push(
new_ir1( new_ir1(
IR_LOAD, EM_wordsize, IR_LOAD, EM_wordsize,
new_ir2( address_of_external(label, offset)
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
)
) )
); );
break; break;
@ -550,11 +592,7 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
appendir( appendir(
new_ir2( new_ir2(
IR_STORE, EM_wordsize, IR_STORE, EM_wordsize,
new_ir2( address_of_external(label, offset),
IR_ADD, EM_pointersize,
new_labelir(label),
new_wordir(offset)
),
pop(EM_wordsize) pop(EM_wordsize)
) )
); );
@ -570,6 +608,17 @@ static void insn_lvalue(int opcode, const char* label, arith offset)
) )
); );
break; break;
case op_bra:
assert(offset == 0);
materialise_stack();
appendir(
new_ir1(
IR_JUMP, 0,
new_labelir(label)
)
);
break;
default: default:
fatal("treebuilder: unknown lvalue instruction '%s'", fatal("treebuilder: unknown lvalue instruction '%s'",
@ -582,6 +631,13 @@ static void generate_tree(struct basicblock* bb)
int i; int i;
printf("; BLOCK %s\n", bb->name); 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; current_bb = bb;
reset_stack(); reset_stack();
@ -623,6 +679,14 @@ static void generate_tree(struct basicblock* bb)
} }
assert(stackptr == 0); 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) void tb_procedure(struct procedure* current_proc)