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
Related show

Commit Message

Richard Biener May 6, 2021, 10:53 a.m.
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

-- 
2.26.2

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))
 	    {