tree-optimization/100434 - DSE aggregate call LHS
authorRichard Biener <rguenther@suse.de>
Wed, 5 May 2021 14:15:12 +0000 (16:15 +0200)
committerRichard Biener <rguenther@suse.de>
Mon, 10 May 2021 09:40:39 +0000 (11:40 +0200)
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.

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 [new file with mode: 0644]
gcc/tree-ssa-dse.c

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 (file)
index 0000000..f8785e9
--- /dev/null
@@ -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" } } */
index 63c876a..c3939a6 100644 (file)
@@ -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))
            {