On Wed, 14 May 2014, Richard Biener wrote:

> 
> This makes FRE/PRE substitute values into all uses instead of leaving
> copies and initializations from constants in the IL which requires
> a copyprop pass to clean up things (which we usually place directly
> after FRE/PRE).
> 
> This should open the possibility to remove some of the passes,
> respectively the two copy-prop passes right after the two FREs
> and the copyprop pass we do early in loop opts.
> 
> The patch exposes a weakness in invariant motion cost computation
> and thus gfortran.dg/vect/fast-math-vect-8.f90 fails for me
> on i?86 (but not on x86_64).
> 
> I want to revisit some of the ???s and uglinesses in the patch,
> but this is a state that passes bootstrap and regtest otherwise
> and thus ready.
> 
> Any comments?

Ok, so here goes the final variant I am about to commit.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Richard.

2014-06-13  Richard Biener  <rguent...@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.


Index: trunk/gcc/tree-ssa-pre.c
===================================================================
*** trunk.orig/gcc/tree-ssa-pre.c       2014-06-12 13:05:07.459653680 +0200
--- trunk/gcc/tree-ssa-pre.c    2014-06-13 09:48:28.646517479 +0200
*************** eliminate_dom_walker::before_dom_childre
*** 4012,4131 ****
    /* 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;
  
    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;
!       }
  
!       sprime = eliminate_avail (res);
!       if (!sprime
!         || sprime == 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))
        {
!         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 (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++;
!     }
  
!   for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
!     {
!       tree lhs = NULL_TREE;
!       tree rhs = NULL_TREE;
  
!       stmt = gsi_stmt (gsi);
! 
!       if (gimple_has_lhs (stmt))
!       lhs = gimple_get_lhs (stmt);
  
!       if (gimple_assign_single_p (stmt))
!       rhs = gimple_assign_rhs1 (stmt);
  
!       /* 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;
  
!         sprime = eliminate_avail (lhs);
!         /* If there is no usable leader mark lhs as leader for its value.  */
!         if (!sprime)
!           eliminate_push_avail (lhs);
  
          /* 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;
! 
          if (!sprime)
            {
              /* If there is no existing usable leader but SCCVN thinks
--- 4012,4104 ----
    /* Mark new bb.  */
    el_avail_stack.safe_push (NULL_TREE);
  
!   /* ???  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 phi = gsi_stmt (gsi);
!       tree res = PHI_RESULT (phi);
  
!       if (virtual_operand_p (res))
        {
          gsi_next (&gsi);
          continue;
        }
  
!       tree sprime = eliminate_avail (res);
!       if (sprime
!         && sprime != res)
        {
!         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 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 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;
!           }
  
!         remove_phi_node (&gsi, false);
  
!         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);
!         gimple stmt = gimple_build_assign (res, sprime);
!         /* ???  It cannot yet be necessary (DOM walk).  */
!         gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
  
!         gimple_stmt_iterator gsi2 = gsi_after_labels (b);
!         gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
!         continue;
!       }
  
!       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.
!            ???  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
*************** eliminate_dom_walker::before_dom_childre
*** 4139,4246 ****
                  && (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))
!               {
!                 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");
!               }
!             continue;
            }
  
          if (sprime
!             && sprime != lhs
!             && (rhs == NULL_TREE
!                 || TREE_CODE (rhs) != SSA_NAME
!                 || may_propagate_copy (rhs, sprime)))
            {
!             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
!                     && has_zero_uses (sprime))
                    {
!                     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))
!                           {
!                             found = true;
!                             break;
!                           }
                        }
!                     if (found)
                        {
!                         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;
                        }
                    }
                }
  
              if (dump_file && (dump_flags & TDF_DETAILS))
                {
                  fprintf (dump_file, "Replaced ");
--- 4112,4240 ----
                  && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
                eliminate_push_avail (sprime);
            }
  
!         /* 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))
!               {
!                 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));
!               }
!             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
!             && 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))
            {
!             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)
!               {
!                 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))
                        {
!                         found = true;
!                         break;
                        }
!                   }
!                 if (found)
!                   {
!                     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);
                        }
+                     /* 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))
                {
                  fprintf (dump_file, "Replaced ");
*************** eliminate_dom_walker::before_dom_childre
*** 4254,4269 ****
              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++;
! 
              tree vdef = gimple_vdef (stmt);
              tree vuse = gimple_vuse (stmt);
              propagate_tree_value_into_stmt (&gsi, sprime);
--- 4248,4259 ----
              if (TREE_CODE (sprime) == SSA_NAME)
                gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
                                NECESSARY, true);
  
              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);
*************** eliminate_dom_walker::before_dom_childre
*** 4291,4425 ****
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    fprintf (dump_file, "  Removed AB side-effects.\n");
                }
            }
        }
        /* 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);
!               }
  
!             /* 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)
        {
!         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)
!           {
!             if (integer_zerop (result))
!               gimple_cond_make_false (stmt);
!             else
!               gimple_cond_make_true (stmt);
!             update_stmt (stmt);
!             el_todo = TODO_cleanup_cfg;
            }
        }
        /* Visit indirect calls and turn them into direct calls if
!        possible.  */
        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)
            {
!             fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
!             if (!gimple_call_addr_fndecl (fn))
                {
!                 fn = ipa_intraprocedural_devirtualization (stmt);
!                 if (fn)
!                   fn = build_fold_addr_expr (fn);
                }
            }
!         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;
  
              /* 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;
  
!             /* 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");
!               }
  
!             /* 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;
            }
        }
      }
--- 4281,4463 ----
                  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.  */
!       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;
!             }
!         }
! 
!       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 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))))
!           {
!             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 using the devirtualization machinery.  */
        if (is_gimple_call (stmt))
        {
!         tree fn = gimple_call_fn (stmt);
!         if (fn
!             && TREE_CODE (fn) == OBJ_TYPE_REF
!             && TREE_CODE (OBJ_TYPE_REF_EXPR (fn)) == SSA_NAME)
            {
!             fn = ipa_intraprocedural_devirtualization (stmt);
!             if (fn && dbg_cnt (devirt))
                {
!                 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);
                }
            }
!       }
  
+       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;
+       }
  
!       /* 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);
!     }
  
!   /* 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);
            }
        }
      }
*************** eliminate (bool do_pre)
*** 4442,4448 ****
  {
    gimple_stmt_iterator gsi;
    gimple stmt;
-   unsigned i;
  
    need_eh_cleanup = BITMAP_ALLOC (NULL);
    need_ab_cleanup = BITMAP_ALLOC (NULL);
--- 4480,4485 ----
*************** eliminate (bool do_pre)
*** 4460,4500 ****
  
    /* 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)
      {
!       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))
        {
!         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);
        }
  
!       /* If this is a store or a now unused copy, remove it.  */
!       if (TREE_CODE (lhs) != SSA_NAME
!         || has_zero_uses (lhs))
        {
          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);
        }
      }
--- 4497,4533 ----
  
    /* 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.
!      Remove stmts in reverse order to make debug stmt creation possible.  */
!   while (!el_to_remove.is_empty ())
      {
!       stmt = el_to_remove.pop ();
  
!       if (dump_file && (dump_flags & TDF_DETAILS))
        {
!         fprintf (dump_file, "Removing dead stmt ");
!         print_gimple_stmt (dump_file, stmt, 0, 0);
        }
  
!       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);
          unlink_stmt_vdef (stmt);
          if (gsi_remove (&gsi, true))
            bitmap_set_bit (need_eh_cleanup, bb->index);
          release_defs (stmt);
        }
      }
Index: trunk/gcc/testsuite/c-c++-common/pr46562-2.c
===================================================================
*** trunk.orig/gcc/testsuite/c-c++-common/pr46562-2.c   2014-06-12 
13:05:44.962651098 +0200
--- trunk/gcc/testsuite/c-c++-common/pr46562-2.c        2014-06-12 
13:05:49.149650810 +0200
*************** int foo(void)
*** 9,13 ****
    return *p;
  }
  
! /* { dg-final { scan-tree-dump "= 0;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 9,13 ----
    return *p;
  }
  
! /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
Index: trunk/gcc/tree-ssa-propagate.c
===================================================================
*** trunk.orig/gcc/tree-ssa-propagate.c 2014-06-12 13:05:44.962651098 +0200
--- trunk/gcc/tree-ssa-propagate.c      2014-06-12 13:05:49.149650810 +0200
*************** replace_exp (use_operand_p op_p, tree va
*** 1410,1420 ****
  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
--- 1410,1415 ----
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c       2014-06-12 
13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c    2014-06-12 
13:05:49.150650810 +0200
*************** int bazzoo (void)
*** 30,34 ****
    return b.i;
  }
  
! /* { dg-final { scan-tree-dump-times "= 0;" 5 "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 30,34 ----
    return b.i;
  }
  
! /* { dg-final { scan-tree-dump-times "return 0;" 4 "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c       2014-06-12 
13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c    2014-06-12 
13:05:49.150650810 +0200
*************** int foo (struct X *p)
*** 14,18 ****
  
  /* We should optimize this to return 0.  */
  
! /* { dg-final { scan-tree-dump "= 0;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 14,18 ----
  
  /* We should optimize this to return 0.  */
  
! /* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c       2014-06-12 
13:05:44.963651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c    2014-06-12 
13:05:49.150650810 +0200
*************** bar (_Complex float x)
*** 23,28 ****
    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" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 23,28 ----
    return z;
  } 
  
! /* 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: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c       2014-06-12 
13:05:44.964651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c    2014-06-12 
13:05:49.150650810 +0200
*************** int foo(int k, int *x)
*** 11,15 ****
    }  while (++j<k);
    return res;
  }
! /* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre"} } */
  /* { dg-final { cleanup-tree-dump "pre" } } */
--- 11,15 ----
    }  while (++j<k);
    return res;
  }
! /* { dg-final { scan-tree-dump-times "Eliminated: 2" 1 "pre"} } */
  /* { dg-final { cleanup-tree-dump "pre" } } */
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
===================================================================
*** trunk.orig/gcc/testsuite/g++.dg/tree-ssa/pr8781.C   2014-06-12 
13:05:44.964651098 +0200
--- trunk/gcc/testsuite/g++.dg/tree-ssa/pr8781.C        2014-06-12 
13:06:08.487649479 +0200
***************
*** 1,5 ****
  /* { dg-do compile } */
! /* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */
  
  int f();
  
--- 1,5 ----
  /* { dg-do compile } */
! /* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */
  
  int f();
  
*************** int x()
*** 24,28 ****
  
  /* We should optimize this to a direct call.  */
  
! /* { dg-final { scan-tree-dump "converting indirect call to function int f()" 
"fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 24,28 ----
  
  /* We should optimize this to a direct call.  */
  
! /* { dg-final { scan-tree-dump-times "= f \\(\\);" 1 "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c
===================================================================
*** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c       2014-06-12 
13:05:44.964651098 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-39.c    2014-06-12 
13:05:49.151650810 +0200
*************** int foo (int i)
*** 15,19 ****
  
  /* We should be able to value-number the final assignment to k to 1.  */
  
! /* { dg-final { scan-tree-dump "k_. = 1;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */
--- 15,19 ----
  
  /* We should be able to value-number the final assignment to k to 1.  */
  
! /* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
  /* { dg-final { cleanup-tree-dump "fre1" } } */

Reply via email to