]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/99912 - delete trivially dead stmts during DSE
authorRichard Biener <rguenther@suse.de>
Tue, 27 Apr 2021 12:32:27 +0000 (14:32 +0200)
committerRichard Biener <rguenther@suse.de>
Thu, 29 Apr 2021 06:32:14 +0000 (08:32 +0200)
DSE performs a backwards walk over stmts removing stores but it
leaves removing resulting dead SSA defs to later passes.  This
eats into its own alias walking budget if the removed stores kept
loads live.  The following patch adds removal of trivially dead
SSA defs which helps in this situation and reduces the amount of
garbage followup passes need to deal with.

2021-04-28  Richard Biener  <rguenther@suse.de>

PR tree-optimization/99912
* tree-ssa-dse.c (dse_dom_walker::m_need_cfg_cleanup): New.
(dse_dom_walker::todo): Likewise.
(dse_dom_walker::dse_optimize_stmt): Move VDEF check to the
caller.
(dse_dom_walker::before_dom_children): Remove trivially
dead SSA defs and schedule CFG cleanup if we removed all
PHIs in a block.
(pass_dse::execute): Get TODO as computed by the DOM walker
and return it.  Wipe dominator info earlier.

* gcc.dg/pr95580.c: Disable DSE.
* gcc.dg/Wrestrict-8.c: Place a use after each memcpy.
* c-c++-common/ubsan/overflow-negate-3.c: Make asms volatile
to prevent them from being removed.
* c-c++-common/ubsan/overflow-sub-4.c: Likewise.

gcc/testsuite/c-c++-common/ubsan/overflow-negate-3.c
gcc/testsuite/c-c++-common/ubsan/overflow-sub-4.c
gcc/testsuite/gcc.dg/Wrestrict-8.c
gcc/testsuite/gcc.dg/pr95580.c
gcc/tree-ssa-dse.c

index 85acce8e729b30e21882268f4c187073b4e8ef1b..6b612fa3fb72626db749449109bbf78690994f39 100644 (file)
@@ -8,11 +8,11 @@ main ()
 {
   int x = INT_MIN;
   int y;
-  asm ("" : "+g" (x));
+  __asm__ volatile ("" : "+g" (x));
   y = -(-x);
-  asm ("" : "+g" (y));
+  __asm__ volatile ("" : "+g" (y));
   y = -(-INT_MIN);
-  asm ("" : "+g" (y));
+  __asm__ volatile ("" : "+g" (y));
 }
 
 /* { dg-output "negation of -2147483648 cannot be represented in type 'int'\[^\n\r]*; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */
index d3fb9baeec9f4b6111188779b8e0bca3e05a3c92..14ed5fb93cd3537822430d838e547e316c65ad88 100644 (file)
@@ -9,10 +9,10 @@ main ()
   int x = INT_MIN;
   int y = 0;
   int z;
-  asm ("" : "+g" (y));
-  asm ("" : "+g" (x));
+  __asm__ volatile ("" : "+g" (y));
+  __asm__ volatile ("" : "+g" (x));
   z = y - (-x);
-  asm ("" : "+g" (z));
+  __asm__ volatile ("" : "+g" (z));
 }
 
 /* { dg-output "negation of -2147483648 cannot be represented in type 'int'\[^\n\r]*; cast to an unsigned type to negate this value to itself\[^\n\r]*(\n|\r\n|\r)" } */
index 24946b08c3b91ca59e41b0feb644f0e38c8a5f5c..62e8bbc3027a8a0f207e4015af232ba547ae2a1e 100644 (file)
@@ -7,7 +7,9 @@ typedef __SIZE_TYPE__ size_t;
 
 extern void* memcpy (void* restrict, const void* restrict, size_t);
 
-#define T(d, s, n)   memcpy (d, s, n)
+void foo (void *);
+
+#define T(d, s, n)   do { memcpy (d, s, n); foo (d); } while (0)
 
 struct S1 { char c; } a8_1[8];
 
index 330a3137f1e99c6f2e48d00a365981c47e960fca..77d8150baa85e6b706bfe426340710acc6cf0736 100644 (file)
@@ -1,6 +1,6 @@
 /* PR c/95580 */
 /* { dg-do compile } */
-/* { dg-options "-O1 -W -fno-tree-dce" } */
+/* { dg-options "-O1 -W -fno-tree-dce -fno-tree-dse" } */
 
 void bar (void);
 
index 4967a5a99272ba1c4e7ce4c4d1309b61665a16fd..aecf6ab8c46c481f61a0d813df6f39b87677b11c 100644 (file)
@@ -963,16 +963,25 @@ public:
   dse_dom_walker (cdi_direction direction)
     : dom_walker (direction),
     m_live_bytes (param_dse_max_object_size),
-    m_byte_tracking_enabled (false) {}
+    m_byte_tracking_enabled (false),
+    m_need_cfg_cleanup (false) {}
 
   virtual edge before_dom_children (basic_block);
+  unsigned todo () const;
 
 private:
   auto_sbitmap m_live_bytes;
   bool m_byte_tracking_enabled;
+  bool m_need_cfg_cleanup;
   void dse_optimize_stmt (gimple_stmt_iterator *);
 };
 
+unsigned
+dse_dom_walker::todo () const
+{
+  return m_need_cfg_cleanup ? TODO_cleanup_cfg : 0;
+}
+
 /* Delete a dead call at GSI, which is mem* call of some kind.  */
 static void
 delete_dead_or_redundant_call (gimple_stmt_iterator *gsi, const char *type)
@@ -1049,11 +1058,6 @@ dse_dom_walker::dse_optimize_stmt (gimple_stmt_iterator *gsi)
 {
   gimple *stmt = gsi_stmt (*gsi);
 
-  /* If this statement has no virtual defs, then there is nothing
-     to do.  */
-  if (!gimple_vdef (stmt))
-    return;
-
   /* Don't return early on *this_2(D) ={v} {CLOBBER}.  */
   if (gimple_has_volatile_ops (stmt)
       && (!gimple_clobber_p (stmt)
@@ -1180,12 +1184,53 @@ dse_dom_walker::before_dom_children (basic_block bb)
 
   for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
     {
-      dse_optimize_stmt (&gsi);
+      gimple *stmt = gsi_stmt (gsi);
+
+      if (gimple_vdef (stmt))
+       dse_optimize_stmt (&gsi);
+      else if (def_operand_p def_p = single_ssa_def_operand (stmt, SSA_OP_DEF))
+       {
+         /* When we remove dead stores make sure to also delete trivially
+            dead SSA defs.  */
+         if (has_zero_uses (DEF_FROM_PTR (def_p))
+             && !gimple_has_side_effects (stmt))
+           {
+             if (dump_file && (dump_flags & TDF_DETAILS))
+               {
+                 fprintf (dump_file, "  Deleted trivially dead stmt: ");
+                 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+                 fprintf (dump_file, "\n");
+               }
+             if (gsi_remove (&gsi, true) && need_eh_cleanup)
+               bitmap_set_bit (need_eh_cleanup, bb->index);
+             release_defs (stmt);
+           }
+       }
       if (gsi_end_p (gsi))
        gsi = gsi_last_bb (bb);
       else
        gsi_prev (&gsi);
     }
+  bool removed_phi = false;
+  for (gphi_iterator si = gsi_start_phis (bb); !gsi_end_p (si);)
+    {
+      gphi *phi = si.phi ();
+      if (has_zero_uses (gimple_phi_result (phi)))
+       {
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "  Deleted trivially dead PHI: ");
+             print_gimple_stmt (dump_file, phi, 0, dump_flags);
+             fprintf (dump_file, "\n");
+           }
+         remove_phi_node (&si, true);
+         removed_phi = true;
+       }
+      else
+       gsi_next (&si);
+    }
+  if (removed_phi && gimple_seq_empty_p (phi_nodes (bb)))
+    m_need_cfg_cleanup = true;
   return NULL;
 }
 
@@ -1234,21 +1279,23 @@ pass_dse::execute (function *fun)
 
   /* Dead store elimination is fundamentally a walk of the post-dominator
      tree and a backwards walk of statements within each block.  */
-  dse_dom_walker (CDI_POST_DOMINATORS).walk (fun->cfg->x_exit_block_ptr);
+  dse_dom_walker walker (CDI_POST_DOMINATORS);
+  walker.walk (fun->cfg->x_exit_block_ptr);
+  free_dominance_info (CDI_POST_DOMINATORS);
+
+  unsigned todo = walker.todo ();
 
   /* Removal of stores may make some EH edges dead.  Purge such edges from
      the CFG as needed.  */
   if (!bitmap_empty_p (need_eh_cleanup))
     {
       gimple_purge_all_dead_eh_edges (need_eh_cleanup);
-      cleanup_tree_cfg ();
+      todo |= TODO_cleanup_cfg;
     }
 
   BITMAP_FREE (need_eh_cleanup);
 
-  /* For now, just wipe the post-dominator information.  */
-  free_dominance_info (CDI_POST_DOMINATORS);
-  return 0;
+  return todo;
 }
 
 } // anon namespace