fixed CopyB emitter
[libfirm] / ir / be / ia32 / ia32_optimize.c
index a72419a..755a281 100644 (file)
@@ -240,6 +240,15 @@ void ia32_place_consts_set_modes(ir_node *irn, void *env) {
                set_irn_mode(irn, mode);
        }
 
+       /*
+               Annotate mode of stored value to link field of the Store
+               as floating point converts might be optimized and we would
+               loose the mode.
+       */
+       if (get_irn_opcode(irn) == iro_Store) {
+               set_irn_link(irn, get_irn_mode(get_Store_value(irn)));
+       }
+
        tenv.block    = get_nodes_block(irn);
        tenv.cg       = cg;
        tenv.irg      = cg->irg;
@@ -431,24 +440,39 @@ static void ia32_create_Push(ir_node *irn, ia32_code_gen_t *cg) {
        ir_node *sp  = get_irn_n(irn, 0);
        ir_node *val, *next, *push, *bl, *proj_M, *proj_res, *old_proj_M;
        const ir_edge_t *edge;
+       heights_t *h;
 
-       if (get_ia32_am_offs(irn) || !be_is_IncSP(sp))
+       /* do not create push if store has already an offset assigned or base is not a IncSP */
+       if (get_ia32_am_offs(irn) || ! be_is_IncSP(sp))
                return;
 
+       /* do not create push if index is not NOREG */
        if (arch_get_irn_register(cg->arch_env, get_irn_n(irn, 1)) !=
                &ia32_gp_regs[REG_GP_NOREG])
                return;
 
+       /* do not create push for floating point */
        val = get_irn_n(irn, 2);
        if (mode_is_float(get_irn_mode(val)))
                return;
 
+       /* do not create push if IncSp doesn't expand stack or expand size is different from register size */
        if (be_get_IncSP_direction(sp) != be_stack_dir_expand ||
                be_get_IncSP_offset(sp) != get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode))
                return;
 
+       /* do not create push, if there is a path (inside the block) from the push value to IncSP */
+       h = heights_new(cg->irg);
+       if (get_nodes_block(val) == get_nodes_block(sp) &&
+               heights_reachable_in_block(h, val, sp))
+       {
+               heights_free(h);
+               return;
+       }
+       heights_free(h);
+
        /* ok, translate into Push */
-       edge = get_irn_out_edge_first(irn);
+       edge       = get_irn_out_edge_first(irn);
        old_proj_M = get_edge_src_irn(edge);
 
        next = sched_next(irn);
@@ -740,16 +764,17 @@ static int is_addr_candidate(const ir_node *block, const ir_node *irn) {
  * - the load must not have other users than the irn             AND
  * - the irn must not have a frame entity set
  *
+ * @param cg          The ia32 code generator
  * @param h           The height information of the irg
  * @param block       The block the Loads must/mustnot be in
  * @param irn         The irn to check
  * return 0 if irn is no candidate, 1 if left load can be used, 2 if right one, 3 for both
  */
-static ia32_am_cand_t is_am_candidate(heights_t *h, const ir_node *block, ir_node *irn) {
+static ia32_am_cand_t is_am_candidate(ia32_code_gen_t *cg, heights_t *h, const ir_node *block, ir_node *irn) {
        ir_node *in, *load, *other, *left, *right;
        int      n, is_cand = 0, cand;
 
-       if (is_ia32_Ld(irn) || is_ia32_St(irn) || is_ia32_Store8Bit(irn))
+       if (is_ia32_Ld(irn) || is_ia32_St(irn) || is_ia32_Store8Bit(irn) || is_ia32_vfild(irn) || is_ia32_vfist(irn))
                return 0;
 
        left  = get_irn_n(irn, 2);
@@ -791,6 +816,18 @@ static ia32_am_cand_t is_am_candidate(heights_t *h, const ir_node *block, ir_nod
 
        cand = is_cand ? (cand | IA32_AM_CAND_RIGHT) : cand;
 
+       /* check some special cases */
+       if (USE_SSE2(cg) && is_ia32_Conv_I2FP(irn)) {
+               /* SSE Conv I -> FP cvtsi2s(s|d) can only load 32 bit values */
+               if (get_mode_size_bits(get_ia32_tgt_mode(irn)) != 32)
+                       cand = IA32_AM_CAND_NONE;
+       }
+       else if (is_ia32_Conv_I2I(irn)) {
+               /* we cannot load an N bit value and implicitly convert it into an M bit value if N > M */
+               if (get_mode_size_bits(get_ia32_src_mode(irn)) > get_mode_size_bits(get_ia32_tgt_mode(irn)))
+                       cand = IA32_AM_CAND_NONE;
+       }
+
        /* if the irn has a frame entity: we do not use address mode */
        return get_ia32_frame_ent(irn) ? IA32_AM_CAND_NONE : cand;
 }
@@ -1021,12 +1058,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, ir_node *noreg) {
        }
 
        /* determine the operand which needs to be checked */
-       if (be_is_NoReg(cg, right)) {
-               temp = left;
-       }
-       else {
-               temp = right;
-       }
+       temp = be_is_NoReg(cg, right) ? left : right;
 
        /* check if right operand is AMConst (LEA with ia32_am_O)  */
        /* but we can only eat it up if there is no other symconst */
@@ -1040,6 +1072,9 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, ir_node *noreg) {
                have_am_sc = 1;
                dolea      = 1;
                lea_o      = temp;
+
+               if (temp == base)
+                       base = noreg;
        }
 
        if (isadd) {
@@ -1085,7 +1120,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, ir_node *noreg) {
                                /* index != right -> we found a good Shl           */
                                /* left  != LEA   -> this Shl was the left operand */
                                /* -> base is right operand                        */
-                               base = right;
+                               base = (right == lea_o) ? noreg : right;
                        }
                }
        }
@@ -1179,7 +1214,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn, ir_node *noreg) {
 
                am_flav = ia32_am_N;
                /* determine new am flavour */
-               if (offs || offs_cnst || offs_lea) {
+               if (offs || offs_cnst || offs_lea || have_am_sc) {
                        am_flav |= ia32_O;
                }
                if (! be_is_NoReg(cg, base)) {
@@ -1396,7 +1431,7 @@ static void optimize_am(ir_node *irn, void *env) {
        /*     - nobody else uses the result of the op                                      */
 
        if ((get_ia32_am_support(irn) != ia32_am_None) && ! is_ia32_Lea(irn)) {
-               ia32_am_cand_t cand      = is_am_candidate(h, block, irn);
+               ia32_am_cand_t cand      = is_am_candidate(cg, h, block, irn);
                ia32_am_cand_t orig_cand = cand;
 
                /* cand == 1: load is left;   cand == 2: load is right; */