public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
@ 2014-05-14 14:04 Richard Biener
  2014-06-13 10:01 ` Richard Biener
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Biener @ 2014-05-14 14:04 UTC (permalink / raw)
  To: gcc-patches


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?

Thanks,
Richard.

2014-05-14  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.
	* 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-pre-16.c: Likewise.

Index: trunk/gcc/tree-ssa-pre.c
===================================================================
*** trunk.orig/gcc/tree-ssa-pre.c	2014-05-14 14:06:26.860907895 +0200
--- trunk/gcc/tree-ssa-pre.c	2014-05-14 14:20:29.068849910 +0200
*************** eliminate_dom_walker::before_dom_childre
*** 4012,4120 ****
  
    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,4163 ----
  
    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;
  	}
! 
!       /* Inhibit the use of an inserted PHI on a loop header when
! 	 there is a load with that value whose address is a simple induction
! 	 variable.  In other cases the vectorizer won't do anything
! 	 anyway (either it's loop invariant or a complicated
! 	 expression).
! 	 ???  This is a somewhat awkward implementation give we don't
! 	 have a mapping back from load VNs to loads.   */
!       bool found = false;
!       if (flag_tree_loop_vectorize
! 	  && b->loop_father->header == b
! 	  && loop_outer (b->loop_father)
! 	  && inserted_exprs
! 	  && bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
  	{
! 	  basic_block *bbs = get_loop_body (b->loop_father);
! 	  for (unsigned i = 0; i < b->loop_father->num_nodes; ++i)
! 	    {
! 	      basic_block bb = bbs[i];
! 	      for (gimple_stmt_iterator gsi2 = gsi_start_bb (bb);
! 		   !gsi_end_p (gsi2); gsi_next (&gsi2))
! 		{
! 		  gimple stmt = gsi_stmt (gsi2);
! 		  if (!gimple_assign_load_p (stmt)
! 		      || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
! 		    continue;
! 		  if (VN_INFO (gimple_assign_lhs (stmt))->valnum
! 		      != VN_INFO (res)->valnum)
! 		    continue;
! 		  ssa_op_iter iter;
! 		  tree op;
! 		  FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
! 		    {
! 		      affine_iv iv;
! 		      basic_block 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)
! 		    break;
! 		}
! 	      if (found)
! 		break;
! 	    }
! 	  free (bbs);
  	}
  
!       if (found)
  	{
! 	  if (dump_file && (dump_flags & TDF_DETAILS))
! 	    {
! 	      fprintf (dump_file, "Not replacing 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);
! 	    }
  	}
        else
! 	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
*** 4128,4229 ****
  		  && (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++;
! 	      propagate_tree_value_into_stmt (&gsi, sprime);
! 	      stmt = gsi_stmt (gsi);
! 	      update_stmt (stmt);
  
- 	      /* 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 (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 ");
--- 4171,4243 ----
  		  && (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
  		eliminate_push_avail (sprime);
  	    }
! 	  if (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 (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));
! 		}
! 
! 	      /* 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
*** 4237,4251 ****
  	      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++;
  	      propagate_tree_value_into_stmt (&gsi, sprime);
  	      stmt = gsi_stmt (gsi);
  	      update_stmt (stmt);
--- 4251,4262 ----
  	      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);
  	      propagate_tree_value_into_stmt (&gsi, sprime);
  	      stmt = gsi_stmt (gsi);
  	      update_stmt (stmt);
*************** eliminate_dom_walker::before_dom_childre
*** 4269,4336 ****
  		  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)
--- 4280,4333 ----
  		  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));
  
        /* 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 = NULL_TREE;
  	  if (!orig_fn)
! 	    ;
! 	  else 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)
*************** eliminate_dom_walker::before_dom_childre
*** 4343,4358 ****
  		    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)))
  	    {
- 	      bool can_make_abnormal_goto
- 		  = stmt_can_make_abnormal_goto (stmt);
- 	      bool was_noreturn = gimple_call_noreturn_p (stmt);
- 
  	      if (dump_file && (dump_flags & TDF_DETAILS))
  		{
  		  fprintf (dump_file, "Replacing call target with ");
--- 4340,4347 ----
  		    fn = build_fold_addr_expr (fn);
  		}
  	    }
! 	  if (fn && gimple_call_addr_fndecl (fn) != NULL_TREE)
  	    {
  	      if (dump_file && (dump_flags & TDF_DETAILS))
  		{
  		  fprintf (dump_file, "Replacing call target with ");
*************** eliminate_dom_walker::before_dom_childre
*** 4363,4398 ****
  
  	      gimple_call_set_fn (stmt, fn);
  	      el_to_update.safe_push (stmt);
  
  	      /* 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;
  	    }
  	}
      }
--- 4352,4477 ----
  
  	      gimple_call_set_fn (stmt, fn);
  	      el_to_update.safe_push (stmt);
+ 	      gimple_set_modified (stmt, true);
+ 
+ 	      /* 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;
+ 	    }
+ 	}
+ 
+       /* 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);
+ 	    }
+ 	}
  
+       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 the stmt if that was not defered.  */
+ 	  if (el_to_update.is_empty ()
+ 	      || el_to_update.last () != stmt)
+ 	    update_stmt (stmt);
+ 	}
  
!       /* 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 (void)
*** 4431,4485 ****
    el_avail.release ();
    el_avail_stack.release ();
  
    /* 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);
  	}
      }
    el_to_remove.release ();
  
-   /* We cannot update call statements with virtual operands during
-      SSA walk.  This might remove them which in turn makes our
-      VN lattice invalid.  */
-   FOR_EACH_VEC_ELT (el_to_update, i, stmt)
-     update_stmt (stmt);
-   el_to_update.release ();
- 
    return el_todo;
  }
  
--- 4510,4560 ----
    el_avail.release ();
    el_avail_stack.release ();
  
+   /* We cannot update call statements with virtual operands during
+      SSA walk.  This might remove them which in turn makes our
+      VN lattice invalid.  */
+   FOR_EACH_VEC_ELT (el_to_update, i, stmt)
+     update_stmt (stmt);
+   el_to_update.release ();
+ 
    /* 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);
  	}
      }
    el_to_remove.release ();
  
    return el_todo;
  }
  
Index: trunk/gcc/testsuite/c-c++-common/pr46562-2.c
===================================================================
*** trunk.orig/gcc/testsuite/c-c++-common/pr46562-2.c	2014-05-14 14:06:26.860907895 +0200
--- trunk/gcc/testsuite/c-c++-common/pr46562-2.c	2014-05-14 14:15:15.536871496 +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-05-14 14:06:26.860907895 +0200
--- trunk/gcc/tree-ssa-propagate.c	2014-05-14 14:15:15.537871496 +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-05-14 14:06:26.860907895 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-24.c	2014-05-14 14:15:15.537871496 +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-05-14 14:06:26.860907895 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-25.c	2014-05-14 14:15:15.537871496 +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-05-14 14:06:26.860907895 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-32.c	2014-05-14 14:15:15.538871496 +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-05-14 14:06:26.860907895 +0200
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-16.c	2014-05-14 14:15:15.538871496 +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" } } */

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
  2014-05-14 14:04 [PATCH][RFC] Make FRE/PRE apply copy/constant propagation Richard Biener
@ 2014-06-13 10:01 ` Richard Biener
  2014-06-14 15:15   ` Eric Botcazou
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Biener @ 2014-06-13 10:01 UTC (permalink / raw)
  To: gcc-patches

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  <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.


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" } } */

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
  2014-06-13 10:01 ` Richard Biener
@ 2014-06-14 15:15   ` Eric Botcazou
  2014-06-16  9:30     ` Richard Biener
  0 siblings, 1 reply; 4+ messages in thread
From: Eric Botcazou @ 2014-06-14 15:15 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1222 bytes --]

> 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.

This breaks Ada bootstrap with non-standard build options (-gnatpgn).  I have 
attached a reduced testcase, but you need the Ada SJLJ scheme to see it so the 
following procedure can be used:

 1. Put p.ad[bs] in $(BUILDDIR)
 2. Do "gcc/gnat1 -quiet p.adb -I $(SRCDIR)/gcc/ada -I gcc/ada -O2 -gnatn"

eric@polaris:~/build/gcc/native> gcc/gnat1 -quiet p.adb -I ~/svn/gcc/gcc/ada -
I gcc/ada -O2 -gnatn
+===========================GNAT BUG DETECTED==============================+
| 4.10.0 20140614 (experimental) [trunk revision 211664] (x86_64-suse-linux) 
GCC error:|
| in forward_edge_to_pdom, at tree-ssa-dce.c:1042                          |
| Error detected around /home/eric/svn/gcc/gcc/ada/sinfo.adb:6010:8        |

-- 
Eric Botcazou

[-- Attachment #2: p.adb --]
[-- Type: text/x-adasrc, Size: 2716 bytes --]

with Atree;    use Atree;
with Einfo;    use Einfo;
with Elists;   use Elists;
with Exp_Ch6;  use Exp_Ch6;
with Nmake;    use Nmake;
with Opt;      use Opt;
with Rtsfind;  use Rtsfind;
with Sem_Aux;  use Sem_Aux;
with Sinfo;    use Sinfo;
with Tbuild;   use Tbuild;

package body P is

   procedure Expand_Allocator_Expression (N : Node_Id) is
      Loc    : constant Source_Ptr := Sloc (N);
      Exp    : constant Node_Id    := Expression (Expression (N));

      procedure Apply_Accessibility_Check (Ref : Node_Id) is
      begin
         null;
      end Apply_Accessibility_Check;

      Indic         : constant Node_Id   := Subtype_Mark (Expression (N));
      T             : constant Entity_Id := Entity (Indic);
      Tag_Assign    : Node_Id;
      Temp          : Entity_Id;
      TagT : Entity_Id := Empty;
      TagR : Node_Id := Empty;

   begin

      if Ada_Version >= Ada_2012 and then Nkind (Exp) = N_Function_Call then
         declare
            Subp : Entity_Id;
         begin
            if Nkind (Name (Exp)) = N_Explicit_Dereference then
               Subp := Designated_Type (Etype (Prefix (Name (Exp))));
            else
               Subp := Entity (Name (Exp));
            end if;
         end;
      end if;

      if Is_Tagged_Type (T) then

         if Ada_Version >= Ada_2005 then
            Make_Build_In_Place_Call_In_Allocator (N, Exp);
            Apply_Accessibility_Check (N);
            return;
         end if;

         Temp := Make_Temporary (Loc, 'P', N);

         if Is_Private_Type (T)
           and then Is_Tagged_Type (Underlying_Type (T))
         then
            TagT := Underlying_Type (T);
            TagR :=
              Unchecked_Convert_To (Underlying_Type (T),
                Make_Explicit_Dereference (Loc,
                  Prefix => New_Occurrence_Of (Temp, Loc)));
         end if;

         if Present (TagT) then
            declare
               Full_T : constant Entity_Id := Underlying_Type (TagT);
            begin
               Tag_Assign :=
                 Make_Assignment_Statement (Loc,
                   Name       =>
                     Make_Selected_Component (Loc,
                       Prefix        => TagR,
                       Selector_Name =>
                         New_Occurrence_Of
                           (First_Tag_Component (Full_T), Loc)),

                   Expression =>
                     Unchecked_Convert_To (RTE (RE_Tag),
                       New_Occurrence_Of
                         (Elists.Node
                           (First_Elmt (Access_Disp_Table (Full_T))), Loc)));
            end;
         end if;

      end if;

   exception
      when RE_Not_Available => return;
   end;

end P;

[-- Attachment #3: p.ads --]
[-- Type: text/x-adasrc, Size: 101 bytes --]

with Types; use Types;

package P is

   procedure Expand_Allocator_Expression (N : Node_Id);

end P;

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][RFC] Make FRE/PRE apply copy/constant propagation
  2014-06-14 15:15   ` Eric Botcazou
@ 2014-06-16  9:30     ` Richard Biener
  0 siblings, 0 replies; 4+ messages in thread
From: Richard Biener @ 2014-06-16  9:30 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches

On Sat, 14 Jun 2014, Eric Botcazou wrote:

> > 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.
> 
> This breaks Ada bootstrap with non-standard build options (-gnatpgn).  I have 
> attached a reduced testcase, but you need the Ada SJLJ scheme to see it so the 
> following procedure can be used:
> 
>  1. Put p.ad[bs] in $(BUILDDIR)
>  2. Do "gcc/gnat1 -quiet p.adb -I $(SRCDIR)/gcc/ada -I gcc/ada -O2 -gnatn"
> 
> eric@polaris:~/build/gcc/native> gcc/gnat1 -quiet p.adb -I ~/svn/gcc/gcc/ada -
> I gcc/ada -O2 -gnatn
> +===========================GNAT BUG DETECTED==============================+
> | 4.10.0 20140614 (experimental) [trunk revision 211664] (x86_64-suse-linux) 
> GCC error:|
> | in forward_edge_to_pdom, at tree-ssa-dce.c:1042                          |
> | Error detected around /home/eric/svn/gcc/gcc/ada/sinfo.adb:6010:8        |

Seems to be an issue with the assert

1041              /* The resulting PHI if not dead can only be degenerate.  
*/
1042              gcc_assert (degenerate_phi_p (phi));

and the fact that the PHI is abnormal and thus while it really _is_
degenerate value-wise, we can't easily prove it (by that predicate).

Not sure what to do here but adjust it to

  gcc_assert (degenerate_phi_p (phi) || SSA_NAME_OCCURS_IN_ABNORMAL_PHI 
(gimple_phi_result (phi)));

So - can you check if bootstrap works with that?

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-06-16  9:30 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-14 14:04 [PATCH][RFC] Make FRE/PRE apply copy/constant propagation Richard Biener
2014-06-13 10:01 ` Richard Biener
2014-06-14 15:15   ` Eric Botcazou
2014-06-16  9:30     ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).