panic instead of wrong results for Set and CMov with float compare. Rename Set to...
authorMatthias Braun <matze@braunis.de>
Mon, 11 Jan 2010 18:11:13 +0000 (18:11 +0000)
committerMatthias Braun <matze@braunis.de>
Mon, 11 Jan 2010 18:11:13 +0000 (18:11 +0000)
[r26950]

ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_finish.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c
ir/be/ia32/ia32_x87.c

index 2de3849..d7de56a 100644 (file)
@@ -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);
index 9082c78..a44732c 100644 (file)
@@ -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:
index ecbcfb9..3e9e003 100644 (file)
@@ -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));
index 9d88e8f..a49559d 100644 (file)
@@ -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)
index c464993..b3ecf0d 100644 (file)
@@ -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 */
index 14c3358..6e806fb 100644 (file)
@@ -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);