Small simplification in ia32 ASM emitter.
[libfirm] / ir / be / ia32 / ia32_transform.c
index 3e0cc10..bf8b48d 100644 (file)
@@ -431,6 +431,44 @@ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct) {
        return ent_cache[kct];
 }
 
+static int prevents_AM(ir_node *const block, ir_node *const am_candidate,
+                       ir_node *const other)
+{
+       if (get_nodes_block(other) != block)
+               return 0;
+
+       if (is_Sync(other)) {
+               int i;
+
+               for (i = get_Sync_n_preds(other) - 1; i >= 0; --i) {
+                       ir_node *const pred = get_Sync_pred(other, i);
+
+                       if (get_nodes_block(pred) != block)
+                               continue;
+
+                       /* Do not block ourselves from getting eaten */
+                       if (is_Proj(pred) && get_Proj_pred(pred) == am_candidate)
+                               continue;
+
+                       if (!heights_reachable_in_block(heights, pred, am_candidate))
+                               continue;
+
+                       return 1;
+               }
+
+               return 0;
+       } else {
+               /* Do not block ourselves from getting eaten */
+               if (is_Proj(other) && get_Proj_pred(other) == am_candidate)
+                       return 0;
+
+               if (!heights_reachable_in_block(heights, other, am_candidate))
+                       return 0;
+
+               return 1;
+       }
+}
+
 /**
  * return true if the node is a Proj(Load) and could be used in source address
  * mode for another node. Will return only true if the @p other node is not
@@ -478,11 +516,10 @@ static int ia32_use_source_address_mode(ir_node *block, ir_node *node,
                return 0;
 
        /* don't do AM if other node inputs depend on the load (via mem-proj) */
-       if (other != NULL && get_nodes_block(other) == block &&
-           heights_reachable_in_block(heights, other, load))
+       if (other != NULL && prevents_AM(block, load, other))
                return 0;
-       if (other2 != NULL && get_nodes_block(other2) == block &&
-           heights_reachable_in_block(heights, other2, load))
+
+       if (other2 != NULL && prevents_AM(block, load, other2))
                return 0;
 
        return 1;
@@ -1315,6 +1352,49 @@ static ir_node *gen_Sub(ir_node *node) {
                        | match_am | match_immediate);
 }
 
+static ir_node *transform_AM_mem(ir_graph *const irg, ir_node *const block,
+                                 ir_node  *const src_val,
+                                 ir_node  *const src_mem,
+                                 ir_node  *const am_mem)
+{
+       if (is_NoMem(am_mem)) {
+               return be_transform_node(src_mem);
+       } else if (is_Proj(src_val) &&
+                  is_Proj(src_mem) &&
+                  get_Proj_pred(src_val) == get_Proj_pred(src_mem)) {
+               /* avoid memory loop */
+               return am_mem;
+       } else if (is_Proj(src_val) && is_Sync(src_mem)) {
+               ir_node  *const ptr_pred = get_Proj_pred(src_val);
+               int       const arity    = get_Sync_n_preds(src_mem);
+               int             n        = 0;
+               ir_node **      ins;
+               int             i;
+
+               NEW_ARR_A(ir_node*, ins, arity + 1);
+
+               for (i = arity - 1; i >= 0; --i) {
+                       ir_node *const pred = get_Sync_pred(src_mem, i);
+
+                       /* avoid memory loop */
+                       if (is_Proj(pred) && get_Proj_pred(pred) == ptr_pred)
+                               continue;
+
+                       ins[n++] = be_transform_node(pred);
+               }
+
+               ins[n++] = am_mem;
+
+               return new_r_Sync(irg, block, n, ins);
+       } else {
+               ir_node *ins[2];
+
+               ins[0] = be_transform_node(src_mem);
+               ins[1] = am_mem;
+               return new_r_Sync(irg, block, 2, ins);
+       }
+}
+
 /**
  * Generates an ia32 DivMod with additional infrastructure for the
  * register allocator if needed.
@@ -1364,17 +1444,7 @@ static ir_node *create_Div(ir_node *node)
        /* Beware: We don't need a Sync, if the memory predecessor of the Div node
           is the memory of the consumed address. We can have only the second op as address
           in Div nodes, so check only op2. */
-       if(!is_NoMem(mem) && skip_Proj(mem) != skip_Proj(op2)) {
-               new_mem = be_transform_node(mem);
-               if(!is_NoMem(addr->mem)) {
-                       ir_node *in[2];
-                       in[0] = new_mem;
-                       in[1] = addr->mem;
-                       new_mem = new_rd_Sync(dbgi, irg, new_block, 2, in);
-               }
-       } else {
-               new_mem = addr->mem;
-       }
+       new_mem = transform_AM_mem(irg, block, op2, mem, addr->mem);
 
        if (mode_is_signed(mode)) {
                ir_node *produceval = new_rd_ia32_ProduceVal(dbgi, irg, new_block);
@@ -2557,48 +2627,6 @@ static ir_node *gen_Cond(ir_node *node) {
        return new_node;
 }
 
-/**
- * Transforms a CopyB node.
- *
- * @return The transformed node.
- */
-static ir_node *gen_CopyB(ir_node *node) {
-       ir_node  *block    = be_transform_node(get_nodes_block(node));
-       ir_node  *src      = get_CopyB_src(node);
-       ir_node  *new_src  = be_transform_node(src);
-       ir_node  *dst      = get_CopyB_dst(node);
-       ir_node  *new_dst  = be_transform_node(dst);
-       ir_node  *mem      = get_CopyB_mem(node);
-       ir_node  *new_mem  = be_transform_node(mem);
-       ir_node  *res      = NULL;
-       ir_graph *irg      = current_ir_graph;
-       dbg_info *dbgi     = get_irn_dbg_info(node);
-       int      size      = get_type_size_bytes(get_CopyB_type(node));
-       int      rem;
-
-       /* If we have to copy more than 32 bytes, we use REP MOVSx and */
-       /* then we need the size explicitly in ECX.                    */
-       if (size >= 32 * 4) {
-               rem = size & 0x3; /* size % 4 */
-               size >>= 2;
-
-               res = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, size);
-               add_irn_dep(res, get_irg_frame(irg));
-
-               res = new_rd_ia32_CopyB(dbgi, irg, block, new_dst, new_src, res, new_mem, rem);
-       } else {
-               if(size == 0) {
-                       ir_fprintf(stderr, "Optimisation warning copyb %+F with size <4\n",
-                                  node);
-               }
-               res = new_rd_ia32_CopyB_i(dbgi, irg, block, new_dst, new_src, new_mem, size);
-       }
-
-       SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env_cg, node));
-
-       return res;
-}
-
 static ir_node *gen_be_Copy(ir_node *node)
 {
        ir_node *new_node = be_duplicate_node(node);
@@ -2723,64 +2751,31 @@ static ir_node *gen_Cmp(ir_node *node)
 
        assert(ia32_mode_needs_gp_reg(cmp_mode));
 
-       /* we prefer the Test instruction where possible except cases where
-        * we can use SourceAM */
+       /* Prefer the Test instruction, when encountering (x & y) ==/!= 0 */
        cmp_unsigned = !mode_is_signed(cmp_mode);
-       if (is_Const_0(right)) {
-               if (is_And(left) &&
-                               get_irn_n_edges(left) == 1 &&
-                               can_fold_test_and(node)) {
-                       /* Test(and_left, and_right) */
-                       ir_node *and_left  = get_And_left(left);
-                       ir_node *and_right = get_And_right(left);
-                       ir_mode *mode      = get_irn_mode(and_left);
-
-                       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_8bit | match_16bit);
-                       if (get_mode_size_bits(mode) == 8) {
-                               new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
-                                                               addr->index, addr->mem, am.new_op1,
-                                                               am.new_op2, am.ins_permuted,
-                                                               cmp_unsigned);
-                       } else {
-                               new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
-                                                           addr->index, addr->mem, am.new_op1,
-                                                           am.new_op2, am.ins_permuted, cmp_unsigned);
-                       }
+       if (is_Const_0(right)          &&
+           is_And(left)               &&
+           get_irn_n_edges(left) == 1 &&
+           can_fold_test_and(node)) {
+               /* Test(and_left, and_right) */
+               ir_node *and_left  = get_And_left(left);
+               ir_node *and_right = get_And_right(left);
+               ir_mode *mode      = get_irn_mode(and_left);
+
+               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_8bit | match_16bit);
+               if (get_mode_size_bits(mode) == 8) {
+                       new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
+                                                                                                                                                       addr->index, addr->mem, am.new_op1,
+                                                                                                                                                       am.new_op2, am.ins_permuted,
+                                                                                                                                                       cmp_unsigned);
                } else {
-                       match_arguments(&am, block, NULL, left, NULL,
-                                       match_am | match_8bit_am | match_16bit_am |
-                                       match_8bit | match_16bit);
-                       if (am.op_type == ia32_AddrModeS) {
-                               /* Cmp(AM, 0) */
-                               ir_node *imm_zero = try_create_Immediate(right, 0);
-                               if (get_mode_size_bits(cmp_mode) == 8) {
-                                       new_node = new_rd_ia32_Cmp8Bit(dbgi, irg, new_block, addr->base,
-                                                                      addr->index, addr->mem, am.new_op2,
-                                                                      imm_zero, am.ins_permuted,
-                                                                      cmp_unsigned);
-                               } else {
-                                       new_node = new_rd_ia32_Cmp(dbgi, irg, new_block, addr->base,
-                                                                  addr->index, addr->mem, am.new_op2,
-                                                                  imm_zero, am.ins_permuted, cmp_unsigned);
-                               }
-                       } else {
-                               /* Test(left, left) */
-                               if (get_mode_size_bits(cmp_mode) == 8) {
-                                       new_node = new_rd_ia32_Test8Bit(dbgi, irg, new_block, addr->base,
-                                                                       addr->index, addr->mem, am.new_op2,
-                                                                       am.new_op2, am.ins_permuted,
-                                                                       cmp_unsigned);
-                               } else {
-                                       new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
-                                                                   addr->index, addr->mem, am.new_op2,
-                                                                   am.new_op2, am.ins_permuted,
-                                                                   cmp_unsigned);
-                               }
-                       }
+                       new_node = new_rd_ia32_Test(dbgi, irg, new_block, addr->base,
+                                                                                                                                       addr->index, addr->mem, am.new_op1,
+                                                                                                                                       am.new_op2, am.ins_permuted, cmp_unsigned);
                }
        } else {
                /* Cmp(left, right) */
@@ -2800,7 +2795,6 @@ static ir_node *gen_Cmp(ir_node *node)
                }
        }
        set_am_attributes(new_node, &am);
-       assert(cmp_mode != NULL);
        set_ia32_ls_mode(new_node, cmp_mode);
 
        SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
@@ -4322,18 +4316,6 @@ static ir_node *gen_Proj_Quot(ir_node *node) {
        return new_rd_Unknown(irg, mode);
 }
 
-/**
- * Transform the Thread Local Storage Proj.
- */
-static ir_node *gen_Proj_tls(ir_node *node) {
-       ir_node  *block = be_transform_node(get_nodes_block(node));
-       ir_graph *irg   = current_ir_graph;
-       dbg_info *dbgi  = NULL;
-       ir_node  *res   = new_rd_ia32_LdTls(dbgi, irg, block, mode_Iu);
-
-       return res;
-}
-
 static ir_node *gen_be_Call(ir_node *node) {
        ir_node *res = be_duplicate_node(node);
        be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
@@ -4684,8 +4666,8 @@ static void ia32_pretransform_node(void *arch_cg) {
 }
 
 /**
- * Walker, checks if all ia32 nodes producing more than one result have
- * its Projs, otherwise creates new Projs and keep them using a be_Keep node.
+ * Walker, checks if all ia32 nodes producing more than one result have their
+ * Projs, otherwise creates new Projs and keeps them using a be_Keep node.
  */
 static void add_missing_keep_walker(ir_node *node, void *data)
 {