OSDN Git Service

2012-01-30 Pascal Obry <obry@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-phiopt.c
index 3accbbc..b739bbc 100644 (file)
@@ -1,6 +1,6 @@
 /* Optimization of PHI nodes by converting them into straightline code.
-   Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation,
-   Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,18 +24,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "ggc.h"
 #include "tree.h"
-#include "rtl.h"
 #include "flags.h"
 #include "tm_p.h"
 #include "basic-block.h"
 #include "timevar.h"
-#include "diagnostic.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-dump.h"
 #include "langhooks.h"
 #include "pointer-set.h"
 #include "domwalk.h"
+#include "cfgloop.h"
+#include "tree-data-ref.h"
 
 static unsigned int tree_ssa_phiopt (void);
 static unsigned int tree_ssa_phiopt_worker (bool);
@@ -49,6 +49,7 @@ static bool abs_replacement (basic_block, basic_block,
                             edge, edge, gimple, tree, tree);
 static bool cond_store_replacement (basic_block, basic_block, edge, edge,
                                    struct pointer_set_t *);
+static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block);
 static struct pointer_set_t * get_non_trapping (void);
 static void replace_phi_edge_with_variable (basic_block, edge, gimple, tree);
 
@@ -151,7 +152,7 @@ tree_ssa_phiopt (void)
      bb0:
        if (cond) goto bb2; else goto bb1;
      bb1:
-       *p = RHS
+       *p = RHS;
      bb2:
 
    with
@@ -162,10 +163,28 @@ tree_ssa_phiopt (void)
        condtmp' = *p;
      bb2:
        condtmp = PHI <RHS, condtmp'>
-       *p = condtmp
+       *p = condtmp;
 
    This transformation can only be done under several constraints,
-   documented below.  */
+   documented below.  It also replaces:
+
+     bb0:
+       if (cond) goto bb2; else goto bb1;
+     bb1:
+       *p = RHS1;
+       goto bb3;
+     bb2:
+       *p = RHS2;
+     bb3:
+
+   with
+
+     bb0:
+       if (cond) goto bb3; else goto bb1;
+     bb1:
+     bb3:
+       condtmp = PHI <RHS1, RHS2>
+       *p = condtmp;  */
 
 static unsigned int
 tree_ssa_cs_elim (void)
@@ -207,7 +226,7 @@ tree_ssa_phiopt_worker (bool do_store_elim)
   bb_order = blocks_in_phiopt_order ();
   n = n_basic_blocks - NUM_FIXED_BLOCKS;
 
-  for (i = 0; i < n; i++) 
+  for (i = 0; i < n; i++)
     {
       gimple cond_stmt, phi;
       basic_block bb1, bb2;
@@ -250,8 +269,23 @@ tree_ssa_phiopt_worker (bool do_store_elim)
          e1 = e2;
          e2 = e_tmp;
        }
+      else if (do_store_elim
+              && EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest)
+       {
+         basic_block bb3 = EDGE_SUCC (bb1, 0)->dest;
+
+         if (!single_succ_p (bb1)
+             || (EDGE_SUCC (bb1, 0)->flags & EDGE_FALLTHRU) == 0
+             || !single_succ_p (bb2)
+             || (EDGE_SUCC (bb2, 0)->flags & EDGE_FALLTHRU) == 0
+             || EDGE_COUNT (bb3->preds) != 2)
+           continue;
+         if (cond_if_else_store_replacement (bb1, bb2, bb3))
+           cfgchanged = true;
+         continue;
+       }
       else
-        continue;
+       continue;      
 
       e1 = EDGE_SUCC (bb1, 0);
 
@@ -279,14 +313,26 @@ tree_ssa_phiopt_worker (bool do_store_elim)
       else
        {
          gimple_seq phis = phi_nodes (bb2);
+         gimple_stmt_iterator gsi;
 
-         /* Check to make sure that there is only one PHI node.
+         /* Check to make sure that there is only one non-virtual PHI node.
             TODO: we could do it with more than one iff the other PHI nodes
             have the same elements for these two edges.  */
-         if (! gimple_seq_singleton_p (phis))
+         phi = NULL;
+         for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
+           {
+             if (!is_gimple_reg (gimple_phi_result (gsi_stmt (gsi))))
+               continue;
+             if (phi)
+               {
+                 phi = NULL;
+                 break;
+               }
+             phi = gsi_stmt (gsi);
+           }
+         if (!phi)
            continue;
 
-         phi = gsi_stmt (gsi_start (phis));
          arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
          arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
 
@@ -307,7 +353,7 @@ tree_ssa_phiopt_worker (bool do_store_elim)
     }
 
   free (bb_order);
-  
+
   if (do_store_elim)
     pointer_set_destroy (nontrap);
   /* If the CFG has changed, we should cleanup the CFG.  */
@@ -332,12 +378,12 @@ blocks_in_phiopt_order (void)
 {
   basic_block x, y;
   basic_block *order = XNEWVEC (basic_block, n_basic_blocks);
-  unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS; 
+  unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS;
   unsigned np, i;
-  sbitmap visited = sbitmap_alloc (last_basic_block); 
+  sbitmap visited = sbitmap_alloc (last_basic_block);
 
-#define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index)) 
-#define VISITED_P(BB) (TEST_BIT (visited, (BB)->index)) 
+#define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index))
+#define VISITED_P(BB) (TEST_BIT (visited, (BB)->index))
 
   sbitmap_zero (visited);
 
@@ -498,8 +544,9 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
   /* To handle special cases like floating point comparison, it is easier and
      less error-prone to build a tree and gimplify it on the fly though it is
      less efficient.  */
-  cond = fold_build2 (gimple_cond_code (stmt), boolean_type_node,
-                     gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
+  cond = fold_build2_loc (gimple_location (stmt),
+                         gimple_cond_code (stmt), boolean_type_node,
+                         gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
 
   /* We need to know which is the true edge and which is the false
      edge so that we know when to invert the condition below.  */
@@ -508,7 +555,8 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
       || (e0 == false_edge && integer_onep (arg0))
       || (e1 == true_edge && integer_zerop (arg1))
       || (e1 == false_edge && integer_onep (arg1)))
-    cond = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);
+    cond = fold_build1_loc (gimple_location (stmt),
+                           TRUTH_NOT_EXPR, TREE_TYPE (cond), cond);
 
   /* Insert our new statements at the end of conditional block before the
      COND_STMT.  */
@@ -543,6 +591,38 @@ conditional_replacement (basic_block cond_bb, basic_block middle_bb,
   return true;
 }
 
+/* Update *ARG which is defined in STMT so that it contains the
+   computed value if that seems profitable.  Return true if the
+   statement is made dead by that rewriting.  */
+
+static bool
+jump_function_from_stmt (tree *arg, gimple stmt)
+{
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  if (code == ADDR_EXPR)
+    {
+      /* For arg = &p->i transform it to p, if possible.  */
+      tree rhs1 = gimple_assign_rhs1 (stmt);
+      HOST_WIDE_INT offset;
+      tree tem = get_addr_base_and_unit_offset (TREE_OPERAND (rhs1, 0),
+                                               &offset);
+      if (tem
+         && TREE_CODE (tem) == MEM_REF
+         && double_int_zero_p
+              (double_int_add (mem_ref_offset (tem),
+                               shwi_to_double_int (offset))))
+       {
+         *arg = TREE_OPERAND (tem, 0);
+         return true;
+       }
+    }
+  /* TODO: Much like IPA-CP jump-functions we want to handle constant
+     additions symbolically here, and we'd need to update the comparison
+     code that compares the arg + cst tuples in our caller.  For now the
+     code above exactly handles the VEC_BASE pattern from vec.h.  */
+  return false;
+}
+
 /*  The function value_replacement does the main work of doing the value
     replacement.  Return true if the replacement is done.  Otherwise return
     false.
@@ -554,6 +634,7 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
                   edge e0, edge e1, gimple phi,
                   tree arg0, tree arg1)
 {
+  gimple_stmt_iterator gsi;
   gimple cond;
   edge true_edge, false_edge;
   enum tree_code code;
@@ -563,8 +644,32 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
   if (HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
     return false;
 
-  if (!empty_block_p (middle_bb))
-    return false;
+  /* Allow a single statement in MIDDLE_BB that defines one of the PHI
+     arguments.  */
+  gsi = gsi_after_labels (middle_bb);
+  if (!gsi_end_p (gsi))
+    {
+      if (is_gimple_debug (gsi_stmt (gsi)))
+       gsi_next_nondebug (&gsi);
+      if (!gsi_end_p (gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         tree lhs;
+         gsi_next_nondebug (&gsi);
+         if (!gsi_end_p (gsi))
+           return false;
+         if (!is_gimple_assign (stmt))
+           return false;
+         /* Now try to adjust arg0 or arg1 according to the computation
+            in the single statement.  */
+         lhs = gimple_assign_lhs (stmt);
+         if (!((lhs == arg0
+                && jump_function_from_stmt (&arg0, stmt))
+               || (lhs == arg1
+                   && jump_function_from_stmt (&arg1, stmt))))
+           return false;
+       }
+    }
 
   cond = last_stmt (cond_bb);
   code = gimple_cond_code (cond);
@@ -649,7 +754,6 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
 
   cond = last_stmt (cond_bb);
   cmp = gimple_cond_code (cond);
-  result = PHI_RESULT (phi);
 
   /* This transformation is only valid for order comparisons.  Record which
      operand is smaller/larger if the result of the comparison is true.  */
@@ -696,7 +800,7 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
          && operand_equal_for_phi_arg_p (arg_false, larger))
        {
          /* Case
-        
+
             if (smaller < larger)
             rslt = smaller;
             else
@@ -905,7 +1009,7 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
      optimize.  */
   if (assign == NULL)
     return false;
-      
+
   /* If we got here, then we have found the only executable statement
      in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
      arg1 = -arg0, then we can not optimize.  */
@@ -918,7 +1022,7 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
     return false;
 
   rhs = gimple_assign_rhs1 (assign);
-              
+
   /* The assignment has to be arg0 = -arg1 or arg1 = -arg0.  */
   if (!(lhs == arg0 && rhs == arg1)
       && !(lhs == arg1 && rhs == arg0))
@@ -996,10 +1100,10 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
 
 /* Auxiliary functions to determine the set of memory accesses which
    can't trap because they are preceded by accesses to the same memory
-   portion.  We do that for INDIRECT_REFs, so we only need to track
+   portion.  We do that for MEM_REFs, so we only need to track
    the SSA_NAME of the pointer indirectly referenced.  The algorithm
    simply is a walk over all instructions in dominator order.  When
-   we see an INDIRECT_REF we determine if we've already seen a same
+   we see an MEM_REF we determine if we've already seen a same
    ref anywhere up to the root of the dominator tree.  If we do the
    current access can't trap.  If we don't see any dominating access
    the current access might trap, but might also make later accesses
@@ -1013,7 +1117,7 @@ abs_replacement (basic_block cond_bb, basic_block middle_bb,
    trap even if a store doesn't (write-only memory).  This probably is
    overly conservative.  */
 
-/* A hash-table of SSA_NAMEs, and in which basic block an INDIRECT_REF
+/* A hash-table of SSA_NAMEs, and in which basic block an MEM_REF
    through it was seen, which would constitute a no-trap region for
    same accesses.  */
 struct name_to_bb
@@ -1026,7 +1130,7 @@ struct name_to_bb
 /* The hash table for remembering what we've seen.  */
 static htab_t seen_ssa_names;
 
-/* The set of INDIRECT_REFs which can't trap.  */
+/* The set of MEM_REFs which can't trap.  */
 static struct pointer_set_t *nontrap_set;
 
 /* The hash function, based on the pointer to the pointer SSA_NAME.  */
@@ -1049,7 +1153,7 @@ name_to_bb_eq (const void *p1, const void *p2)
 }
 
 /* We see the expression EXP in basic block BB.  If it's an interesting
-   expression (an INDIRECT_REF through an SSA_NAME) possibly insert the
+   expression (an MEM_REF through an SSA_NAME) possibly insert the
    expression into the set NONTRAP or the hash table of seen expressions.
    STORE is true if this expression is on the LHS, otherwise it's on
    the RHS.  */
@@ -1057,7 +1161,7 @@ static void
 add_or_mark_expr (basic_block bb, tree exp,
                  struct pointer_set_t *nontrap, bool store)
 {
-  if (INDIRECT_REF_P (exp)
+  if (TREE_CODE (exp) == MEM_REF
       && TREE_CODE (TREE_OPERAND (exp, 0)) == SSA_NAME)
     {
       tree name = TREE_OPERAND (exp, 0);
@@ -1066,7 +1170,7 @@ add_or_mark_expr (basic_block bb, tree exp,
       struct name_to_bb *n2bb;
       basic_block found_bb = 0;
 
-      /* Try to find the last seen INDIRECT_REF through the same
+      /* Try to find the last seen MEM_REF through the same
          SSA_NAME, which can trap.  */
       map.ssa_name = name;
       map.bb = 0;
@@ -1076,7 +1180,7 @@ add_or_mark_expr (basic_block bb, tree exp,
       if (n2bb)
         found_bb = n2bb->bb;
 
-      /* If we've found a trapping INDIRECT_REF, _and_ it dominates EXP
+      /* If we've found a trapping MEM_REF, _and_ it dominates EXP
          (it's in a basic block on the path from us to the dominator root)
         then we can't trap.  */
       if (found_bb && found_bb->aux == (void *)1)
@@ -1137,7 +1241,7 @@ nt_fini_block (struct dom_walk_data *data ATTRIBUTE_UNUSED, basic_block bb)
 /* This is the entry point of gathering non trapping memory accesses.
    It will do a dominator walk over the whole function, and it will
    make use of the bb->aux pointers.  It returns a set of trees
-   (the INDIRECT_REFs itself) which can't trap.  */
+   (the MEM_REFs itself) which can't trap.  */
 static struct pointer_set_t *
 get_non_trapping (void)
 {
@@ -1192,24 +1296,20 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
   gimple newphi, new_stmt;
   gimple_stmt_iterator gsi;
   source_location locus;
-  enum tree_code code;
 
   /* Check if middle_bb contains of only one store.  */
   if (!assign
-      || gimple_code (assign) != GIMPLE_ASSIGN)
+      || !gimple_assign_single_p (assign))
     return false;
 
   locus = gimple_location (assign);
   lhs = gimple_assign_lhs (assign);
   rhs = gimple_assign_rhs1 (assign);
-  if (!INDIRECT_REF_P (lhs))
+  if (TREE_CODE (lhs) != MEM_REF
+      || TREE_CODE (TREE_OPERAND (lhs, 0)) != SSA_NAME
+      || !is_gimple_reg_type (TREE_TYPE (lhs)))
     return false;
 
-  /* RHS is either a single SSA_NAME or a constant. */
-  code = gimple_assign_rhs_code (assign);
-  if (get_gimple_rhs_class (code) != GIMPLE_SINGLE_RHS
-      || (code != SSA_NAME && !is_gimple_min_invariant (rhs)))
-    return false;
   /* Prove that we can move the store down.  We could also check
      TREE_THIS_NOTRAP here, but in that case we also could move stores,
      whose value is not available readily, which we want to avoid.  */
@@ -1218,20 +1318,15 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
 
   /* Now we've checked the constraints, so do the transformation:
      1) Remove the single store.  */
-  mark_symbols_for_renaming (assign);
   gsi = gsi_for_stmt (assign);
+  unlink_stmt_vdef (assign);
   gsi_remove (&gsi, true);
+  release_defs (assign);
 
   /* 2) Create a temporary where we can store the old content
         of the memory touched by the store, if we need to.  */
   if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
-    {
-      condstoretemp = create_tmp_var (TREE_TYPE (lhs), "cstore");
-      get_var_ann (condstoretemp);
-      if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE
-          || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
-       DECL_GIMPLE_REG_P (condstoretemp) = 1;
-    }
+    condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
   add_referenced_var (condstoretemp);
 
   /* 3) Insert a load from the memory of the store to the temporary
@@ -1241,7 +1336,6 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
   name = make_ssa_name (condstoretemp, new_stmt);
   gimple_assign_set_lhs (new_stmt, name);
   gimple_set_location (new_stmt, locus);
-  mark_symbols_for_renaming (new_stmt);
   gsi_insert_on_edge (e1, new_stmt);
 
   /* 4) Create a PHI node at the join block, with one argument
@@ -1253,7 +1347,6 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
 
   lhs = unshare_expr (lhs);
   new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
-  mark_symbols_for_renaming (new_stmt);
 
   /* 5) Insert that PHI node.  */
   gsi = gsi_after_labels (join_bb);
@@ -1268,6 +1361,265 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
   return true;
 }
 
+/* Do the main work of conditional store replacement.  */
+
+static bool
+cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb,
+                                 basic_block join_bb, gimple then_assign,
+                                 gimple else_assign)
+{
+  tree lhs_base, lhs, then_rhs, else_rhs;
+  source_location then_locus, else_locus;
+  gimple_stmt_iterator gsi;
+  gimple newphi, new_stmt;
+
+  if (then_assign == NULL
+      || !gimple_assign_single_p (then_assign)
+      || gimple_clobber_p (then_assign)
+      || else_assign == NULL
+      || !gimple_assign_single_p (else_assign)
+      || gimple_clobber_p (else_assign))
+    return false;
+
+  lhs = gimple_assign_lhs (then_assign);
+  if (!is_gimple_reg_type (TREE_TYPE (lhs))
+      || !operand_equal_p (lhs, gimple_assign_lhs (else_assign), 0))
+    return false;
+
+  lhs_base = get_base_address (lhs);
+  if (lhs_base == NULL_TREE
+      || (!DECL_P (lhs_base) && TREE_CODE (lhs_base) != MEM_REF))
+    return false;
+
+  then_rhs = gimple_assign_rhs1 (then_assign);
+  else_rhs = gimple_assign_rhs1 (else_assign);
+  then_locus = gimple_location (then_assign);
+  else_locus = gimple_location (else_assign);
+
+  /* Now we've checked the constraints, so do the transformation:
+     1) Remove the stores.  */
+  gsi = gsi_for_stmt (then_assign);
+  unlink_stmt_vdef (then_assign);
+  gsi_remove (&gsi, true);
+  release_defs (then_assign);
+
+  gsi = gsi_for_stmt (else_assign);
+  unlink_stmt_vdef (else_assign);
+  gsi_remove (&gsi, true);
+  release_defs (else_assign);
+
+  /* 2) Create a temporary where we can store the old content
+       of the memory touched by the store, if we need to.  */
+  if (!condstoretemp || TREE_TYPE (lhs) != TREE_TYPE (condstoretemp))
+    condstoretemp = create_tmp_reg (TREE_TYPE (lhs), "cstore");
+  add_referenced_var (condstoretemp);
+
+  /* 3) Create a PHI node at the join block, with one argument
+       holding the old RHS, and the other holding the temporary
+       where we stored the old memory contents.  */
+  newphi = create_phi_node (condstoretemp, join_bb);
+  add_phi_arg (newphi, then_rhs, EDGE_SUCC (then_bb, 0), then_locus);
+  add_phi_arg (newphi, else_rhs, EDGE_SUCC (else_bb, 0), else_locus);
+
+  new_stmt = gimple_build_assign (lhs, PHI_RESULT (newphi));
+
+  /* 4) Insert that PHI node.  */
+  gsi = gsi_after_labels (join_bb);
+  if (gsi_end_p (gsi))
+    {
+      gsi = gsi_last_bb (join_bb);
+      gsi_insert_after (&gsi, new_stmt, GSI_NEW_STMT);
+    }
+  else
+    gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT);
+
+  return true;
+}
+
+/* Conditional store replacement.  We already know
+   that the recognized pattern looks like so:
+
+   split:
+     if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
+   THEN_BB:
+     ...
+     X = Y;
+     ...
+     goto JOIN_BB;
+   ELSE_BB:
+     ...
+     X = Z;
+     ...
+     fallthrough (edge E0)
+   JOIN_BB:
+     some more
+
+   We check that it is safe to sink the store to JOIN_BB by verifying that
+   there are no read-after-write or write-after-write dependencies in
+   THEN_BB and ELSE_BB.  */
+
+static bool
+cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb,
+                                basic_block join_bb)
+{
+  gimple then_assign = last_and_only_stmt (then_bb);
+  gimple else_assign = last_and_only_stmt (else_bb);
+  VEC (data_reference_p, heap) *then_datarefs, *else_datarefs;
+  VEC (ddr_p, heap) *then_ddrs, *else_ddrs;
+  gimple then_store, else_store;
+  bool found, ok = false, res;
+  struct data_dependence_relation *ddr;
+  data_reference_p then_dr, else_dr;
+  int i, j;
+  tree then_lhs, else_lhs;
+  VEC (gimple, heap) *then_stores, *else_stores;
+  basic_block blocks[3];
+
+  if (MAX_STORES_TO_SINK == 0)
+    return false;
+
+  /* Handle the case with single statement in THEN_BB and ELSE_BB.  */
+  if (then_assign && else_assign)
+    return cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
+                                             then_assign, else_assign);
+
+  /* Find data references.  */
+  then_datarefs = VEC_alloc (data_reference_p, heap, 1);
+  else_datarefs = VEC_alloc (data_reference_p, heap, 1);
+  if ((find_data_references_in_bb (NULL, then_bb, &then_datarefs)
+        == chrec_dont_know)
+      || !VEC_length (data_reference_p, then_datarefs)
+      || (find_data_references_in_bb (NULL, else_bb, &else_datarefs)
+        == chrec_dont_know)
+      || !VEC_length (data_reference_p, else_datarefs))
+    {
+      free_data_refs (then_datarefs);
+      free_data_refs (else_datarefs);
+      return false;
+    }
+
+  /* Find pairs of stores with equal LHS.  */
+  then_stores = VEC_alloc (gimple, heap, 1);
+  else_stores = VEC_alloc (gimple, heap, 1);
+  FOR_EACH_VEC_ELT (data_reference_p, then_datarefs, i, then_dr)
+    {
+      if (DR_IS_READ (then_dr))
+        continue;
+
+      then_store = DR_STMT (then_dr);
+      then_lhs = gimple_get_lhs (then_store);
+      found = false;
+
+      FOR_EACH_VEC_ELT (data_reference_p, else_datarefs, j, else_dr)
+        {
+          if (DR_IS_READ (else_dr))
+            continue;
+
+          else_store = DR_STMT (else_dr);
+          else_lhs = gimple_get_lhs (else_store);
+
+          if (operand_equal_p (then_lhs, else_lhs, 0))
+            {
+              found = true;
+              break;
+            }
+        }
+
+      if (!found)
+        continue;
+
+      VEC_safe_push (gimple, heap, then_stores, then_store);
+      VEC_safe_push (gimple, heap, else_stores, else_store);
+    }
+
+  /* No pairs of stores found.  */
+  if (!VEC_length (gimple, then_stores)
+      || VEC_length (gimple, then_stores) > (unsigned) MAX_STORES_TO_SINK)
+    {
+      free_data_refs (then_datarefs);
+      free_data_refs (else_datarefs);
+      VEC_free (gimple, heap, then_stores);
+      VEC_free (gimple, heap, else_stores);
+      return false;
+    }
+
+  /* Compute and check data dependencies in both basic blocks.  */
+  then_ddrs = VEC_alloc (ddr_p, heap, 1);
+  else_ddrs = VEC_alloc (ddr_p, heap, 1);
+  compute_all_dependences (then_datarefs, &then_ddrs, NULL, false);
+  compute_all_dependences (else_datarefs, &else_ddrs, NULL, false);
+  blocks[0] = then_bb;
+  blocks[1] = else_bb;
+  blocks[2] = join_bb;
+  renumber_gimple_stmt_uids_in_blocks (blocks, 3);
+
+  /* Check that there are no read-after-write or write-after-write dependencies
+     in THEN_BB.  */
+  FOR_EACH_VEC_ELT (ddr_p, then_ddrs, i, ddr)
+    {
+      struct data_reference *dra = DDR_A (ddr);
+      struct data_reference *drb = DDR_B (ddr);
+
+      if (DDR_ARE_DEPENDENT (ddr) != chrec_known
+          && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
+               && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
+              || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
+                  && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
+              || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
+        {
+          free_dependence_relations (then_ddrs);
+          free_dependence_relations (else_ddrs);
+         free_data_refs (then_datarefs);
+         free_data_refs (else_datarefs);
+          VEC_free (gimple, heap, then_stores);
+          VEC_free (gimple, heap, else_stores);
+          return false;
+        }
+    }
+
+  /* Check that there are no read-after-write or write-after-write dependencies
+     in ELSE_BB.  */
+  FOR_EACH_VEC_ELT (ddr_p, else_ddrs, i, ddr)
+    {
+      struct data_reference *dra = DDR_A (ddr);
+      struct data_reference *drb = DDR_B (ddr);
+
+      if (DDR_ARE_DEPENDENT (ddr) != chrec_known
+          && ((DR_IS_READ (dra) && DR_IS_WRITE (drb)
+               && gimple_uid (DR_STMT (dra)) > gimple_uid (DR_STMT (drb)))
+              || (DR_IS_READ (drb) && DR_IS_WRITE (dra)
+                  && gimple_uid (DR_STMT (drb)) > gimple_uid (DR_STMT (dra)))
+              || (DR_IS_WRITE (dra) && DR_IS_WRITE (drb))))
+        {
+          free_dependence_relations (then_ddrs);
+          free_dependence_relations (else_ddrs);
+         free_data_refs (then_datarefs);
+         free_data_refs (else_datarefs);
+          VEC_free (gimple, heap, then_stores);
+          VEC_free (gimple, heap, else_stores);
+          return false;
+        }
+    }
+
+  /* Sink stores with same LHS.  */
+  FOR_EACH_VEC_ELT (gimple, then_stores, i, then_store)
+    {
+      else_store = VEC_index (gimple, else_stores, i);
+      res = cond_if_else_store_replacement_1 (then_bb, else_bb, join_bb,
+                                              then_store, else_store);
+      ok = ok || res;
+    }
+
+  free_dependence_relations (then_ddrs);
+  free_dependence_relations (else_ddrs);
+  free_data_refs (then_datarefs);
+  free_data_refs (else_datarefs);
+  VEC_free (gimple, heap, then_stores);
+  VEC_free (gimple, heap, else_stores);
+
+  return ok;
+}
+
 /* Always do these optimizations if we have SSA
    trees to work on.  */
 static bool
@@ -1291,8 +1643,7 @@ struct gimple_opt_pass pass_phiopt =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func
-    | TODO_ggc_collect
+  TODO_ggc_collect
     | TODO_verify_ssa
     | TODO_verify_flow
     | TODO_verify_stmts                        /* todo_flags_finish */
@@ -1320,8 +1671,7 @@ struct gimple_opt_pass pass_cselim =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func
-    | TODO_ggc_collect
+  TODO_ggc_collect
     | TODO_verify_ssa
     | TODO_verify_flow
     | TODO_verify_stmts                        /* todo_flags_finish */