From: Matthias Braun Date: Mon, 11 Jan 2010 18:11:13 +0000 (+0000) Subject: panic instead of wrong results for Set and CMov with float compare. Rename Set to... X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=aa5427e4c02cde09cacdc8ecfbebccd94669713b;p=libfirm panic instead of wrong results for Set and CMov with float compare. Rename Set to Setcc and CMov to CMovcc [r26950] --- diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 2de3849f4..d7de56a3e 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -556,6 +556,7 @@ static void ia32_emit_cmp_suffix(int pnc) be_emit_char('p'); return; } + if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) { str = cmp2condition_u[pnc & 7]; } else { @@ -772,7 +773,7 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...) case 'R': { const arch_register_t *reg = va_arg(ap, const arch_register_t*); - emit_register(reg, NULL); + emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL); break; } @@ -1083,37 +1084,37 @@ static void emit_ia32_Jcc(const ir_node *node) if (pnc & ia32_pn_Cmp_float) { /* Some floating point comparisons require a test of the parity flag, * which indicates that the result is unordered */ - switch (pnc & 15) { - case pn_Cmp_Uo: { - ia32_emitf(proj_true, "\tjp %L\n"); - break; - } + switch (pnc & 0x0f) { + case pn_Cmp_Uo: { + ia32_emitf(proj_true, "\tjp %L\n"); + break; + } - case pn_Cmp_Leg: - ia32_emitf(proj_true, "\tjnp %L\n"); - break; + case pn_Cmp_Leg: + ia32_emitf(proj_true, "\tjnp %L\n"); + break; - case pn_Cmp_Eq: - case pn_Cmp_Lt: - case pn_Cmp_Le: - /* we need a local label if the false proj is a fallthrough - * as the falseblock might have no label emitted then */ - if (can_be_fallthrough(proj_false)) { - need_parity_label = 1; - ia32_emitf(proj_false, "\tjp 1f\n"); - } else { - ia32_emitf(proj_false, "\tjp %L\n"); - } - goto emit_jcc; + case pn_Cmp_Eq: + case pn_Cmp_Lt: + case pn_Cmp_Le: + /* we need a local label if the false proj is a fallthrough + * as the falseblock might have no label emitted then */ + if (can_be_fallthrough(proj_false)) { + need_parity_label = 1; + ia32_emitf(proj_false, "\tjp 1f\n"); + } else { + ia32_emitf(proj_false, "\tjp %L\n"); + } + goto emit_jcc; - case pn_Cmp_Ug: - case pn_Cmp_Uge: - case pn_Cmp_Ne: - ia32_emitf(proj_true, "\tjp %L\n"); - goto emit_jcc; + case pn_Cmp_Ug: + case pn_Cmp_Uge: + case pn_Cmp_Ne: + ia32_emitf(proj_true, "\tjp %L\n"); + goto emit_jcc; - default: - goto emit_jcc; + default: + goto emit_jcc; } } else { emit_jcc: @@ -1132,7 +1133,42 @@ emit_jcc: } } -static void emit_ia32_CMov(const ir_node *node) +/** + * Emits an ia32 Setcc. This is mostly easy but some floating point compares + * are tricky. + */ +static void emit_ia32_Setcc(const ir_node *node) +{ + const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res); + + pn_Cmp pnc = get_ia32_condcode(node); + pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc); + if (pnc & ia32_pn_Cmp_float) { + switch (pnc & 0x0f) { + case pn_Cmp_Uo: + ia32_emitf(node, "\tsetp %#R\n", dreg); + break; + + case pn_Cmp_Leg: + ia32_emitf(node, "\tsetnp %#R\n", dreg); + break; + + case pn_Cmp_Eq: + case pn_Cmp_Lt: + case pn_Cmp_Le: + case pn_Cmp_Ug: + case pn_Cmp_Uge: + case pn_Cmp_Ne: + panic("No handling for set with parity bit yet in ia32_Setcc"); + + default: + break; + } + } + ia32_emitf(node, "\tset%P %#R\n", pnc, dreg); +} + +static void emit_ia32_CMovcc(const ir_node *node) { const ia32_attr_t *attr = get_ia32_attr_const(node); int ins_permuted = attr->data.ins_permuted; @@ -1141,10 +1177,10 @@ static void emit_ia32_CMov(const ir_node *node) const arch_register_t *in_true; const arch_register_t *in_false; - pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc); + pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc); - in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true)); - in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_false)); + in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true)); + in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false)); /* should be same constraint fullfilled? */ if (out == in_false) { @@ -1871,7 +1907,7 @@ static void ia32_register_emitters(void) /* other ia32 emitter functions */ IA32_EMIT2(Conv_I2I8Bit, Conv_I2I); IA32_EMIT(Asm); - IA32_EMIT(CMov); + IA32_EMIT(CMovcc); IA32_EMIT(Call); IA32_EMIT(Const); IA32_EMIT(Conv_FP2FP); @@ -1883,6 +1919,7 @@ static void ia32_register_emitters(void) IA32_EMIT(GetEIP); IA32_EMIT(IMul); IA32_EMIT(Jcc); + IA32_EMIT(Setcc); IA32_EMIT(LdTls); IA32_EMIT(Minus64Bit); IA32_EMIT(SwitchJmp); @@ -2862,7 +2899,7 @@ static void bemit_shrd(const ir_node *node) } } -static void bemit_cmov(const ir_node *node) +static void bemit_cmovcc(const ir_node *node) { const ia32_attr_t *attr = get_ia32_attr_const(node); int ins_permuted = attr->data.ins_permuted; @@ -2871,10 +2908,10 @@ static void bemit_cmov(const ir_node *node) const arch_register_t *in_true; const arch_register_t *in_false; - pnc = determine_final_pnc(node, n_ia32_CMov_eflags, pnc); + pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc); - in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true)); - in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_false)); + in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true)); + in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false)); /* should be same constraint fullfilled? */ if (out == in_false) { @@ -3072,19 +3109,21 @@ UNOPMEM(negmem, 0xF6, 3) UNOPMEM(incmem, 0xFE, 0) UNOPMEM(decmem, 0xFE, 1) -static void bemit_set(const ir_node *node) +static void bemit_setcc(const ir_node *node) { pn_Cmp pnc; bemit8(0x0F); pnc = get_ia32_condcode(node); - pnc = determine_final_pnc(node, n_ia32_Set_eflags, pnc); - if (get_ia32_attr_const(node)->data.ins_permuted) - pnc = ia32_get_negated_pnc(pnc); + pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc); + + /* TODO: all the special casing for float compares is missing */ + if (pnc & ia32_pn_Cmp_float) + panic("binary setcc from float compare not implemented yet"); bemit8(0x90 + pnc2cc(pnc)); - bemit_modru(get_out_reg(node, pn_ia32_Set_res), 2); + bemit_modru(get_out_reg(node, pn_ia32_Setcc_res), 2); } static void bemit_ldtls(const ir_node *node) @@ -4032,7 +4071,7 @@ static void ia32_register_binary_emitters(void) register_emitter(op_ia32_AndMem, bemit_andmem); register_emitter(op_ia32_AndMem8Bit, bemit_andmem8bit); register_emitter(op_ia32_Breakpoint, bemit_int3); - register_emitter(op_ia32_CMov, bemit_cmov); + register_emitter(op_ia32_CMovcc, bemit_cmovcc); register_emitter(op_ia32_Call, bemit_call); register_emitter(op_ia32_Cltd, bemit_cltd); register_emitter(op_ia32_Cmc, bemit_cmc); @@ -4088,7 +4127,7 @@ static void ia32_register_binary_emitters(void) register_emitter(op_ia32_Sar, bemit_sar); register_emitter(op_ia32_SarMem, bemit_sarmem); register_emitter(op_ia32_Sbb, bemit_sbb); - register_emitter(op_ia32_Set, bemit_set); + register_emitter(op_ia32_Setcc, bemit_setcc); register_emitter(op_ia32_Shl, bemit_shl); register_emitter(op_ia32_ShlD, bemit_shld); register_emitter(op_ia32_ShlMem, bemit_shlmem); diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 9082c7888..a44732cac 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -218,7 +218,7 @@ static inline int need_constraint_copy(ir_node *irn) case iro_ia32_Lea: case iro_ia32_Conv_I2I: case iro_ia32_Conv_I2I8Bit: - case iro_ia32_CMov: + case iro_ia32_CMovcc: return 0; default: diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index ecbcfb98b..3e9e0032d 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -197,7 +197,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { /* dump pn code */ if (is_ia32_SwitchJmp(n)) { fprintf(F, "pn_code = %ld\n", get_ia32_condcode(n)); - } else if (is_ia32_CMov(n) || is_ia32_Set(n) || is_ia32_Jcc(n)) { + } else if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) { ia32_attr_t *attr = get_ia32_attr(n); long pnc = get_ia32_condcode(n); fprintf(F, "pn_code = 0x%lX (%s)\n", pnc, get_pnc_string(pnc & pn_Cmp_True)); diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 9d88e8f45..a49559d03 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -1090,37 +1090,34 @@ Test8Bit => { modified_flags => $status_flags }, -Set => { +Setcc => { #irn_flags => "R", reg_req => { in => [ "eflags" ], out => [ "eax ebx ecx edx" ] }, ins => [ "eflags" ], outs => [ "res" ], attr_type => "ia32_condcode_attr_t", - attr => "pn_Cmp pnc, int ins_permuted", - init_attr => "attr->attr.data.ins_permuted = ins_permuted;\n". - "\tset_ia32_ls_mode(res, mode_Bu);\n", - emit => '. set%CMP0 %DB0', + attr => "pn_Cmp pnc", + init_attr => "set_ia32_ls_mode(res, mode_Bu);\n", latency => 1, units => [ "GP" ], mode => $mode_gp, }, -SetMem => { +SetccMem => { #irn_flags => "R", state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] }, ins => [ "base", "index", "mem","eflags" ], attr_type => "ia32_condcode_attr_t", - attr => "pn_Cmp pnc, int ins_permuted", - init_attr => "attr->attr.data.ins_permuted = ins_permuted;\n". - "\tset_ia32_ls_mode(res, mode_Bu);\n", + attr => "pn_Cmp pnc", + init_attr => "set_ia32_ls_mode(res, mode_Bu);\n", emit => '. set%CMP3 %AM', latency => 1, units => [ "GP" ], mode => 'mode_M', }, -CMov => { +CMovcc => { #irn_flags => "R", # (note: leave the false,true order intact to make it compatible with other # ia32_binary ops) diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index c46499351..b3ecf0dc4 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -1809,7 +1809,7 @@ static ir_node *gen_Minus(ir_node *node) */ static ir_node *gen_Not(ir_node *node) { - ir_node *op = get_Not_op(node); + ir_node *op = get_Not_op(node); assert(get_irn_mode(node) != mode_b); /* should be lowered already */ assert (! mode_is_float(get_irn_mode(node))); @@ -2176,41 +2176,47 @@ static ir_node *dest_am_unop(ir_node *node, ir_node *op, ir_node *mem, static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem) { - ir_mode *mode = get_irn_mode(node); - ir_node *mux_true = get_Mux_true(node); - ir_node *mux_false = get_Mux_false(node); - ir_node *cond; - ir_node *new_mem; - dbg_info *dbgi; - ir_node *block; - ir_node *new_block; - ir_node *flags; - ir_node *new_node; - int negated; - pn_Cmp pnc; - ia32_address_t addr; + ir_mode *mode = get_irn_mode(node); + ir_node *mux_true = get_Mux_true(node); + ir_node *mux_false = get_Mux_false(node); + ir_node *cond; + ir_node *new_mem; + dbg_info *dbgi; + ir_node *block; + ir_node *new_block; + ir_node *flags; + ir_node *new_node; + bool negated; + pn_Cmp pnc; + ia32_address_t addr; if (get_mode_size_bits(mode) != 8) return NULL; if (is_Const_1(mux_true) && is_Const_0(mux_false)) { - negated = 0; + negated = false; } else if (is_Const_0(mux_true) && is_Const_1(mux_false)) { - negated = 1; + negated = true; } else { return NULL; } + cond = get_Mux_sel(node); + flags = get_flags_node(cond, &pnc); + /* we can't handle the float special cases with SetM */ + if (pnc & ia32_pn_Cmp_float) + return NULL; + if (negated) + pnc = get_negated_pnc(pnc, pnc & ia32_pn_Cmp_float ? mode_F : mode_Is); + build_address_ptr(&addr, ptr, mem); dbgi = get_irn_dbg_info(node); block = get_nodes_block(node); new_block = be_transform_node(block); - cond = get_Mux_sel(node); - flags = get_flags_node(cond, &pnc); new_mem = be_transform_node(mem); - new_node = new_bd_ia32_SetMem(dbgi, new_block, addr.base, - addr.index, addr.mem, flags, pnc, negated); + new_node = new_bd_ia32_SetccMem(dbgi, new_block, addr.base, + addr.index, addr.mem, flags, pnc); set_address(new_node, &addr); set_ia32_op_type(new_node, ia32_AddrModeD); set_ia32_ls_mode(new_node, mode); @@ -2336,6 +2342,7 @@ static ir_node *try_create_dest_am(ir_node *node) case iro_Mux: new_node = try_create_SetMem(val, ptr, mem); break; + case iro_Minus: op1 = get_Minus_op(val); new_node = dest_am_unop(val, op1, mem, ptr, mode, new_bd_ia32_NegMem); @@ -2960,9 +2967,9 @@ static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags, match_arguments(&am, block, val_false, val_true, flags, match_commutative | match_am | match_16bit_am | match_mode_neutral); - new_node = new_bd_ia32_CMov(dbgi, new_block, addr->base, addr->index, - addr->mem, am.new_op1, am.new_op2, new_flags, - am.ins_permuted, pnc); + new_node = new_bd_ia32_CMovcc(dbgi, new_block, addr->base, addr->index, + addr->mem, am.new_op1, am.new_op2, new_flags, + am.ins_permuted, pnc); set_am_attributes(new_node, &am); SET_IA32_ORIG_NODE(new_node, node); @@ -2976,13 +2983,12 @@ static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags, * Creates a ia32 Setcc instruction. */ static ir_node *create_set_32bit(dbg_info *dbgi, ir_node *new_block, - ir_node *flags, pn_Cmp pnc, ir_node *orig_node, - int ins_permuted) + ir_node *flags, pn_Cmp pnc, ir_node *orig_node) { ir_mode *mode = get_irn_mode(orig_node); ir_node *new_node; - new_node = new_bd_ia32_Set(dbgi, new_block, flags, pnc, ins_permuted); + new_node = new_bd_ia32_Setcc(dbgi, new_block, flags, pnc); SET_IA32_ORIG_NODE(new_node, orig_node); /* we might need to conv the result up */ @@ -3144,7 +3150,7 @@ static ir_node *gen_Mux(ir_node *node) unsigned scale; flags = get_flags_node(cond, &pnc); - new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, /*is_permuted=*/0); + new_node = create_set_32bit(dbgi, new_block, flags, pnc, node); if (ia32_cg_config.use_sse2) { /* cannot load from different mode on SSE */ @@ -3241,9 +3247,10 @@ static ir_node *gen_Mux(ir_node *node) if (is_Const(mux_true) && is_Const(mux_false)) { /* both are const, good */ if (is_Const_1(mux_true) && is_Const_0(mux_false)) { - new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, /*is_premuted=*/0); + new_node = create_set_32bit(dbgi, new_block, flags, pnc, node); } else if (is_Const_0(mux_true) && is_Const_1(mux_false)) { - new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, /*is_premuted=*/1); + pnc = get_negated_pnc(pnc, pnc & ia32_pn_Cmp_float ? mode_F : mode_Is); + new_node = create_set_32bit(dbgi, new_block, flags, pnc, node); } else { /* Not that simple. */ goto need_cmov; @@ -4782,7 +4789,7 @@ static ir_node *gen_ffs(ir_node *node) flag = new_r_Proj(block, real, mode_b, pn_ia32_flags); /* sete */ - set = new_bd_ia32_Set(dbgi, block, flag, pn_Cmp_Eq, 0); + set = new_bd_ia32_Setcc(dbgi, block, flag, pn_Cmp_Eq); SET_IA32_ORIG_NODE(set, node); /* conv to 32bit */ @@ -4852,7 +4859,7 @@ static ir_node *gen_parity(ir_node *node) cmp = fix_mem_proj(cmp, &am); /* setp */ - new_node = new_bd_ia32_Set(dbgi, new_block, cmp, ia32_pn_Cmp_parity, 0); + new_node = new_bd_ia32_Setcc(dbgi, new_block, cmp, ia32_pn_Cmp_parity); SET_IA32_ORIG_NODE(new_node, node); /* conv to 32bit */ diff --git a/ir/be/ia32/ia32_x87.c b/ir/be/ia32/ia32_x87.c index 14c335873..6e806fba3 100644 --- a/ir/be/ia32/ia32_x87.c +++ b/ir/be/ia32/ia32_x87.c @@ -1473,9 +1473,9 @@ static int sim_Fucom(x87_state *state, ir_node *n) int reg_index_1 = arch_register_get_index(op1); int reg_index_2 = arch_register_get_index(op2); unsigned live = vfp_live_args_after(sim, n, 0); - int permuted = attr->attr.data.ins_permuted; - int xchg = 0; - int pops = 0; + bool permuted = attr->attr.data.ins_permuted; + bool xchg = false; + int pops = 0; DB((dbg, LEVEL_1, ">>> %+F %s, %s\n", n, arch_register_get_name(op1), arch_register_get_name(op2))); @@ -1503,7 +1503,7 @@ static int sim_Fucom(x87_state *state, ir_node *n) } else if (op2_idx == 0) { /* res = op X tos */ permuted = !permuted; - xchg = 1; + xchg = true; } else { /* bring the first one to tos */ x87_create_fxch(state, n, op1_idx); @@ -1538,9 +1538,9 @@ static int sim_Fucom(x87_state *state, ir_node *n) op2_idx = 0; } /* res = op X tos, pop */ - pops = 1; + pops = 1; permuted = !permuted; - xchg = 1; + xchg = true; } else { /* both operands are dead here, check first for identity. */ if (op1_idx == op2_idx) { @@ -1575,8 +1575,8 @@ static int sim_Fucom(x87_state *state, ir_node *n) } /* res = op X tos, pop, pop */ permuted = !permuted; - xchg = 1; - pops = 2; + xchg = true; + pops = 2; } else { /* if one is already the TOS, we need two fxch */ if (op1_idx == 0) { @@ -1587,9 +1587,9 @@ static int sim_Fucom(x87_state *state, ir_node *n) x87_create_fxch(state, n, op2_idx); op2_idx = 0; /* res = op X tos, pop, pop */ - pops = 2; + pops = 2; permuted = !permuted; - xchg = 1; + xchg = true; } else if (op2_idx == 0) { /* second one is TOS, move to st(1) */ x87_create_fxch(state, n, 1);