diff --git a/mach/proto/mcg/data.c b/mach/proto/mcg/data.c index cbf1cd04f..95d828650 100644 --- a/mach/proto/mcg/data.c +++ b/mach/proto/mcg/data.c @@ -59,7 +59,7 @@ void data_int(arith data, size_t size, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 1) || (size == 2) || (size == 4) || (size == 8)); - fprintf(outputfile, "\t.data%d ", size); + fprintf(outputfile, "\t.data%ld ", size); writehex(data, size); fprintf(outputfile, "\n"); } @@ -73,7 +73,7 @@ void data_float(const char* data, size_t size, bool is_ro) emit_header(is_ro ? SECTION_ROM : SECTION_DATA); assert((size == 4) || (size == 8)); - fprintf(outputfile, "\t.dataf%d %s\n", size, data); + fprintf(outputfile, "\t.dataf%ld %s\n", size, data); } static bool istext(c) @@ -130,7 +130,7 @@ void data_block(const uint8_t* data, size_t size, bool is_ro) void data_offset(const char* label, arith offset, bool is_ro) { emit_header(is_ro ? SECTION_ROM : SECTION_DATA); - fprintf(outputfile, "\t.data%d %s+%lld\n", + fprintf(outputfile, "\t.data%d %s+%ld\n", EM_pointersize, platform_label(label), offset); } @@ -140,7 +140,7 @@ void data_bss(arith size, int init) fatal("non-zero-initialised bss not supported"); emit_header(SECTION_BSS); - fprintf(outputfile, "\t.space %lld\n", size); + fprintf(outputfile, "\t.space %ld\n", size); } /* vim: set sw=4 ts=4 expandtab : */ diff --git a/mach/proto/mcg/parse_em.c b/mach/proto/mcg/parse_em.c index b66b177c4..bb6d6f108 100644 --- a/mach/proto/mcg/parse_em.c +++ b/mach/proto/mcg/parse_em.c @@ -181,6 +181,36 @@ static void queue_ilabel(arith label) change_basicblock(bb_get(ilabel_to_str(label))); } +/* This is really hacky; to handle basic block flow + * descriptor blocks, we need to be able to identify + * them, read them and parse them. So we create + * can exit to. So we create fake bb objects for each + * block, purely to track this, and copy ints and labels + * into them. + */ + +static void data_block_int(arith value) +{ + if (data_bb) + { + struct em* em = new_insn(op_loc); + em->paramtype = PARAM_IVALUE; + em->u.ivalue = value; + array_append(&data_bb->ems, em); + } +} + +static void data_block_label(const char* label) +{ + if (data_bb) + { + struct em* em = new_insn(op_bra); + em->paramtype = PARAM_BVALUE; + em->u.bvalue.left = bb_get(label); + array_append(&data_bb->ems, em); + } +} + static void parse_pseu(void) { switch (em.em_opcode) @@ -227,6 +257,7 @@ static void parse_pseu(void) { arith val = atol(em.em_string); data_int(val, em.em_size, ro); + data_block_int(val); break; } @@ -237,12 +268,16 @@ static void parse_pseu(void) } case str_ptyp: - data_block(strdup(em.em_string), em.em_size, ro); + data_block((const uint8_t*) strdup(em.em_string), em.em_size, ro); break; case cst_ptyp: - data_int(em.em_cst, EM_wordsize, ro); + { + arith value = em.em_cst; + data_int(value, EM_wordsize, ro); + data_block_int(value); break; + } case nof_ptyp: data_offset(dlabel_to_str(em.em_dlb), em.em_off, ro); @@ -256,22 +291,8 @@ static void parse_pseu(void) case ilb_ptyp: { const char* label = ilabel_to_str(em.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) - { - struct em* em = new_insn(op_bra); - em->paramtype = PARAM_BVALUE; - em->u.bvalue.left = bb_get(label); - array_append(&data_bb->ems, em); - } - data_offset(label, 0, ro); + data_block_label(label); break; } @@ -384,9 +405,12 @@ static void create_data_label(const char* label) data_label(label); if (current_proc) { + /* Create the fake bb used to track values inside this data block + * (as it's a chance it's a jump table which we'll need to process + * later). + */ data_bb = bb_get(label); data_bb->is_fake = true; - array_append(¤t_proc->blocks, data_bb); } } diff --git a/mach/proto/mcg/treebuilder.c b/mach/proto/mcg/treebuilder.c index 3328bf620..c1b5c7eb6 100644 --- a/mach/proto/mcg/treebuilder.c +++ b/mach/proto/mcg/treebuilder.c @@ -5,10 +5,20 @@ static struct basicblock* current_bb; static int stackptr; static struct ir* stack[64]; +struct jumptable +{ + struct basicblock* defaulttarget; + IMAPOF(struct basicblock) targets; +}; + static struct ir* convert(struct ir* src, int srcsize, int destsize, int opcode); static struct ir* appendir(struct ir* ir); static void insn_ivalue(int opcode, arith value); +static void parse_csa(struct basicblock* data_bb, struct jumptable* table); +static void parse_csb(struct basicblock* data_bb, struct jumptable* table); +static void emit_jumptable(struct ir* targetvalue, struct jumptable* table); + static void reset_stack(void) { stackptr = 0; @@ -739,27 +749,6 @@ static void rotate(int opcode, int size, int irop, int irop_reverse) } } -static struct ir* extract_block_refs(struct basicblock* bb) -{ - struct ir* outir = NULL; - int i; - - for (i=0; iems.count; i++) - { - struct em* em = bb->ems.item[i]; - assert(em->opcode == op_bra); - assert(em->paramtype == PARAM_BVALUE); - - outir = new_ir2( - IR_PAIR, 0, - new_bbir(em->u.bvalue.left), - outir - ); - } - - return outir; -} - static void change_by(struct ir* address, int amount) { appendir( @@ -1339,25 +1328,34 @@ static void insn_ivalue(int opcode, arith value) } case op_csa: - case op_csb: { - const char* helper = aprintf(".%s", - (opcode == op_csa) ? "csa" : "csb"); struct ir* descriptor = pop(EM_pointersize); + struct ir* targetvalue = appendir(pop(EM_pointersize)); + struct jumptable jumptable = {}; + int i; if (descriptor->opcode != IR_LABEL) - fatal("csa/csb are only supported if they refer " + fatal("csa is only supported if it refers " "directly to a descriptor block"); - push(descriptor); - materialise_stack(); - appendir( - new_ir2( - IR_FARJUMP, 0, - new_labelir(helper), - extract_block_refs(bb_get(descriptor->u.lvalue)) - ) - ); + parse_csa(bb_get(descriptor->u.lvalue), &jumptable); + emit_jumptable(targetvalue, &jumptable); + break; + } + + case op_csb: + { + struct ir* descriptor = pop(EM_pointersize); + struct ir* targetvalue = appendir(pop(EM_pointersize)); + struct jumptable jumptable = {}; + int i; + + if (descriptor->opcode != IR_LABEL) + fatal("csb is only supported if it refers " + "directly to a descriptor block"); + + parse_csb(bb_get(descriptor->u.lvalue), &jumptable); + emit_jumptable(targetvalue, &jumptable); break; } @@ -1762,4 +1760,133 @@ void tb_procedure(void) generate_tree(current_proc->blocks.item[i]); } +static void parse_csa(struct basicblock* data_bb, struct jumptable* table) +{ + struct em* em; + int lowerbound; + int count; + int i; + + assert(data_bb->ems.count >= 3); + + /* Default target */ + + em = data_bb->ems.item[0]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + table->defaulttarget = em->u.bvalue.left; + + /* Lower bound */ + + em = data_bb->ems.item[1]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + lowerbound = em->u.ivalue; + + /* Count */ + + em = data_bb->ems.item[2]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + count = em->u.ivalue + 1; /* value in descriptor is inclusive */ + assert(data_bb->ems.count >= (count + 3)); + + /* Now, each target in turn. */ + + for (i=0; iems.item[3 + i]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + target = em->u.bvalue.left; + + imap_put(&table->targets, lowerbound+i, target); + } +} + +static void parse_csb(struct basicblock* data_bb, struct jumptable* table) +{ + struct em* em; + int count; + int i; + + assert(data_bb->ems.count >= 2); + + /* Default target */ + + em = data_bb->ems.item[0]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + table->defaulttarget = em->u.bvalue.left; + + /* Number of targets */ + + em = data_bb->ems.item[1]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + count = em->u.ivalue; + assert(data_bb->ems.count >= (count*2 + 2)); + + /* Now, each target in turn. */ + + for (i=0; iems.item[2 + i*2]; + assert(em->opcode == op_loc); + assert(em->paramtype == PARAM_IVALUE); + value = em->u.ivalue; + + em = data_bb->ems.item[3 + i*2]; + assert(em->opcode == op_bra); + assert(em->paramtype == PARAM_BVALUE); + target = em->u.bvalue.left; + + imap_put(&table->targets, value, target); + } +} + +static void emit_jumptable(struct ir* targetvalue, struct jumptable* jumptable) +{ + int i; + + materialise_stack(); + for (i=0; itargets.count; i++) + { + int value = jumptable->targets.item[i].left; + struct basicblock* target = jumptable->targets.item[i].right; + struct basicblock* nextblock = bb_get(NULL); + + array_append(¤t_proc->blocks, nextblock); + appendir( + new_ir2( + IR_CJUMPEQ, 0, + new_ir2( + IR_COMPARESI, EM_wordsize, + targetvalue, + new_wordir(value) + ), + new_ir2( + IR_PAIR, 0, + new_bbir(target), + new_bbir(nextblock) + ) + ) + ); + + current_bb = nextblock; + } + + appendir( + new_ir1( + IR_JUMP, 0, + new_bbir(jumptable->defaulttarget) + ) + ); +} + /* vim: set sw=4 ts=4 expandtab : */