diff gcc/tree-ssa-dce.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/tree-ssa-dce.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/tree-ssa-dce.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Dead code elimination pass for the GNU compiler.
-   Copyright (C) 2002-2018 Free Software Foundation, Inc.
+   Copyright (C) 2002-2020 Free Software Foundation, Inc.
    Contributed by Ben Elliston <bje@redhat.com>
    and Andrew MacLeod <amacleod@redhat.com>
    Adapted to use control dependence by Steven Bosscher, SUSE Labs.
@@ -115,6 +115,14 @@
 static int *bb_postorder;
 
 
+/* True if we should treat any stmt with a vdef as necessary.  */
+
+static inline bool
+keep_all_vdefs_p ()
+{
+  return optimize_debug;
+}
+
 /* If STMT is not already marked necessary, mark it, and add it to the
    worklist if ADD_TO_WORKLIST is true.  */
 
@@ -237,6 +245,12 @@
 
 	    default:;
 	    }
+
+	if (callee != NULL_TREE
+	    && flag_allocation_dce
+	    && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+	  return;
+
 	/* Most, but not all function calls are required.  Function calls that
 	   produce no result and have no side effects (i.e. const pure
 	   functions) are unnecessary.  */
@@ -245,6 +259,17 @@
 	    mark_stmt_necessary (stmt, true);
 	    return;
 	  }
+	/* IFN_GOACC_LOOP calls are necessary in that they are used to
+	   represent parameter (i.e. step, bound) of a lowered OpenACC
+	   partitioned loop.  But this kind of partitioned loop might not
+	   survive from aggressive loop removal for it has loop exit and
+	   is assumed to be finite.  Therefore, we need to explicitly mark
+	   these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */
+	if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP))
+	  {
+	    mark_stmt_necessary (stmt, true);
+	    return;
+	  }
 	if (!gimple_call_lhs (stmt))
 	  return;
 	break;
@@ -300,6 +325,12 @@
       return;
     }
 
+  if (gimple_vdef (stmt) && keep_all_vdefs_p ())
+    {
+      mark_stmt_necessary (stmt, true);
+      return;
+    }
+
   return;
 }
 
@@ -400,7 +431,7 @@
   /* Prevent the empty possibly infinite loops from being removed.  */
   if (aggressive)
     {
-      struct loop *loop;
+      class loop *loop;
       if (mark_irreducible_loops ())
 	FOR_EACH_BB_FN (bb, cfun)
 	  {
@@ -420,7 +451,7 @@
 	if (!finite_loop_p (loop))
 	  {
 	    if (dump_file)
-	      fprintf (dump_file, "can not prove finiteness of loop %i\n", loop->num);
+	      fprintf (dump_file, "cannot prove finiteness of loop %i\n", loop->num);
 	    mark_control_dependent_edges_necessary (loop->latch, false);
 	  }
     }
@@ -515,6 +546,9 @@
 static void
 mark_aliased_reaching_defs_necessary (gimple *stmt, tree ref)
 {
+  /* Should have been caught before calling this function.  */
+  gcc_checking_assert (!keep_all_vdefs_p ());
+
   unsigned int chain;
   ao_ref refd;
   gcc_assert (!chain_ovfl);
@@ -577,6 +611,11 @@
 
 	  default:;
 	  }
+
+      if (callee != NULL_TREE
+	  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+	      || DECL_IS_OPERATOR_DELETE_P (callee)))
+	return false;
     }
 
   if (! gimple_clobber_p (def_stmt))
@@ -588,6 +627,8 @@
 static void
 mark_all_reaching_defs_necessary (gimple *stmt)
 {
+  /* Should have been caught before calling this function.  */
+  gcc_checking_assert (!keep_all_vdefs_p ());
   walk_aliased_vdefs (NULL, gimple_vuse (stmt),
 		      mark_all_reaching_defs_necessary_1, NULL, &visited);
 }
@@ -763,7 +804,11 @@
 	  /* If this is a call to free which is directly fed by an
 	     allocation function do not mark that necessary through
 	     processing the argument.  */
-	  if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+	  bool is_delete_operator
+	    = (is_gimple_call (stmt)
+	       && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+	  if (is_delete_operator
+	      || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      gimple *def_stmt;
@@ -773,11 +818,25 @@
 	      if (TREE_CODE (ptr) == SSA_NAME
 		  && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
 		  && (def_callee = gimple_call_fndecl (def_stmt))
-		  && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
-		  && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
-		      || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
-		      || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
-		continue;
+		  && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+		       && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
+			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+			   || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+		      || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)))
+		{
+		  /* Delete operators can have alignment and (or) size as next
+		     arguments.  When being a SSA_NAME, they must be marked
+		     as necessary.  */
+		  if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
+		    for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
+		      {
+			tree arg = gimple_call_arg (stmt, i);
+			if (TREE_CODE (arg) == SSA_NAME)
+			  mark_operand_necessary (arg);
+		      }
+
+		  continue;
+		}
 	    }
 
 	  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
@@ -787,6 +846,10 @@
 	  if (!use)
 	    continue;
 
+	  /* No need to search for vdefs if we intrinsicly keep them all.  */
+	  if (keep_all_vdefs_p ())
+	    continue;
+
 	  /* If we dropped to simple mode make all immediately
 	     reachable definitions necessary.  */
 	  if (chain_ovfl)
@@ -831,6 +894,11 @@
 		      || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
 		continue;
 
+	      if (callee != NULL_TREE
+		  && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+		      || DECL_IS_OPERATOR_DELETE_P (callee)))
+		continue;
+
 	      /* Calls implicitly load from memory, their arguments
 	         in addition may explicitly perform memory loads.  */
 	      mark_all_reaching_defs_necessary (stmt);
@@ -985,7 +1053,8 @@
    containing I so that we don't have to look it up.  */
 
 static void
-remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
+remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb,
+		  vec<edge> &to_remove_edges)
 {
   gimple *stmt = gsi_stmt (*i);
 
@@ -1045,20 +1114,17 @@
       e->flags |= EDGE_FALLTHRU;
 
       /* Remove the remaining outgoing edges.  */
-      for (ei = ei_start (bb->succs); (e2 = ei_safe_edge (ei)); )
+      FOR_EACH_EDGE (e2, ei, bb->succs)
 	if (e != e2)
 	  {
-	    cfg_altered = true;
 	    /* If we made a BB unconditionally exit a loop or removed
 	       an entry into an irreducible region, then this transform
 	       alters the set of BBs in the loop.  Schedule a fixup.  */
 	    if (loop_exit_edge_p (bb->loop_father, e)
 		|| (e2->dest->flags & BB_IRREDUCIBLE_LOOP))
 	      loops_state_set (LOOPS_NEED_FIXUP);
-	    remove_edge (e2);
+	    to_remove_edges.safe_push (e2);
 	  }
-	else
-	  ei_next (&ei);
     }
 
   /* If this is a store into a variable that is being optimized away,
@@ -1201,6 +1267,7 @@
   gimple *stmt;
   tree call;
   vec<basic_block> h;
+  auto_vec<edge> to_remove_edges;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\nEliminating unnecessary statements:\n");
@@ -1238,6 +1305,7 @@
       bb = h.pop ();
 
       /* Remove dead statements.  */
+      auto_bitmap debug_seen;
       for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi)
 	{
 	  stmt = gsi_stmt (gsi);
@@ -1251,7 +1319,9 @@
 	     defining statement of its argument is not necessary
 	     (and thus is getting removed).  */
 	  if (gimple_plf (stmt, STMT_NECESSARY)
-	      && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+	      && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+		  || (is_gimple_call (stmt)
+		      && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
 	    {
 	      tree ptr = gimple_call_arg (stmt, 0);
 	      if (TREE_CODE (ptr) == SSA_NAME)
@@ -1283,11 +1353,15 @@
 			}
 		    }
 		  if (!dead)
-		    continue;
+		    {
+		      bitmap_clear (debug_seen);
+		      continue;
+		    }
 		}
 	      if (!is_gimple_debug (stmt))
 		something_changed = true;
-	      remove_dead_stmt (&gsi, bb);
+	      remove_dead_stmt (&gsi, bb, to_remove_edges);
+	      continue;
 	    }
 	  else if (is_gimple_call (stmt))
 	    {
@@ -1304,12 +1378,13 @@
 		     did not mark as necessary, it will confuse the
 		     special logic we apply to malloc/free pair removal.  */
 		  && (!(call = gimple_call_fndecl (stmt))
-		      || DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
-		      || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
-			  && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
-			  && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
-			  && !ALLOCA_FUNCTION_CODE_P
-			      (DECL_FUNCTION_CODE (call)))))
+		      || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
+			   || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
+			       && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+			       && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
+			       && !ALLOCA_FUNCTION_CODE_P
+			       (DECL_FUNCTION_CODE (call))))
+			  && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
 		{
 		  something_changed = true;
 		  if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1324,14 +1399,18 @@
 		  update_stmt (stmt);
 		  release_ssa_name (name);
 
-		  /* GOMP_SIMD_LANE or ASAN_POISON without lhs is not
-		     needed.  */
+		  /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
+		     without lhs is not needed.  */
 		  if (gimple_call_internal_p (stmt))
 		    switch (gimple_call_internal_fn (stmt))
 		      {
 		      case IFN_GOMP_SIMD_LANE:
+			if (gimple_call_num_args (stmt) >= 3
+			    && !integer_nonzerop (gimple_call_arg (stmt, 2)))
+			  break;
+			/* FALLTHRU */
 		      case IFN_ASAN_POISON:
-			remove_dead_stmt (&gsi, bb);
+			remove_dead_stmt (&gsi, bb, to_remove_edges);
 			break;
 		      default:
 			break;
@@ -1353,7 +1432,22 @@
 		    break;
 		  }
 	    }
+	  else if (gimple_debug_bind_p (stmt))
+	    {
+	      /* We are only keeping the last debug-bind of a
+	         non-DEBUG_EXPR_DECL variable in a series of
+		 debug-bind stmts.  */
+	      tree var = gimple_debug_bind_get_var (stmt);
+	      if (TREE_CODE (var) != DEBUG_EXPR_DECL
+		  && !bitmap_set_bit (debug_seen, DECL_UID (var)))
+		remove_dead_stmt (&gsi, bb, to_remove_edges);
+	      continue;
+	    }
+	  bitmap_clear (debug_seen);
 	}
+
+      /* Remove dead PHI nodes.  */
+      something_changed |= remove_dead_phis (bb);
     }
 
   h.release ();
@@ -1361,10 +1455,16 @@
   /* Since we don't track liveness of virtual PHI nodes, it is possible that we
      rendered some PHI nodes unreachable while they are still in use.
      Mark them for renaming.  */
-  if (cfg_altered)
+  if (!to_remove_edges.is_empty ())
     {
       basic_block prev_bb;
 
+      /* Remove edges.  We've delayed this to not get bogus debug stmts
+         during PHI node removal.  */
+      for (unsigned i = 0; i < to_remove_edges.length (); ++i)
+	remove_edge (to_remove_edges[i]);
+      cfg_altered = true;
+
       find_unreachable_blocks ();
 
       /* Delete all unreachable basic blocks in reverse dominator order.  */
@@ -1430,11 +1530,6 @@
 	    }
 	}
     }
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      /* Remove dead PHI nodes.  */
-      something_changed |= remove_dead_phis (bb);
-    }
 
   if (bb_postorder)
     free (bb_postorder);