From: Christian Würdig Date: Fri, 31 Mar 2006 16:55:26 +0000 (+0000) Subject: changed SwitchJmp emitter (but still broken in some cases) X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=5735b25f3620ce15040574a294d029f5002473a7;p=libfirm changed SwitchJmp emitter (but still broken in some cases) --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 6841c9096..a86a40f15 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -873,7 +873,7 @@ static int ia32_cmp_branch_t(const void *a, const void *b) { static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) { unsigned long interval; char buf[SNPRINTF_BUF_LEN]; - int last_value, i, pn, do_jmp_tbl = 1; + int last_value, i, pn; jmp_tbl_t tbl; ir_node *proj; const ir_edge_t *edge; @@ -920,83 +920,59 @@ static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) { /* two-complement's magic make this work without overflow */ interval = tbl.max_value - tbl.min_value; - /* check value interval */ - if (interval > 16 * 1024) { - do_jmp_tbl = 0; - } + /* emit the table */ + if (tbl.min_value != 0) { + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "sub [%1S-%d], %u", irn, tbl.min_value * 4, interval); + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmp DWORD PTR [%1S-%d], %u", irn, tbl.min_value * 4, interval); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* first switch value is not 0 */"); - /* check ratio of value interval to number of branches */ - if ((float)(interval + 1) / (float)tbl.num_branches > 8.0) { - do_jmp_tbl = 0; + IA32_DO_EMIT(irn); } + else { + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %u", irn, interval); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* compare for switch */"); - if (do_jmp_tbl) { - /* emit the table */ - if (tbl.min_value != 0) { - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %lu, -%d(%1S)", - interval, tbl.min_value, irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* first switch value is not 0 */"); + IA32_DO_EMIT(irn); + } - IA32_DO_EMIT(irn); - } - else { - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %lu, %1S", interval, irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* compare for switch */"); + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "ja %s", get_cfop_target(tbl.defProj, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default jump if out of range */"); + IA32_DO_EMIT(irn); - IA32_DO_EMIT(irn); - } + if (tbl.num_branches > 1) { + /* create table */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "ja %s", get_cfop_target(tbl.defProj, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default jump if out of range */"); + lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "jmp %s[%1S*4]", tbl.label, irn); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get jump table entry as target */"); IA32_DO_EMIT(irn); - if (tbl.num_branches > 1) { - /* create table */ - - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "jmp [%1S*4+%s]", irn, tbl.label); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get jump table entry as target */"); - IA32_DO_EMIT(irn); + fprintf(F, "\t.section\t.rodata\n"); + fprintf(F, "\t.align 4\n"); - fprintf(F, "\t.section\t.rodata\n"); - fprintf(F, "\t.align 4\n"); + fprintf(F, "%s:\n", tbl.label); - fprintf(F, "%s:\n", tbl.label); - - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[0].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */\n", tbl.branches[0].value); - IA32_DO_EMIT(irn); + snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[0].target, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */\n", tbl.branches[0].value); + IA32_DO_EMIT(irn); - last_value = tbl.branches[0].value; - for (i = 1; i < tbl.num_branches; ++i) { - while (++last_value < tbl.branches[i].value) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.defProj, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */"); - IA32_DO_EMIT(irn); - } - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value); + last_value = tbl.branches[0].value; + for (i = 1; i < tbl.num_branches; ++i) { + while (++last_value < tbl.branches[i].value) { + snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.defProj, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */"); IA32_DO_EMIT(irn); } - - fprintf(F, "\t.text"); - } - else { - /* one jump is enough */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.branches[0].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* only one case given */"); - IA32_DO_EMIT(irn); - } - } - else { // no jump table - for (i = 0; i < tbl.num_branches; ++i) { - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmpl %d, %1S", tbl.branches[i].value, irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", i); + snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value); IA32_DO_EMIT(irn); - fprintf(F, "\tje %s\n", get_cfop_target(tbl.branches[i].target, buf)); } - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.defProj, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */"); + fprintf(F, "\t.text"); + } + else { + /* one jump is enough */ + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.branches[0].target, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* only one case given */"); IA32_DO_EMIT(irn); }