fix warning
[libfirm] / ir / be / ia32 / ia32_transform.c
index 8319bbe..9028aac 100644 (file)
@@ -22,7 +22,6 @@
  * @brief       This file implements the IR transformation from firm into
  *              ia32-Firm.
  * @author      Christian Wuerdig, Matthias Braun
- * @version     $Id$
  */
 #include "config.h"
 
@@ -188,7 +187,7 @@ static ir_node *get_symconst_base(void)
 {
        ir_graph *irg = current_ir_graph;
 
-       if (be_get_irg_options(irg)->pic) {
+       if (be_options.pic) {
                const arch_env_t *arch_env = be_get_irg_arch_env(irg);
                return arch_env->impl->get_pic_base(irg);
        }
@@ -488,15 +487,20 @@ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct)
  * input here, for unary operations use NULL).
  */
 static int ia32_use_source_address_mode(ir_node *block, ir_node *node,
-                                        ir_node *other, ir_node *other2, match_flags_t flags)
+                                        ir_node *other, ir_node *other2,
+                                        match_flags_t flags)
 {
        ir_node *load;
+       ir_mode *mode;
        long     pn;
 
        /* float constants are always available */
        if (is_Const(node)) {
-               ir_mode *mode = get_irn_mode(node);
+               mode = get_irn_mode(node);
                if (mode_is_float(mode)) {
+                       ir_tarval *tv = get_Const_tarval(node);
+                       if (!tarval_ieee754_can_conv_lossless(tv, mode_D))
+                               return 0;
                        if (ia32_cg_config.use_sse2) {
                                if (is_simple_sse_Const(node))
                                        return 0;
@@ -508,6 +512,7 @@ static int ia32_use_source_address_mode(ir_node *block, ir_node *node,
                                return 0;
                        return 1;
                }
+               return 0;
        }
 
        if (!is_Proj(node))
@@ -518,6 +523,10 @@ static int ia32_use_source_address_mode(ir_node *block, ir_node *node,
                return 0;
        if (get_nodes_block(load) != block)
                return 0;
+       mode = get_irn_mode(node);
+       /* we can't fold mode_E AM */
+       if (mode == ia32_mode_E)
+               return 0;
        /* we only use address mode if we're the only user of the load */
        if (get_irn_n_edges(node) != (flags & match_two_users ? 2 : 1))
                return 0;
@@ -983,6 +992,31 @@ static ir_node *get_fpcw(void)
        return initial_fpcw;
 }
 
+static ir_node *skip_float_upconv(ir_node *node)
+{
+       ir_mode *mode = get_irn_mode(node);
+       assert(mode_is_float(mode));
+
+       while (is_Conv(node)) {
+               ir_node *pred      = get_Conv_op(node);
+               ir_mode *pred_mode = get_irn_mode(pred);
+
+               /**
+                * suboptimal, but without this check the address mode matcher
+                * can incorrectly think that something has only 1 user
+                */
+               if (get_irn_n_edges(node) > 1)
+                       break;
+
+               if (!mode_is_float(pred_mode)
+                       || get_mode_size_bits(pred_mode) > get_mode_size_bits(mode))
+                       break;
+               node = pred;
+               mode = pred_mode;
+       }
+       return node;
+}
+
 /**
  * Construct a standard binary operation, set AM and immediate if required.
  *
@@ -994,27 +1028,19 @@ static ir_node *get_fpcw(void)
 static ir_node *gen_binop_x87_float(ir_node *node, ir_node *op1, ir_node *op2,
                                     construct_binop_float_func *func)
 {
-       ir_mode             *mode = get_irn_mode(node);
        dbg_info            *dbgi;
-       ir_node             *block, *new_block, *new_node;
+       ir_node             *block;
+       ir_node             *new_block;
+       ir_node             *new_node;
        ia32_address_mode_t  am;
        ia32_address_t      *addr = &am.addr;
        ia32_x87_attr_t     *attr;
        /* All operations are considered commutative, because there are reverse
         * variants */
-       match_flags_t        flags = match_commutative;
-
-       /* happens for div nodes... */
-       if (mode == mode_T) {
-               if (is_Div(node))
-                       mode = get_Div_resmode(node);
-               else
-                       panic("can't determine mode");
-       }
+       match_flags_t        flags = match_commutative | match_am;
 
-       /* cannot use address mode with long double on x87 */
-       if (get_mode_size_bits(mode) <= 64)
-               flags |= match_am;
+       op1 = skip_float_upconv(op1);
+       op2 = skip_float_upconv(op2);
 
        block = get_nodes_block(node);
        match_arguments(&am, block, op1, op2, NULL, flags);
@@ -1318,9 +1344,6 @@ static ir_node *gen_Add(ir_node *node)
 
        ia32_mark_non_am(node);
 
-       op2 = ia32_skip_downconv(op2);
-       op1 = ia32_skip_downconv(op1);
-
        /**
         * Rules for an Add:
         *   0. Immediate Trees (example Add(Symconst, Const) -> Const)
@@ -1966,7 +1989,8 @@ static ir_node *gen_bt(ir_node *cmp, ir_node *x, ir_node *n)
 }
 
 static ia32_condition_code_t relation_to_condition_code(ir_relation relation,
-                                                        ir_mode *mode)
+                                                        ir_mode *mode,
+                                                        bool overflow_possible)
 {
        if (mode_is_float(mode)) {
                switch (relation) {
@@ -1999,13 +2023,15 @@ static ia32_condition_code_t relation_to_condition_code(ir_relation relation,
                case ir_relation_unordered_equal:
                case ir_relation_equal:                return ia32_cc_equal;
                case ir_relation_unordered_less:
-               case ir_relation_less:                 return ia32_cc_less;
+               case ir_relation_less:
+                       return overflow_possible ? ia32_cc_less : ia32_cc_sign;
                case ir_relation_unordered_less_equal:
                case ir_relation_less_equal:           return ia32_cc_less_equal;
                case ir_relation_unordered_greater:
                case ir_relation_greater:              return ia32_cc_greater;
                case ir_relation_unordered_greater_equal:
-               case ir_relation_greater_equal:        return ia32_cc_greater_equal;
+               case ir_relation_greater_equal:
+                       return overflow_possible ? ia32_cc_greater_equal : ia32_cc_not_sign;
                case ir_relation_unordered_less_greater:
                case ir_relation_less_greater:         return ia32_cc_not_equal;
                case ir_relation_less_equal_greater:
@@ -2041,21 +2067,22 @@ static ia32_condition_code_t relation_to_condition_code(ir_relation relation,
        }
 }
 
-static ir_node *get_flags_node_cmp(ir_node *cmp, ia32_condition_code_t *cc_out)
+static ir_node *get_flags_node(ir_node *cmp, ia32_condition_code_t *cc_out)
 {
        /* must have a Cmp as input */
        ir_relation relation = get_Cmp_relation(cmp);
-       ir_relation possible;
        ir_node    *l        = get_Cmp_left(cmp);
        ir_node    *r        = get_Cmp_right(cmp);
        ir_mode    *mode     = get_irn_mode(l);
+       bool        overflow_possible;
        ir_node    *flags;
 
        /* check for bit-test */
-       if (ia32_cg_config.use_bt && (relation == ir_relation_equal
-                       || (mode_is_signed(mode) && relation == ir_relation_less_greater)
-                       || (!mode_is_signed(mode) && ((relation & ir_relation_greater_equal) == ir_relation_greater)))
-                   && is_And(l)) {
+       if (ia32_cg_config.use_bt
+           && (relation == ir_relation_equal
+               || (mode_is_signed(mode) && relation == ir_relation_less_greater)
+               || (!mode_is_signed(mode) && ((relation & ir_relation_greater_equal) == ir_relation_greater)))
+           && is_And(l)) {
                ir_node *la = get_And_left(l);
                ir_node *ra = get_And_right(l);
                if (is_Shl(ra)) {
@@ -2068,7 +2095,7 @@ static ir_node *get_flags_node_cmp(ir_node *cmp, ia32_condition_code_t *cc_out)
                        if (is_Const_1(c) && is_Const_0(r)) {
                                /* (1 << n) & ra) */
                                ir_node *n = get_Shl_right(la);
-                               flags    = gen_bt(cmp, ra, n);
+                               flags = gen_bt(cmp, ra, n);
                                /* the bit is copied into the CF flag */
                                if (relation & ir_relation_equal)
                                        *cc_out = ia32_cc_above_equal; /* test for CF=0 */
@@ -2079,33 +2106,25 @@ static ir_node *get_flags_node_cmp(ir_node *cmp, ia32_condition_code_t *cc_out)
                }
        }
 
-       /* the middle-end tries to eliminate impossible relations, so a ptr != 0
+       /* the middle-end tries to eliminate impossible relations, so a ptr <> 0
         * test becomes ptr > 0. But for x86 an equal comparison is preferable to
         * a >0 (we can sometimes eliminate the cmp in favor of flags produced by
-        * a predecessor node). So add the < bit */
-       possible = ir_get_possible_cmp_relations(l, r);
-       if (((relation & ir_relation_less) && !(possible & ir_relation_greater))
-         || ((relation & ir_relation_greater) && !(possible & ir_relation_less)))
-               relation |= ir_relation_less_greater;
+        * a predecessor node). So add the < bit.
+        * (Note that we do not want to produce <=> (which can happen for
+        * unoptimized code), because no x86 flag can represent that */
+       if (!(relation & ir_relation_equal) && relation & ir_relation_less_greater)
+               relation |= get_negated_relation(ir_get_possible_cmp_relations(l, r)) & ir_relation_less_greater;
+
+       overflow_possible = true;
+       if (is_Const(r) && is_Const_null(r))
+               overflow_possible = false;
 
        /* just do a normal transformation of the Cmp */
-       *cc_out = relation_to_condition_code(relation, mode);
+       *cc_out = relation_to_condition_code(relation, mode, overflow_possible);
        flags   = be_transform_node(cmp);
        return flags;
 }
 
-/**
- * Transform a node returning a "flag" result.
- *
- * @param node    the node to transform
- * @param cc_out  the compare mode to use
- */
-static ir_node *get_flags_node(ir_node *node, ia32_condition_code_t *cc_out)
-{
-       assert(is_Cmp(node));
-       return get_flags_node_cmp(node, cc_out);
-}
-
 /**
  * Transforms a Load.
  *
@@ -2756,26 +2775,30 @@ static ir_node *gen_Store(ir_node *node)
  *
  * @return the created ia32 SwitchJmp node
  */
-static ir_node *create_Switch(ir_node *node)
-{
-       dbg_info  *dbgi       = get_irn_dbg_info(node);
-       ir_node   *block      = be_transform_node(get_nodes_block(node));
-       ir_node   *sel        = get_Cond_selector(node);
-       ir_node   *new_sel    = be_transform_node(sel);
-       long       default_pn = get_Cond_default_proj(node);
-       ir_node   *new_node;
-       ir_entity *entity;
-
-       assert(get_mode_size_bits(get_irn_mode(sel)) == 32);
+static ir_node *gen_Switch(ir_node *node)
+{
+       dbg_info              *dbgi     = get_irn_dbg_info(node);
+       ir_graph              *irg      = get_irn_irg(node);
+       ir_node               *block    = be_transform_node(get_nodes_block(node));
+       ir_node               *sel      = get_Switch_selector(node);
+       ir_node               *new_sel  = be_transform_node(sel);
+       ir_mode               *sel_mode = get_irn_mode(sel);
+       const ir_switch_table *table    = get_Switch_table(node);
+       unsigned               n_outs   = get_Switch_n_outs(node);
+       ir_node               *new_node;
+       ir_entity             *entity;
+
+       assert(get_mode_size_bits(get_irn_mode(sel)) <= 32);
+       if (get_mode_size_bits(sel_mode) != 32)
+               new_sel = create_upconv(new_sel, sel);
 
        entity = new_entity(NULL, id_unique("TBL%u"), get_unknown_type());
        set_entity_visibility(entity, ir_visibility_private);
        add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
 
-       /* TODO: we could perform some more matching here to also use the base
-        * register of the address mode */
-       new_node
-               = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, default_pn);
+       table = ir_switch_table_duplicate(irg, table);
+
+       new_node = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, n_outs, table);
        set_ia32_am_scale(new_node, 2);
        set_ia32_am_sc(new_node, entity);
        set_ia32_op_type(new_node, ia32_AddrModeS);
@@ -2796,15 +2819,10 @@ static ir_node *gen_Cond(ir_node *node)
        ir_node              *new_block = be_transform_node(block);
        dbg_info             *dbgi      = get_irn_dbg_info(node);
        ir_node              *sel       = get_Cond_selector(node);
-       ir_mode              *sel_mode  = get_irn_mode(sel);
        ir_node              *flags     = NULL;
        ir_node              *new_node;
        ia32_condition_code_t cc;
 
-       if (sel_mode != mode_b) {
-               return create_Switch(node);
-       }
-
        /* we get flags from a Cmp */
        flags = get_flags_node(sel, &cc);
 
@@ -2847,15 +2865,14 @@ static ir_node *create_Fucom(ir_node *node)
                set_ia32_commutative(new_node);
                SET_IA32_ORIG_NODE(new_node, node);
        } else {
-               if (ia32_cg_config.use_ftst && is_Const_0(right)) {
+               if (is_Const_0(right)) {
                        new_node = new_bd_ia32_vFtstFnstsw(dbgi, new_block, new_left, 0);
                } else {
                        new_right = be_transform_node(right);
                        new_node  = new_bd_ia32_vFucomFnstsw(dbgi, new_block, new_left, new_right, 0);
+                       set_ia32_commutative(new_node);
                }
 
-               set_ia32_commutative(new_node);
-
                SET_IA32_ORIG_NODE(new_node, node);
 
                new_node = new_bd_ia32_Sahf(dbgi, new_block, new_node);
@@ -3012,9 +3029,9 @@ static ir_node *gen_Cmp(ir_node *node)
                assert(get_irn_mode(and_left) == cmp_mode);
 
                match_arguments(&am, block, and_left, and_right, NULL,
-                                                                               match_commutative |
-                                                                               match_am | match_8bit_am | match_16bit_am |
-                                                                               match_am_and_immediates | match_immediate);
+                               match_commutative |
+                               match_am | match_8bit_am | match_16bit_am |
+                               match_am_and_immediates | match_immediate);
 
                /* use 32bit compare mode if possible since the opcode is smaller */
                if (upper_bits_clean(am.new_op1, cmp_mode) &&
@@ -3024,10 +3041,13 @@ static ir_node *gen_Cmp(ir_node *node)
 
                if (get_mode_size_bits(cmp_mode) == 8) {
                        new_node = new_bd_ia32_Test8Bit(dbgi, new_block, addr->base,
-                                       addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+                                                       addr->index, addr->mem,
+                                                       am.new_op1, am.new_op2,
+                                                       am.ins_permuted);
                } else {
-                       new_node = new_bd_ia32_Test(dbgi, new_block, addr->base, addr->index,
-                                       addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+                       new_node = new_bd_ia32_Test(dbgi, new_block, addr->base,
+                                                   addr->index, addr->mem, am.new_op1,
+                                                   am.new_op2, am.ins_permuted);
                }
        } else {
                /* Cmp(left, right) */
@@ -3047,7 +3067,8 @@ static ir_node *gen_Cmp(ir_node *node)
                                                       am.new_op2, am.ins_permuted);
                } else {
                        new_node = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index,
-                                       addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
+                                                  addr->mem, am.new_op1, am.new_op2,
+                                                  am.ins_permuted);
                }
        }
        set_am_attributes(new_node, &am);
@@ -3150,9 +3171,11 @@ static ir_node *create_doz(ir_node *psi, ir_node *a, ir_node *b)
 
        dbgi = get_irn_dbg_info(psi);
        sbb  = new_bd_ia32_Sbb0(dbgi, block, eflags);
+       set_ia32_ls_mode(sbb, mode_Iu);
        notn = new_bd_ia32_Not(dbgi, block, sbb);
 
        new_node = new_bd_ia32_And(dbgi, block, noreg_GP, noreg_GP, nomem, new_node, notn);
+       set_ia32_ls_mode(new_node, mode_Iu);
        set_ia32_commutative(new_node);
        return new_node;
 }
@@ -4755,7 +4778,7 @@ static ir_node *gen_be_Call(ir_node *node)
 
        /* special case for PIC trampoline calls */
        old_no_pic_adjust  = ia32_no_pic_adjust;
-       ia32_no_pic_adjust = be_get_irg_options(current_ir_graph)->pic;
+       ia32_no_pic_adjust = be_options.pic;
 
        match_arguments(&am, src_block, NULL, src_ptr, src_mem,
                        match_am | match_immediate);
@@ -5061,6 +5084,7 @@ static ir_node *gen_ffs(ir_node *node)
 
        /* or */
        orn = new_bd_ia32_Or(dbgi, block, noreg_GP, noreg_GP, nomem, bsf, neg);
+       set_ia32_ls_mode(orn, mode_Iu);
        set_ia32_commutative(orn);
 
        /* add 1 */
@@ -5116,6 +5140,7 @@ static ir_node *gen_parity(ir_node *node)
        ir_node *xor2 = new_bd_ia32_XorHighLow(dbgi, new_block, xor);
        ir_node *flags;
 
+       set_ia32_ls_mode(xor, mode_Iu);
        set_ia32_commutative(xor);
 
        set_irn_mode(xor2, mode_T);
@@ -5253,27 +5278,23 @@ static ir_node *gen_bswap(ir_node *node)
        ir_node *new_block = be_transform_node(block);
        ir_mode *mode      = get_irn_mode(param);
        unsigned size      = get_mode_size_bits(mode);
-       ir_node  *m1, *m2, *m3, *m4, *s1, *s2, *s3, *s4;
 
        switch (size) {
        case 32:
-               if (ia32_cg_config.use_i486) {
+               if (ia32_cg_config.use_bswap) {
                        /* swap available */
                        return new_bd_ia32_Bswap(dbgi, new_block, param);
+               } else {
+                       ir_node *i8 = ia32_create_Immediate(NULL, 0, 8);
+                       ir_node *rol1 = new_bd_ia32_Rol(dbgi, new_block, param, i8);
+                       ir_node *i16 = ia32_create_Immediate(NULL, 0, 16);
+                       ir_node *rol2 = new_bd_ia32_Rol(dbgi, new_block, rol1, i16);
+                       ir_node *rol3 = new_bd_ia32_Rol(dbgi, new_block, rol2, i8);
+                       set_ia32_ls_mode(rol1, mode_Hu);
+                       set_ia32_ls_mode(rol2, mode_Iu);
+                       set_ia32_ls_mode(rol3, mode_Hu);
+                       return rol3;
                }
-               s1 = new_bd_ia32_Shl(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 24));
-               s2 = new_bd_ia32_Shl(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
-
-               m1 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s2, ia32_create_Immediate(NULL, 0, 0xFF00));
-               m2 = new_bd_ia32_Lea(dbgi, new_block, s1, m1);
-
-               s3 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
-
-               m3 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s3, ia32_create_Immediate(NULL, 0, 0xFF0000));
-               m4 = new_bd_ia32_Lea(dbgi, new_block, m2, m3);
-
-               s4 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 24));
-               return new_bd_ia32_Lea(dbgi, new_block, m4, s4);
 
        case 16:
                /* swap16 always available */
@@ -5471,7 +5492,7 @@ static ir_node *gen_Proj_Builtin(ir_node *proj)
        case ir_bk_parity:
        case ir_bk_popcount:
        case ir_bk_bswap:
-               assert(get_Proj_proj(proj) == pn_Builtin_1_result);
+               assert(get_Proj_proj(proj) == pn_Builtin_max+1);
                return new_node;
        case ir_bk_trap:
        case ir_bk_debugbreak:
@@ -5480,14 +5501,14 @@ static ir_node *gen_Proj_Builtin(ir_node *proj)
                assert(get_Proj_proj(proj) == pn_Builtin_M);
                return new_node;
        case ir_bk_inport:
-               if (get_Proj_proj(proj) == pn_Builtin_1_result) {
+               if (get_Proj_proj(proj) == pn_Builtin_max+1) {
                        return new_r_Proj(new_node, get_irn_mode(proj), pn_ia32_Inport_res);
                } else {
                        assert(get_Proj_proj(proj) == pn_Builtin_M);
                        return new_r_Proj(new_node, mode_M, pn_ia32_Inport_M);
                }
        case ir_bk_inner_trampoline:
-               if (get_Proj_proj(proj) == pn_Builtin_1_result) {
+               if (get_Proj_proj(proj) == pn_Builtin_max+1) {
                        return get_Tuple_pred(new_node, 1);
                } else {
                        assert(get_Proj_proj(proj) == pn_Builtin_M);
@@ -5731,6 +5752,7 @@ static void register_transformers(void)
        be_set_transform_function(op_Shrs,             gen_Shrs);
        be_set_transform_function(op_Store,            gen_Store);
        be_set_transform_function(op_Sub,              gen_Sub);
+       be_set_transform_function(op_Switch,           gen_Switch);
        be_set_transform_function(op_SymConst,         gen_SymConst);
        be_set_transform_function(op_Unknown,          ia32_gen_Unknown);
 }