diff mbox series

tree-optimization/100434 - DSE aggregate call LHS

Message ID nycvar.YFH.7.76.2105061252120.11551@elmra.sevgm.obk
State New
Headers show
Series tree-optimization/100434 - DSE aggregate call LHS | expand

Commit Message

Richard Biener May 6, 2021, 10:53 a.m. UTC
This makes DSE consider aggregate LHS of calls as dead, for pure
or const calls the whole stmt and for others by removing the LHS.

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

I wonder if there's a more canonical test for call LHS that cannot
be removed than

+      if (gimple_call_return_slot_opt_p (as_a <gcall *>(stmt))
+         && (TREE_ADDRESSABLE (TREE_TYPE (gimple_call_fntype (stmt)))
+             || !poly_int_tree_p
+                   (TYPE_SIZE (TREE_TYPE (gimple_call_fntype (stmt))))))
+       return;

?

Richard.

2021-05-05  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/100434
	* tree-ssa-dse.c (initialize_ao_ref_for_dse): Handle
	call LHS.
	(dse_optimize_stmt): Handle call LHS by dropping the
	LHS or the whole call if it doesn't have other
	side-effects.
	(pass_dse::execute): Adjust.

	* gcc.dg/tree-ssa/ssa-dse-43.c: New testcase.
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c |  22 +++++
 gcc/tree-ssa-dse.c                         | 107 +++++++++++++--------
 2 files changed, 87 insertions(+), 42 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c
diff mbox series

Patch

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c
new file mode 100644
index 00000000000..f8785e9da46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-43.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-dse1-details" } */
+
+struct X { int x; };
+struct X x;
+
+extern struct X foo (void);
+void bar()
+{
+  x = foo();
+  x = (struct X){};
+}
+
+extern struct X __attribute__((const)) foo2 (int);
+void bar2()
+{
+  x = foo2 (1);
+  x = foo2 (2);
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted dead store in call LHS: x = foo " 1 "dse1" } } */
+/* { dg-final { scan-tree-dump-times "Deleted dead store: x = foo2 " 1 "dse1" } } */
diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c
index 63c876a1ff2..c3939a6417f 100644
--- a/gcc/tree-ssa-dse.c
+++ b/gcc/tree-ssa-dse.c
@@ -140,10 +140,13 @@  initialize_ao_ref_for_dse (gimple *stmt, ao_ref *write)
 	  break;
 	}
     }
-  else if (is_gimple_assign (stmt))
+  else if (tree lhs = gimple_get_lhs (stmt))
     {
-      ao_ref_init (write, gimple_assign_lhs (stmt));
-      return true;
+      if (TREE_CODE (lhs) != SSA_NAME)
+	{
+	  ao_ref_init (write, lhs);
+	  return true;
+	}
     }
   return false;
 }
@@ -1035,7 +1038,7 @@  delete_dead_or_redundant_assignment (gimple_stmt_iterator *gsi, const char *type
    post dominates the first store, then the first store is dead.  */
 
 static void
-dse_optimize_stmt (gimple_stmt_iterator *gsi, sbitmap live_bytes)
+dse_optimize_stmt (function *fun, gimple_stmt_iterator *gsi, sbitmap live_bytes)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
@@ -1113,49 +1116,69 @@  dse_optimize_stmt (gimple_stmt_iterator *gsi, sbitmap live_bytes)
 	}
     }
 
-  if (is_gimple_assign (stmt))
+  bool by_clobber_p = false;
+
+  /* Check if this statement stores zero to a memory location,
+     and if there is a subsequent store of zero to the same
+     memory location.  If so, remove the subsequent store.  */
+  if (gimple_assign_single_p (stmt)
+      && initializer_zerop (gimple_assign_rhs1 (stmt)))
+    dse_optimize_redundant_stores (stmt);
+
+  /* Self-assignments are zombies.  */
+  if (is_gimple_assign (stmt)
+      && operand_equal_p (gimple_assign_rhs1 (stmt),
+			  gimple_assign_lhs (stmt), 0))
+    ;
+  else
     {
-      bool by_clobber_p = false;
-
-      /* Check if this statement stores zero to a memory location,
-	 and if there is a subsequent store of zero to the same
-	 memory location.  If so, remove the subsequent store.  */
-      if (gimple_assign_single_p (stmt)
-	  && initializer_zerop (gimple_assign_rhs1 (stmt)))
-	dse_optimize_redundant_stores (stmt);
-
-      /* Self-assignments are zombies.  */
-      if (operand_equal_p (gimple_assign_rhs1 (stmt),
-			   gimple_assign_lhs (stmt), 0))
-	;
-      else
-	{
-	  bool byte_tracking_enabled
-	    = setup_live_bytes_from_ref (&ref, live_bytes);
-	  enum dse_store_status store_status;
-	  store_status = dse_classify_store (&ref, stmt,
-					     byte_tracking_enabled,
-					     live_bytes, &by_clobber_p);
-	  if (store_status == DSE_STORE_LIVE)
-	    return;
+      bool byte_tracking_enabled
+	  = setup_live_bytes_from_ref (&ref, live_bytes);
+      enum dse_store_status store_status;
+      store_status = dse_classify_store (&ref, stmt,
+					 byte_tracking_enabled,
+					 live_bytes, &by_clobber_p);
+      if (store_status == DSE_STORE_LIVE)
+	return;
 
-	  if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD)
-	    {
-	      maybe_trim_partially_dead_store (&ref, live_bytes, stmt);
-	      return;
-	    }
+      if (store_status == DSE_STORE_MAYBE_PARTIAL_DEAD)
+	{
+	  maybe_trim_partially_dead_store (&ref, live_bytes, stmt);
+	  return;
 	}
+    }
 
-      /* Now we know that use_stmt kills the LHS of stmt.  */
+  /* Now we know that use_stmt kills the LHS of stmt.  */
 
-      /* But only remove *this_2(D) ={v} {CLOBBER} if killed by
-	 another clobber stmt.  */
-      if (gimple_clobber_p (stmt)
-	  && !by_clobber_p)
-	return;
+  /* But only remove *this_2(D) ={v} {CLOBBER} if killed by
+     another clobber stmt.  */
+  if (gimple_clobber_p (stmt)
+      && !by_clobber_p)
+    return;
 
-      delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup);
+  if (is_gimple_call (stmt)
+      && (gimple_has_side_effects (stmt)
+	  || (stmt_could_throw_p (fun, stmt)
+	      && !fun->can_delete_dead_exceptions)))
+    {
+      /* Make sure we do not remove a return slot we cannot reconstruct
+	 later.  */
+      if (gimple_call_return_slot_opt_p (as_a <gcall *>(stmt))
+	  && (TREE_ADDRESSABLE (TREE_TYPE (gimple_call_fntype (stmt)))
+	      || !poly_int_tree_p
+		    (TYPE_SIZE (TREE_TYPE (gimple_call_fntype (stmt))))))
+	return;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "  Deleted dead store in call LHS: ");
+	  print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+	  fprintf (dump_file, "\n");
+	}
+      gimple_call_set_lhs (stmt, NULL_TREE);
+      update_stmt (stmt);
     }
+  else
+    delete_dead_or_redundant_assignment (gsi, "dead", need_eh_cleanup);
 }
 
 namespace {
@@ -1194,7 +1217,7 @@  pass_dse::execute (function *fun)
   need_eh_cleanup = BITMAP_ALLOC (NULL);
   auto_sbitmap live_bytes (param_dse_max_object_size);
 
-  renumber_gimple_stmt_uids (cfun);
+  renumber_gimple_stmt_uids (fun);
 
   calculate_dominance_info (CDI_DOMINATORS);
 
@@ -1211,7 +1234,7 @@  pass_dse::execute (function *fun)
 	  gimple *stmt = gsi_stmt (gsi);
 
 	  if (gimple_vdef (stmt))
-	    dse_optimize_stmt (&gsi, live_bytes);
+	    dse_optimize_stmt (fun, &gsi, live_bytes);
 	  else if (def_operand_p
 		     def_p = single_ssa_def_operand (stmt, SSA_OP_DEF))
 	    {