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); } }
