tree-ssa-pre.c (eliminate_dom_walker::before_dom_children): Rewrite to propagate...
authorRichard Biener <rguenther@suse.de>
Fri, 13 Jun 2014 10:21:40 +0000 (10:21 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 13 Jun 2014 10:21:40 +0000 (10:21 +0000)
2014-06-13  Richard Biener  <rguenther@suse.de>

* tree-ssa-pre.c (eliminate_dom_walker::before_dom_children):
Rewrite to propagate the VN result into all uses where
possible and to remove stmts becoming dead because of that.
(eliminate): Generalize stmt removal handling, remove in
reverse dominator order to support proper debug stmt
generation.  Update stmts before removing stmts.
* tree-ssa-propagate.c (propagate_tree_value): Remove
bogus assert.

* c-c++-common/pr46562-2.c: Adjust.
* g++.dg/tree-ssa/pr8781.C: Likewise.
* gcc.dg/tree-ssa/ssa-fre-24.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-25.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-32.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-39.c: Likewise.
* gcc.dg/tree-ssa/ssa-pre-16.c: Likewise.

From-SVN: r211625

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/pr46562-2.c
gcc/testsuite/g++.dg/tree-ssa/pr8781.C
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c
gcc/tree-ssa-pre.c
gcc/tree-ssa-propagate.c

index 3ddd98c..1e30212 100644 (file)
@@ -1,3 +1,14 @@
+2014-06-13  Richard Biener  <rguenther@suse.de>
+
+       * tree-ssa-pre.c (eliminate_dom_walker::before_dom_children):
+       Rewrite to propagate the VN result into all uses where
+       possible and to remove stmts becoming dead because of that.
+       (eliminate): Generalize stmt removal handling, remove in
+       reverse dominator order to support proper debug stmt
+       generation.  Update stmts before removing stmts.
+       * tree-ssa-propagate.c (propagate_tree_value): Remove
+       bogus assert.
+
 2014-06-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        PR tree-optimization/61375
index 7bb2d7a..d6bb704 100644 (file)
@@ -1,3 +1,13 @@
+2014-06-13  Richard Biener  <rguenther@suse.de>
+
+       * c-c++-common/pr46562-2.c: Adjust.
+       * g++.dg/tree-ssa/pr8781.C: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-24.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-25.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-32.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-fre-39.c: Likewise.
+       * gcc.dg/tree-ssa/ssa-pre-16.c: Likewise.
+
 2014-06-13  Thomas Preud'homme  <thomas.preudhomme@arm.com>
 
        PR tree-optimization/61375
index 45bf5cf..e64432c 100644 (file)
@@ -9,5 +9,5 @@ int foo(void)
   return *p;
 }
 
-/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */
+/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index bf75413..19549c4 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */
 
 int f();
 
@@ -24,5 +24,5 @@ int x()
 
 /* We should optimize this to a direct call.  */
 
-/* { dg-final { scan-tree-dump "converting indirect call to function int f()" "fre1" } } */
+/* { dg-final { scan-tree-dump-times "= f \\(\\);" 1 "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index c683218..833a1b9 100644 (file)
@@ -30,5 +30,5 @@ int bazzoo (void)
   return b.i;
 }
 
-/* { dg-final { scan-tree-dump-times "= 0;" 5 "fre1" } } */
+/* { dg-final { scan-tree-dump-times "return 0;" 4 "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index e7723f9..5317a18 100644 (file)
@@ -14,5 +14,5 @@ int foo (struct X *p)
 
 /* We should optimize this to return 0.  */
 
-/* { dg-final { scan-tree-dump "= 0;" "fre1" } } */
+/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index 537fd5a..ad4f1d0 100644 (file)
@@ -23,6 +23,6 @@ bar (_Complex float x)
   return z;
 } 
 
-/* We should CSE all the way to replace the final assignment to z with x.  */
-/* { dg-final { scan-tree-dump-times "with x_1\\\(D\\\) in z" 3 "fre1" } } */
+/* We should CSE all the way to replace the return value with x.  */
+/* { dg-final { scan-tree-dump-times "return x_\\d\+\\(D\\);" 2 "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index a30926c..4c5ed0b 100644 (file)
@@ -15,5 +15,5 @@ int foo (int i)
 
 /* We should be able to value-number the final assignment to k to 1.  */
 
-/* { dg-final { scan-tree-dump "k_. = 1;" "fre1" } } */
+/* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
 /* { dg-final { cleanup-tree-dump "fre1" } } */
index b087dc1..7bc1dd3 100644 (file)
@@ -11,5 +11,5 @@ int foo(int k, int *x)
   }  while (++j<k);
   return res;
 }
-/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
+/* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
 /* { dg-final { cleanup-tree-dump "pre" } } */
index 89e94e9..b7550b9 100644 (file)
@@ -4012,120 +4012,93 @@ eliminate_dom_walker::before_dom_children (basic_block b)
   /* Mark new bb.  */
   el_avail_stack.safe_push (NULL_TREE);
 
-  /* If this block is not reachable do nothing.  */
-  edge_iterator ei;
-  edge e;
-  FOR_EACH_EDGE (e, ei, b->preds)
-    if (e->flags & EDGE_EXECUTABLE)
-      break;
-  if (!e)
-    return;
+  /* ???  If we do nothing for unreachable blocks then this will confuse
+     tailmerging.  Eventually we can reduce its reliance on SCCVN now
+     that we fully copy/constant-propagate (most) things.  */
 
   for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
     {
-      gimple stmt, phi = gsi_stmt (gsi);
-      tree sprime = NULL_TREE, res = PHI_RESULT (phi);
-      gimple_stmt_iterator gsi2;
-
-      /* We want to perform redundant PHI elimination.  Do so by
-        replacing the PHI with a single copy if possible.
-        Do not touch inserted, single-argument or virtual PHIs.  */
-      if (gimple_phi_num_args (phi) == 1
-         || virtual_operand_p (res))
-       {
-         gsi_next (&gsi);
-         continue;
-       }
+      gimple phi = gsi_stmt (gsi);
+      tree res = PHI_RESULT (phi);
 
-      sprime = eliminate_avail (res);
-      if (!sprime
-         || sprime == res)
+      if (virtual_operand_p (res))
        {
-         eliminate_push_avail (res);
          gsi_next (&gsi);
          continue;
        }
-      else if (is_gimple_min_invariant (sprime))
-       {
-         if (!useless_type_conversion_p (TREE_TYPE (res),
-                                         TREE_TYPE (sprime)))
-           sprime = fold_convert (TREE_TYPE (res), sprime);
-       }
 
-      if (dump_file && (dump_flags & TDF_DETAILS))
+      tree sprime = eliminate_avail (res);
+      if (sprime
+         && sprime != res)
        {
-         fprintf (dump_file, "Replaced redundant PHI node defining ");
-         print_generic_expr (dump_file, res, 0);
-         fprintf (dump_file, " with ");
-         print_generic_expr (dump_file, sprime, 0);
-         fprintf (dump_file, "\n");
-       }
-
-      remove_phi_node (&gsi, false);
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Replaced redundant PHI node defining ");
+             print_generic_expr (dump_file, res, 0);
+             fprintf (dump_file, " with ");
+             print_generic_expr (dump_file, sprime, 0);
+             fprintf (dump_file, "\n");
+           }
 
-      if (inserted_exprs
-         && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
-         && TREE_CODE (sprime) == SSA_NAME)
-       gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
-
-      if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
-       sprime = fold_convert (TREE_TYPE (res), sprime);
-      stmt = gimple_build_assign (res, sprime);
-      gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
-
-      gsi2 = gsi_after_labels (b);
-      gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
-      /* Queue the copy for eventual removal.  */
-      el_to_remove.safe_push (stmt);
-      /* If we inserted this PHI node ourself, it's not an elimination.  */
-      if (inserted_exprs
-         && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
-       pre_stats.phis--;
-      else
-       pre_stats.eliminations++;
-    }
+         /* If we inserted this PHI node ourself, it's not an elimination.  */
+         if (inserted_exprs
+             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
+           pre_stats.phis--;
+         else
+           pre_stats.eliminations++;
 
-  for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
-    {
-      tree lhs = NULL_TREE;
-      tree rhs = NULL_TREE;
+         /* If we will propagate into all uses don't bother to do
+            anything.  */
+         if (may_propagate_copy (res, sprime))
+           {
+             /* Mark the PHI for removal.  */
+             el_to_remove.safe_push (phi);
+             gsi_next (&gsi);
+             continue;
+           }
 
-      stmt = gsi_stmt (gsi);
+         remove_phi_node (&gsi, false);
 
-      if (gimple_has_lhs (stmt))
-       lhs = gimple_get_lhs (stmt);
+         if (inserted_exprs
+             && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
+             && TREE_CODE (sprime) == SSA_NAME)
+           gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
 
-      if (gimple_assign_single_p (stmt))
-       rhs = gimple_assign_rhs1 (stmt);
+         if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
+           sprime = fold_convert (TREE_TYPE (res), sprime);
+         gimple stmt = gimple_build_assign (res, sprime);
+         /* ???  It cannot yet be necessary (DOM walk).  */
+         gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
 
-      /* Lookup the RHS of the expression, see if we have an
-        available computation for it.  If so, replace the RHS with
-        the available computation.  */
-      if (gimple_has_lhs (stmt)
-         && TREE_CODE (lhs) == SSA_NAME
-         && !gimple_has_volatile_ops  (stmt))
-       {
-         tree sprime;
-         gimple orig_stmt = stmt;
+         gimple_stmt_iterator gsi2 = gsi_after_labels (b);
+         gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
+         continue;
+       }
 
-         sprime = eliminate_avail (lhs);
-         /* If there is no usable leader mark lhs as leader for its value.  */
-         if (!sprime)
-           eliminate_push_avail (lhs);
+      eliminate_push_avail (res);
+      gsi_next (&gsi);
+    }
 
+  for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
+    {
+      tree sprime = NULL_TREE;
+      stmt = gsi_stmt (gsi);
+      tree lhs = gimple_get_lhs (stmt);
+      if (lhs && TREE_CODE (lhs) == SSA_NAME
+         && !gimple_has_volatile_ops (stmt)
          /* See PR43491.  Do not replace a global register variable when
             it is a the RHS of an assignment.  Do replace local register
             variables since gcc does not guarantee a local variable will
             be allocated in register.
-            Do not perform copy propagation or undo constant propagation.  */
-         if (gimple_assign_single_p (stmt)
-             && (TREE_CODE (rhs) == SSA_NAME
-                 || is_gimple_min_invariant (rhs)
-                 || (TREE_CODE (rhs) == VAR_DECL
-                     && is_global_var (rhs)
-                     && DECL_HARD_REGISTER (rhs))))
-           continue;
-
+            ???  The fix isn't effective here.  This should instead
+            be ensured by not value-numbering them the same but treating
+            them like volatiles?  */
+         && !(gimple_assign_single_p (stmt)
+              && (TREE_CODE (gimple_assign_rhs1 (stmt)) == VAR_DECL
+                  && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))
+                  && is_global_var (gimple_assign_rhs1 (stmt)))))
+       {
+         sprime = eliminate_avail (lhs);
          if (!sprime)
            {
              /* If there is no existing usable leader but SCCVN thinks
@@ -4139,107 +4112,128 @@ eliminate_dom_walker::before_dom_children (basic_block b)
                  && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
                eliminate_push_avail (sprime);
            }
-         else if (is_gimple_min_invariant (sprime))
-           {
-             /* If there is no existing leader but SCCVN knows this
-                value is constant, use that constant.  */
-             if (!useless_type_conversion_p (TREE_TYPE (lhs),
-                                             TREE_TYPE (sprime)))
-               sprime = fold_convert (TREE_TYPE (lhs), sprime);
-
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               {
-                 fprintf (dump_file, "Replaced ");
-                 print_gimple_expr (dump_file, stmt, 0, 0);
-                 fprintf (dump_file, " with ");
-                 print_generic_expr (dump_file, sprime, 0);
-                 fprintf (dump_file, " in ");
-                 print_gimple_stmt (dump_file, stmt, 0, 0);
-               }
-             pre_stats.eliminations++;
-
-             tree vdef = gimple_vdef (stmt);
-             tree vuse = gimple_vuse (stmt);
-             propagate_tree_value_into_stmt (&gsi, sprime);
-             stmt = gsi_stmt (gsi);
-             update_stmt (stmt);
-             if (vdef != gimple_vdef (stmt))
-               VN_INFO (vdef)->valnum = vuse;
 
-             /* If we removed EH side-effects from the statement, clean
-                its EH information.  */
-             if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
+         /* If this now constitutes a copy duplicate points-to
+            and range info appropriately.  This is especially
+            important for inserted code.  See tree-ssa-copy.c
+            for similar code.  */
+         if (sprime
+             && TREE_CODE (sprime) == SSA_NAME)
+           {
+             basic_block sprime_b = gimple_bb (SSA_NAME_DEF_STMT (sprime));
+             if (POINTER_TYPE_P (TREE_TYPE (lhs))
+                 && SSA_NAME_PTR_INFO (lhs)
+                 && !SSA_NAME_PTR_INFO (sprime))
                {
-                 bitmap_set_bit (need_eh_cleanup,
-                                 gimple_bb (stmt)->index);
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   fprintf (dump_file, "  Removed EH side-effects.\n");
+                 duplicate_ssa_name_ptr_info (sprime,
+                                              SSA_NAME_PTR_INFO (lhs));
+                 if (b != sprime_b)
+                   mark_ptr_info_alignment_unknown
+                       (SSA_NAME_PTR_INFO (sprime));
                }
-             continue;
+             else if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+                      && SSA_NAME_RANGE_INFO (lhs)
+                      && !SSA_NAME_RANGE_INFO (sprime)
+                      && b == sprime_b)
+               duplicate_ssa_name_range_info (sprime,
+                                              SSA_NAME_RANGE_TYPE (lhs),
+                                              SSA_NAME_RANGE_INFO (lhs));
            }
 
+         /* Inhibit the use of an inserted PHI on a loop header when
+            the address of the memory reference is a simple induction
+            variable.  In other cases the vectorizer won't do anything
+            anyway (either it's loop invariant or a complicated
+            expression).  */
          if (sprime
-             && sprime != lhs
-             && (rhs == NULL_TREE
-                 || TREE_CODE (rhs) != SSA_NAME
-                 || may_propagate_copy (rhs, sprime)))
+             && TREE_CODE (sprime) == SSA_NAME
+             && do_pre
+             && flag_tree_loop_vectorize
+             && loop_outer (b->loop_father)
+             && has_zero_uses (sprime)
+             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))
+             && gimple_assign_load_p (stmt))
            {
-             bool can_make_abnormal_goto
-                 = is_gimple_call (stmt)
-                 && stmt_can_make_abnormal_goto (stmt);
-
-             gcc_assert (sprime != rhs);
-
-             /* Inhibit the use of an inserted PHI on a loop header when
-                the address of the memory reference is a simple induction
-                variable.  In other cases the vectorizer won't do anything
-                anyway (either it's loop invariant or a complicated
-                expression).  */
-             if (do_pre
-                 && flag_tree_loop_vectorize
-                 && gimple_assign_single_p (stmt)
-                 && TREE_CODE (sprime) == SSA_NAME
-                 && loop_outer (b->loop_father))
+             gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
+             basic_block def_bb = gimple_bb (def_stmt);
+             if (gimple_code (def_stmt) == GIMPLE_PHI
+                 && b->loop_father->header == def_bb)
                {
-                 gimple def_stmt = SSA_NAME_DEF_STMT (sprime);
-                 basic_block def_bb = gimple_bb (def_stmt);
-                 if (gimple_code (def_stmt) == GIMPLE_PHI
-                     && b->loop_father->header == def_bb
-                     && has_zero_uses (sprime))
+                 ssa_op_iter iter;
+                 tree op;
+                 bool found = false;
+                 FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
                    {
-                     ssa_op_iter iter;
-                     tree op;
-                     bool found = false;
-                     FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+                     affine_iv iv;
+                     def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
+                     if (def_bb
+                         && flow_bb_inside_loop_p (b->loop_father, def_bb)
+                         && simple_iv (b->loop_father,
+                                       b->loop_father, op, &iv, true))
                        {
-                         affine_iv iv;
-                         def_bb = gimple_bb (SSA_NAME_DEF_STMT (op));
-                         if (def_bb
-                             && flow_bb_inside_loop_p (b->loop_father,
-                                                       def_bb)
-                             && simple_iv (b->loop_father,
-                                           b->loop_father, op, &iv, true))
-                           {
-                             found = true;
-                             break;
-                           }
+                         found = true;
+                         break;
                        }
-                     if (found)
+                   }
+                 if (found)
+                   {
+                     if (dump_file && (dump_flags & TDF_DETAILS))
                        {
-                         if (dump_file && (dump_flags & TDF_DETAILS))
-                           {
-                             fprintf (dump_file, "Not replacing ");
-                             print_gimple_expr (dump_file, stmt, 0, 0);
-                             fprintf (dump_file, " with ");
-                             print_generic_expr (dump_file, sprime, 0);
-                             fprintf (dump_file, " which would add a loop"
-                                      " carried dependence to loop %d\n",
-                                      b->loop_father->num);
-                           }
-                         continue;
+                         fprintf (dump_file, "Not replacing ");
+                         print_gimple_expr (dump_file, stmt, 0, 0);
+                         fprintf (dump_file, " with ");
+                         print_generic_expr (dump_file, sprime, 0);
+                         fprintf (dump_file, " which would add a loop"
+                                  " carried dependence to loop %d\n",
+                                  b->loop_father->num);
                        }
+                     /* Don't keep sprime available.  */
+                     eliminate_push_avail (lhs);
+                     sprime = NULL_TREE;
                    }
                }
+           }
+
+         if (sprime)
+           {
+             /* If we can propagate the value computed for LHS into
+                all uses don't bother doing anything with this stmt.  */
+             if (may_propagate_copy (lhs, sprime))
+               {
+                 /* Mark it for removal.  */
+                 el_to_remove.safe_push (stmt);
+
+                 /* ???  Don't count copy/constant propagations.  */
+                 if (gimple_assign_single_p (stmt)
+                     && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+                         || gimple_assign_rhs1 (stmt) == sprime))
+                   continue;
+
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "Replaced ");
+                     print_gimple_expr (dump_file, stmt, 0, 0);
+                     fprintf (dump_file, " with ");
+                     print_generic_expr (dump_file, sprime, 0);
+                     fprintf (dump_file, " in all uses of ");
+                     print_gimple_stmt (dump_file, stmt, 0, 0);
+                   }
+
+                 pre_stats.eliminations++;
+                 continue;
+               }
+
+             /* If this is an assignment from our leader (which
+                happens in the case the value-number is a constant)
+                then there is nothing to do.  */
+             if (gimple_assign_single_p (stmt)
+                 && sprime == gimple_assign_rhs1 (stmt))
+               continue;
+
+             /* Else replace its RHS.  */
+             bool can_make_abnormal_goto
+                 = is_gimple_call (stmt)
+                 && stmt_can_make_abnormal_goto (stmt);
 
              if (dump_file && (dump_flags & TDF_DETAILS))
                {
@@ -4254,16 +4248,12 @@ eliminate_dom_walker::before_dom_children (basic_block b)
              if (TREE_CODE (sprime) == SSA_NAME)
                gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
                                NECESSARY, true);
-             /* We need to make sure the new and old types actually match,
-                which may require adding a simple cast, which fold_convert
-                will do for us.  */
-             if ((!rhs || TREE_CODE (rhs) != SSA_NAME)
-                 && !useless_type_conversion_p (gimple_expr_type (stmt),
-                                                TREE_TYPE (sprime)))
-               sprime = fold_convert (gimple_expr_type (stmt), sprime);
 
              pre_stats.eliminations++;
-
+             gimple orig_stmt = stmt;
+             if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                             TREE_TYPE (sprime)))
+               sprime = fold_convert (TREE_TYPE (lhs), sprime);
              tree vdef = gimple_vdef (stmt);
              tree vuse = gimple_vuse (stmt);
              propagate_tree_value_into_stmt (&gsi, sprime);
@@ -4291,135 +4281,183 @@ eliminate_dom_walker::before_dom_children (basic_block b)
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "  Removed AB side-effects.\n");
                }
+
+             continue;
            }
        }
+
       /* If the statement is a scalar store, see if the expression
-        has the same value number as its rhs.  If so, the store is
-        dead.  */
-      else if (gimple_assign_single_p (stmt)
-              && !gimple_has_volatile_ops (stmt)
-              && !is_gimple_reg (gimple_assign_lhs (stmt))
-              && (TREE_CODE (rhs) == SSA_NAME
-                  || is_gimple_min_invariant (rhs)))
-       {
-         tree val;
-         val = vn_reference_lookup (gimple_assign_lhs (stmt),
-                                    gimple_vuse (stmt), VN_WALK, NULL);
-         if (TREE_CODE (rhs) == SSA_NAME)
-           rhs = VN_INFO (rhs)->valnum;
-         if (val
-             && operand_equal_p (val, rhs, 0))
-           {
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               {
-                 fprintf (dump_file, "Deleted redundant store ");
-                 print_gimple_stmt (dump_file, stmt, 0, 0);
-               }
+         has the same value number as its rhs.  If so, the store is
+         dead.  */
+      if (gimple_assign_single_p (stmt)
+         && !gimple_has_volatile_ops (stmt)
+         && !is_gimple_reg (gimple_assign_lhs (stmt))
+         && (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+             || is_gimple_min_invariant (gimple_assign_rhs1 (stmt))))
+        {
+          tree val;
+         tree rhs = gimple_assign_rhs1 (stmt);
+          val = vn_reference_lookup (gimple_assign_lhs (stmt),
+                                     gimple_vuse (stmt), VN_WALK, NULL);
+          if (TREE_CODE (rhs) == SSA_NAME)
+            rhs = VN_INFO (rhs)->valnum;
+          if (val
+              && operand_equal_p (val, rhs, 0))
+            {
+              if (dump_file && (dump_flags & TDF_DETAILS))
+                {
+                  fprintf (dump_file, "Deleted redundant store ");
+                  print_gimple_stmt (dump_file, stmt, 0, 0);
+                }
+
+              /* Queue stmt for removal.  */
+              el_to_remove.safe_push (stmt);
+             continue;
+            }
+        }
 
-             /* Queue stmt for removal.  */
-             el_to_remove.safe_push (stmt);
-           }
-       }
-      /* Visit COND_EXPRs and fold the comparison with the
-        available value-numbers.  */
-      else if (gimple_code (stmt) == GIMPLE_COND)
+      bool can_make_abnormal_goto = stmt_can_make_abnormal_goto (stmt);
+      bool was_noreturn = (is_gimple_call (stmt)
+                          && gimple_call_noreturn_p (stmt));
+      tree vdef = gimple_vdef (stmt);
+      tree vuse = gimple_vuse (stmt);
+
+      /* If we didn't replace the whole stmt (or propagate the result
+         into all uses), replace all uses on this stmt with their
+        leaders.  */
+      use_operand_p use_p;
+      ssa_op_iter iter;
+      FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
        {
-         tree op0 = gimple_cond_lhs (stmt);
-         tree op1 = gimple_cond_rhs (stmt);
-         tree result;
-
-         if (TREE_CODE (op0) == SSA_NAME)
-           op0 = VN_INFO (op0)->valnum;
-         if (TREE_CODE (op1) == SSA_NAME)
-           op1 = VN_INFO (op1)->valnum;
-         result = fold_binary (gimple_cond_code (stmt), boolean_type_node,
-                               op0, op1);
-         if (result && TREE_CODE (result) == INTEGER_CST)
+         tree use = USE_FROM_PTR (use_p);
+         /* ???  The call code above leaves stmt operands un-updated.  */
+         if (TREE_CODE (use) != SSA_NAME)
+           continue;
+         tree sprime = eliminate_avail (use);
+         if (sprime && sprime != use
+             && may_propagate_copy (use, sprime)
+             /* We substitute into debug stmts to avoid excessive
+                debug temporaries created by removed stmts, but we need
+                to avoid doing so for inserted sprimes as we never want
+                to create debug temporaries for them.  */
+             && (!inserted_exprs
+                 || TREE_CODE (sprime) != SSA_NAME
+                 || !is_gimple_debug (stmt)
+                 || !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (sprime))))
            {
-             if (integer_zerop (result))
-               gimple_cond_make_false (stmt);
-             else
-               gimple_cond_make_true (stmt);
-             update_stmt (stmt);
-             el_todo = TODO_cleanup_cfg;
+             propagate_value (use_p, sprime);
+             gimple_set_modified (stmt, true);
+             if (TREE_CODE (sprime) == SSA_NAME
+                 && !is_gimple_debug (stmt))
+               gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
+                               NECESSARY, true);
            }
        }
+
       /* Visit indirect calls and turn them into direct calls if
-        possible.  */
+        possible using the devirtualization machinery.  */
       if (is_gimple_call (stmt))
        {
-         tree orig_fn = gimple_call_fn (stmt);
-         tree fn;
-         if (!orig_fn)
-           continue;
-         if (TREE_CODE (orig_fn) == SSA_NAME)
-           fn = VN_INFO (orig_fn)->valnum;
-         else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
-                  && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
+         tree fn = gimple_call_fn (stmt);
+         if (fn
+             && TREE_CODE (fn) == OBJ_TYPE_REF
+             && TREE_CODE (OBJ_TYPE_REF_EXPR (fn)) == SSA_NAME)
            {
-             fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
-             if (!gimple_call_addr_fndecl (fn))
+             fn = ipa_intraprocedural_devirtualization (stmt);
+             if (fn && dbg_cnt (devirt))
                {
-                 fn = ipa_intraprocedural_devirtualization (stmt);
-                 if (fn)
-                   fn = build_fold_addr_expr (fn);
+                 if (dump_enabled_p ())
+                   {
+                     location_t loc = gimple_location (stmt);
+                     dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+                                      "converting indirect call to "
+                                      "function %s\n",
+                                      cgraph_get_node (fn)->name ());
+                   }
+                 gimple_call_set_fndecl (stmt, fn);
+                 gimple_set_modified (stmt, true);
                }
            }
-         else
-           continue;
-         if (gimple_call_addr_fndecl (fn) != NULL_TREE
-             && useless_type_conversion_p (TREE_TYPE (orig_fn),
-                                           TREE_TYPE (fn))
-              && dbg_cnt (devirt))
-           {
-             bool can_make_abnormal_goto
-                 = stmt_can_make_abnormal_goto (stmt);
-             bool was_noreturn = gimple_call_noreturn_p (stmt);
-
-             if (dump_enabled_p ())
-               {
-                  location_t loc = gimple_location (stmt);
-                  dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
-                                   "converting indirect call to function %s\n",
-                                   cgraph_get_node (gimple_call_addr_fndecl (fn))->name ());
-               }
-
-             gimple_call_set_fn (stmt, fn);
-             tree vdef = gimple_vdef (stmt);
-             tree vuse = gimple_vuse (stmt);
-             update_stmt (stmt);
-             if (vdef != gimple_vdef (stmt))
-               VN_INFO (vdef)->valnum = vuse;
+       }
 
+      if (gimple_modified_p (stmt))
+       {
+         /* If a formerly non-invariant ADDR_EXPR is turned into an
+            invariant one it was on a separate stmt.  */
+         if (gimple_assign_single_p (stmt)
+             && TREE_CODE (gimple_assign_rhs1 (stmt)) == ADDR_EXPR)
+           recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
+         gimple old_stmt = stmt;
+         if (is_gimple_call (stmt))
+           {
+             /* ???  Only fold calls inplace for now, this may create new
+                SSA names which in turn will confuse free_scc_vn SSA name
+                release code.  */
+             fold_stmt_inplace (&gsi);
              /* When changing a call into a noreturn call, cfg cleanup
                 is needed to fix up the noreturn call.  */
              if (!was_noreturn && gimple_call_noreturn_p (stmt))
                el_todo |= TODO_cleanup_cfg;
+           }
+         else
+           {
+             fold_stmt (&gsi);
+             stmt = gsi_stmt (gsi);
+             if ((gimple_code (stmt) == GIMPLE_COND
+                  && (gimple_cond_true_p (stmt)
+                      || gimple_cond_false_p (stmt)))
+                 || (gimple_code (stmt) == GIMPLE_SWITCH
+                     && TREE_CODE (gimple_switch_index (stmt)) == INTEGER_CST))
+               el_todo |= TODO_cleanup_cfg;
+           }
+         /* If we removed EH side-effects from the statement, clean
+            its EH information.  */
+         if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
+           {
+             bitmap_set_bit (need_eh_cleanup,
+                             gimple_bb (stmt)->index);
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               fprintf (dump_file, "  Removed EH side-effects.\n");
+           }
+         /* Likewise for AB side-effects.  */
+         if (can_make_abnormal_goto
+             && !stmt_can_make_abnormal_goto (stmt))
+           {
+             bitmap_set_bit (need_ab_cleanup,
+                             gimple_bb (stmt)->index);
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               fprintf (dump_file, "  Removed AB side-effects.\n");
+           }
+         update_stmt (stmt);
+         if (vdef != gimple_vdef (stmt))
+           VN_INFO (vdef)->valnum = vuse;
+       }
 
-             /* If we removed EH side-effects from the statement, clean
-                its EH information.  */
-             if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
-               {
-                 bitmap_set_bit (need_eh_cleanup,
-                                 gimple_bb (stmt)->index);
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   fprintf (dump_file, "  Removed EH side-effects.\n");
-               }
-
-             /* Likewise for AB side-effects.  */
-             if (can_make_abnormal_goto
-                 && !stmt_can_make_abnormal_goto (stmt))
-               {
-                 bitmap_set_bit (need_ab_cleanup,
-                                 gimple_bb (stmt)->index);
-                 if (dump_file && (dump_flags & TDF_DETAILS))
-                   fprintf (dump_file, "  Removed AB side-effects.\n");
-               }
+      /* Make the new value available - for fully redundant LHS we
+         continue with the next stmt above.  */
+      if (lhs && TREE_CODE (lhs) == SSA_NAME)
+       eliminate_push_avail (lhs);
+    }
 
-             /* Changing an indirect call to a direct call may
-                have exposed different semantics.  This may
-                require an SSA update.  */
-             el_todo |= TODO_update_ssa_only_virtuals;
+  /* Replace destination PHI arguments.  */
+  edge_iterator ei;
+  edge e;
+  FOR_EACH_EDGE (e, ei, b->succs)
+    {
+      for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple phi = gsi_stmt (gsi);
+         use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
+         tree arg = USE_FROM_PTR (use_p);
+         if (TREE_CODE (arg) != SSA_NAME
+             || virtual_operand_p (arg))
+           continue;
+         tree sprime = eliminate_avail (arg);
+         if (sprime && may_propagate_copy (arg, sprime))
+           {
+             propagate_value (use_p, sprime);
+             if (TREE_CODE (sprime) == SSA_NAME)
+               gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
            }
        }
     }
@@ -4442,7 +4480,6 @@ eliminate (bool do_pre)
 {
   gimple_stmt_iterator gsi;
   gimple stmt;
-  unsigned i;
 
   need_eh_cleanup = BITMAP_ALLOC (NULL);
   need_ab_cleanup = BITMAP_ALLOC (NULL);
@@ -4460,41 +4497,37 @@ eliminate (bool do_pre)
 
   /* We cannot remove stmts during BB walk, especially not release SSA
      names there as this confuses the VN machinery.  The stmts ending
-     up in el_to_remove are either stores or simple copies.  */
-  FOR_EACH_VEC_ELT (el_to_remove, i, stmt)
+     up in el_to_remove are either stores or simple copies.
+     Remove stmts in reverse order to make debug stmt creation possible.  */
+  while (!el_to_remove.is_empty ())
     {
-      tree lhs = gimple_assign_lhs (stmt);
-      tree rhs = gimple_assign_rhs1 (stmt);
-      use_operand_p use_p;
-      gimple use_stmt;
-
-      /* If there is a single use only, propagate the equivalency
-        instead of keeping the copy.  */
-      if (TREE_CODE (lhs) == SSA_NAME
-         && TREE_CODE (rhs) == SSA_NAME
-         && single_imm_use (lhs, &use_p, &use_stmt)
-         && may_propagate_copy (USE_FROM_PTR (use_p), rhs))
+      stmt = el_to_remove.pop ();
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
        {
-         SET_USE (use_p, rhs);
-         update_stmt (use_stmt);
-         if (inserted_exprs
-             && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
-             && TREE_CODE (rhs) == SSA_NAME)
-           gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
+         fprintf (dump_file, "Removing dead stmt ");
+         print_gimple_stmt (dump_file, stmt, 0, 0);
        }
 
-      /* If this is a store or a now unused copy, remove it.  */
-      if (TREE_CODE (lhs) != SSA_NAME
-         || has_zero_uses (lhs))
+      tree lhs;
+      if (gimple_code (stmt) == GIMPLE_PHI)
+       lhs = gimple_phi_result (stmt);
+      else
+       lhs = gimple_get_lhs (stmt);
+
+      if (inserted_exprs
+         && TREE_CODE (lhs) == SSA_NAME)
+       bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
+
+      gsi = gsi_for_stmt (stmt);
+      if (gimple_code (stmt) == GIMPLE_PHI)
+       remove_phi_node (&gsi, true);
+      else
        {
          basic_block bb = gimple_bb (stmt);
-         gsi = gsi_for_stmt (stmt);
          unlink_stmt_vdef (stmt);
          if (gsi_remove (&gsi, true))
            bitmap_set_bit (need_eh_cleanup, bb->index);
-         if (inserted_exprs
-             && TREE_CODE (lhs) == SSA_NAME)
-           bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
          release_defs (stmt);
        }
     }
index 1988835..255bff9 100644 (file)
@@ -1410,11 +1410,6 @@ replace_exp (use_operand_p op_p, tree val)
 void
 propagate_tree_value (tree *op_p, tree val)
 {
-  gcc_checking_assert (!(TREE_CODE (val) == SSA_NAME
-                        && *op_p
-                        && TREE_CODE (*op_p) == SSA_NAME
-                        && !may_propagate_copy (*op_p, val)));
-
   if (TREE_CODE (val) == SSA_NAME)
     *op_p = val;
   else