https://gcc.gnu.org/g:e02ce3b8c4574c81a943eb1084b0e0bf6a9955d5

commit r17-3204-ge02ce3b8c4574c81a943eb1084b0e0bf6a9955d5
Author: Andrew MacLeod <[email protected]>
Date:   Tue Aug 4 12:13:15 2026 -0400

    Provide a DCE no-delete option.
    
    Add a flag which replaces statement with assignment to zero instead of
    removing them.
    
            PR tree-optimization/126329
            gcc/
            * tree-ssa-dce.cc (simple_dce_from_worklist): Add no-delete option.
            * tree-ssa-dce.h (simple_dce_from_worklist): Add no delete param.
            * tree-vrp.cc (remove_unreachable::handle_early): Use no delete 
option.
    
            gcc/testsuite/
            * gcc.dg/pr126329.c: New.

Diff:
---
 gcc/testsuite/gcc.dg/pr126329.c | 28 +++++++++++++++++++++
 gcc/tree-ssa-dce.cc             | 54 +++++++++++++++++++++++++++++++++--------
 gcc/tree-ssa-dce.h              |  2 +-
 gcc/tree-vrp.cc                 |  2 +-
 4 files changed, 74 insertions(+), 12 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/pr126329.c b/gcc/testsuite/gcc.dg/pr126329.c
new file mode 100644
index 000000000000..50165c574e5d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr126329.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+#include <stdint.h>
+int32_t g30;
+void f25(int32_t a1)
+{
+    int a2;
+    _Bool c6, c14;
+    int8_t v8;
+    int64_t v15;
+    int8_t v16;
+    if (a1 == 8098) goto lbl_sw11;
+    a2 = __builtin_ffs(a1);
+lbl_b8:
+    v8 = a2;
+    c6 = v8 >= v16;
+    goto lbl_br26;
+lbl_sw11:
+lbl_br17:
+    goto lbl_b8;
+lbl_br26:
+    g30 = v8;
+    if (c6) __builtin_unreachable();
+    c6 = c14 = a1;
+    a1 = v8;
+    if (v15) goto lbl_br26;
+    if (c14) goto lbl_br17;
+}
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index 548d5d4bd661..bf818ad2c919 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -2170,10 +2170,16 @@ make_pass_cd_dce (gcc::context *ctxt)
 /* A cheap DCE interface.  WORKLIST is a list of possibly dead stmts and
    is consumed by this function.  The function has linear complexity in
    the number of dead stmts with a constant factor like the average SSA
-   use operands number.  */
+   use operands number.
+   If no_delete is true (defaults to false) then rather than deleting the
+   statement, it is replaced with an assignment to 0.  This allows the
+   same elimination of statement dependencies, but delays the actual statement
+   removal from the IL until the next time DCE is run and they are detected
+   as dead statements with no uses. */
 
 void
-simple_dce_from_worklist (bitmap worklist, bitmap need_eh_cleanup)
+simple_dce_from_worklist (bitmap worklist, bitmap need_eh_cleanup,
+                         bool no_delete)
 {
   int phiremoved = 0;
   int stmtremoved = 0;
@@ -2217,11 +2223,20 @@ simple_dce_from_worklist (bitmap worklist, bitmap 
need_eh_cleanup)
       gimple *t = SSA_NAME_DEF_STMT (def);
       if (gimple_has_side_effects (t))
        {
-         if (gcall *call = dyn_cast <gcall *> (t))
+         gcall *call = dyn_cast <gcall *> (t);
+         if (call)
            {
              gimple_call_set_lhs (call, NULL_TREE);
              update_stmt (call);
-             release_ssa_name (def);
+             if (no_delete)
+               {
+                 tree zero = build_zero_cst (TREE_TYPE (def));
+                 gassign *new_stmt = gimple_build_assign (def, zero);
+                 gimple_stmt_iterator gsi = gsi_for_stmt (t);
+                 gsi_insert_after (&gsi, new_stmt, GSI_SAME_STMT);
+               }
+             else
+               release_ssa_name (def);
            }
          continue;
        }
@@ -2263,19 +2278,38 @@ simple_dce_from_worklist (bitmap worklist, bitmap 
need_eh_cleanup)
       gimple_stmt_iterator gsi = gsi_for_stmt (t);
       if (gimple_code (t) == GIMPLE_PHI)
        {
-         remove_phi_node (&gsi, true);
+         if (no_delete)
+           {
+             gphi *phi = as_a<gphi *> (t);
+             tree zero = build_zero_cst (TREE_TYPE (def));
+             for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
+               SET_PHI_ARG_DEF (phi, i, zero);
+             update_stmt (phi);
+           }
+         else
+           remove_phi_node (&gsi, true);
+
          phiremoved++;
        }
       else
        {
          unlink_stmt_vdef (t);
-         gsi_remove (&gsi, true);
-         release_defs (t);
+         if (no_delete)
+           {
+             tree zero = build_zero_cst (TREE_TYPE (def));
+             gassign *new_stmt = gimple_build_assign (def, zero);
+             gsi_replace (&gsi, new_stmt, true);
+           }
+         else
+           {
+             gsi_remove (&gsi, true);
+             release_defs (t);
+           }
          stmtremoved++;
        }
     }
-  statistics_counter_event (cfun, "PHIs removed",
+  statistics_counter_event (cfun, no_delete ? "PHIs rewritten" : "PHIs 
removed",
                            phiremoved);
-  statistics_counter_event (cfun, "Statements removed",
-                           stmtremoved);
+  statistics_counter_event (cfun, no_delete ? "Statements rewritten"
+                                           : "Statements removed", 
stmtremoved);
 }
diff --git a/gcc/tree-ssa-dce.h b/gcc/tree-ssa-dce.h
index dd874479fb56..d97e5e7c3b1e 100644
--- a/gcc/tree-ssa-dce.h
+++ b/gcc/tree-ssa-dce.h
@@ -18,5 +18,5 @@ along with GCC; see the file COPYING3.  If not see
 
 #ifndef TREE_SSA_DCE_H
 #define TREE_SSA_DCE_H
-extern void simple_dce_from_worklist (bitmap, bitmap = nullptr);
+extern void simple_dce_from_worklist (bitmap, bitmap = nullptr, bool no_delete 
= false);
 #endif
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index da65d67b4052..6f1e3eb90352 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -248,7 +248,7 @@ remove_unreachable::handle_early (gimple *s, edge e)
     {
       auto_bitmap dce;
       bitmap_set_bit (dce, SSA_NAME_VERSION (ssa));
-      simple_dce_from_worklist (dce);
+      simple_dce_from_worklist (dce, nullptr, true);
     }
 }

Reply via email to