https://gcc.gnu.org/g:f495eae10735f687366a59884a25561de823daff
commit f495eae10735f687366a59884a25561de823daff Author: Ondřej Machota <ondrejmach...@gmail.com> Date: Tue Apr 15 09:21:56 2025 +0200 rtl-ssa-dce: remove useless conditions and fix dead debug insns Diff: --- gcc/dce.cc | 87 ++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/gcc/dce.cc b/gcc/dce.cc index 40b4cd991151..630906fb1ec6 100644 --- a/gcc/dce.cc +++ b/gcc/dce.cc @@ -123,6 +123,8 @@ can_delete_call (rtx_insn *insn) return true; } +static bool inside_ud = false; + /* Return true if INSN is a normal instruction that can be deleted by the DCE pass. */ @@ -578,8 +580,6 @@ reset_unmarked_insns_debug_uses (void) } /* Delete every instruction that hasn't been marked. */ -static bool inside_ud = false; - static void delete_unmarked_insns (void) { @@ -819,7 +819,6 @@ fini_dce (bool fast) static unsigned int rest_of_handle_ud_dce (void) { - inside_ud = true; rtx_insn *insn; init_dce (false); @@ -833,6 +832,7 @@ rest_of_handle_ud_dce (void) } worklist.release (); + inside_ud = true; if (MAY_HAVE_DEBUG_BIND_INSNS) reset_unmarked_insns_debug_uses (); @@ -1381,9 +1381,8 @@ bool is_rtx_insn_prelive(rtx_insn *insn) { gcc_assert(GET_CODE(insn) == INSN); /* Don't delete insns that may throw if we cannot do so. */ - if (!(cfun->can_delete_dead_exceptions && can_alter_cfg) - && !insn_nothrow_p (insn)) - return true; + if (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn)) + return true; /* Callee-save restores are needed. */ if (RTX_FRAME_RELATED_P (insn) && crtl->shrink_wrapped_separate @@ -1410,8 +1409,8 @@ bool is_rtx_insn_prelive(rtx_insn *insn) { bool is_prelive(insn_info *insn) { - /* Phi insns are never prelive, bb head and end contain artificial uses that - we need to mark as prelive */ + /* Phi insns and debug insns are never prelive, bb head and end contain + artificial uses that we need to mark as prelive */ if (insn->is_bb_head() || insn->is_bb_end()) return true; @@ -1468,6 +1467,9 @@ rtl_ssa_dce_mark_prelive_insn(insn_info *insn, auto_vec<set_info *> &worklist, static auto_vec<set_info *> rtl_ssa_dce_mark_prelive(std::unordered_set<insn_info *> &marked) { + if (dump_file) + fprintf(dump_file, "DCE: prelive phase\n"); + auto_vec<set_info *> worklist; for (insn_info * insn : crtl->ssa->all_insns()) { if (is_prelive(insn)) @@ -1478,12 +1480,13 @@ rtl_ssa_dce_mark_prelive(std::unordered_set<insn_info *> &marked) } static std::unordered_set<insn_info *> -rtl_ssa_dce_mark() +rtl_ssa_dce_mark(std::unordered_set<phi_info *> &marked_phis) { - std::unordered_set<insn_info *> marked{}; /* Phi insn might have more that one phi node: gcc/gcc/testsuite/gcc.c-torture/execute/20000224-1.c */ - std::unordered_set<phi_info *> marked_phi_nodes{}; + std::unordered_set<insn_info *> marked{}; auto worklist = rtl_ssa_dce_mark_prelive(marked); + if (dump_file) + fprintf(dump_file, "DCE: marking phase\n"); while (!worklist.is_empty()) { set_info* set = worklist.pop(); @@ -1505,10 +1508,10 @@ rtl_ssa_dce_mark() might be used. */ phi_info* pi = as_a<phi_info *> (set); auto pi_uid = pi->uid(); - if (marked_phi_nodes.count(pi) > 0) + if (marked_phis.count(pi) > 0) continue; - marked_phi_nodes.emplace(pi); + marked_phis.emplace(pi); uses = pi->inputs(); } @@ -1527,37 +1530,43 @@ rtl_ssa_dce_mark() return marked; } +// Iterate over non-debug instructions in RPO and remove all aren't marked. static void rtl_ssa_dce_sweep(std::unordered_set<insn_info *> marked) { - /* We can get the number of items in the `marked` set and create an array - of changes with appropriate size */ + if (dump_file) + fprintf(dump_file, "DCE: Sweep phase\n"); + auto_vec<insn_change> to_delete; - for (insn_info * insn : crtl->ssa->all_insns()) { - /* Artificial and marked insns cannot be deleted. - There is a slight problem with phis, because we might want to delete - some phi nodes from phi insn. */ - if (insn->is_artificial() || insn->is_debug_insn() || marked.count(insn) > 0) + for (insn_info * insn : crtl->ssa->nondebug_insns()) { + // Artificial or marked insns cannot be deleted. + if (insn->is_artificial() || marked.count(insn) > 0) continue; - auto change = insn_change::delete_insn(insn); - to_delete.safe_push(change); if (dump_file) - fprintf(dump_file, "Sweeping insn %d\n", insn->uid()); - /* crtl->ssa->change_insn(change); */ + fprintf(dump_file, "Sweeping insn: %d\n", insn->uid()); + + auto change = insn_change::delete_insn(insn); + to_delete.safe_push(std::move(change)); + + // If we use following way with reverse_nondebug_insns, not all insns seem + // to be deleted... + // crtl->ssa->change_insn(change); } - auto attempt = crtl->ssa->new_change_attempt (); auto_vec<insn_change*> changes(to_delete.length()); for (size_t i = 0; i != to_delete.length(); ++i) { changes.safe_push(&to_delete[i]); } gcc_assert (crtl->ssa->verify_insn_changes(changes)); - /* segfault: gcc.c-torture/execute/20000224-1.c */ crtl->ssa->change_insns(changes); + + if (dump_file) + fprintf(dump_file, "DCE: finish sweep phase\n"); } +// Clear debug_insn uses and set gen_rtx_UNKNOWN_VAR_LOC static void reset_debug_insn_uses(insn_info * insn) { gcc_assert(insn->is_debug_insn()); @@ -1570,15 +1579,19 @@ static void reset_debug_insn_uses(insn_info * insn) { crtl->ssa->change_insn (change); } -// WIP +// Iterate over all debug_insns and reset those for which at least one of the +// uses isn't marked. static void -rtl_ssa_dce_reset_dead_debug(std::unordered_set<insn_info *> &marked) { +rtl_ssa_dce_reset_dead_debug(std::unordered_set<insn_info *> &marked, std::unordered_set<phi_info *> &marked_phis) { for (insn_info *insn : crtl->ssa->all_insns()) { if (!insn->is_debug_insn()) continue; + // TODO : use iterate_safely? for (use_info * use: insn->uses()) { - if (marked.count(use->def()->insn()) == 0) { + insn_info *parent_insn = use->def()->insn(); + if ((parent_insn->is_phi() && marked_phis.count(as_a<phi_info *>(use->def())) == 0) + || (!parent_insn->is_phi() && marked.count(parent_insn) == 0)) { reset_debug_insn_uses(insn); break; } @@ -1610,10 +1623,14 @@ rtl_ssa_dce() { rtl_ssa_dce_init(); // debug(crtl->ssa); - std::unordered_set<insn_info *> marked = rtl_ssa_dce_mark(); + if (dump_file) + dump(dump_file, crtl->ssa); + std::unordered_set<phi_info *> marked_phis; + std::unordered_set<insn_info *> marked = rtl_ssa_dce_mark(marked_phis); if (MAY_HAVE_DEBUG_BIND_INSNS) - rtl_ssa_dce_reset_dead_debug(marked); + rtl_ssa_dce_reset_dead_debug(marked, marked_phis); rtl_ssa_dce_sweep(marked); + // std::cerr << "\033[31m" << "SSA debug start" << "\033[0m" << "\n"; // debug (crtl->ssa); // for (insn_info * insn : crtl->ssa->all_insns()) { @@ -1624,14 +1641,6 @@ rtl_ssa_dce() // std::cerr << "\033[31m" << "SSA debug end" << "\033[0m" << "\n"; rtl_ssa_dce_done(); - /* We need to perform some kind of reset_unmarked_insns_debug_uses - to be able to reproduce ud_dce - now only 4 tests are falling - because of debug_insn being dependent on parallel with set flags - - gcc.c-torture/execute/20051215-1.c - - gcc.c-torture/execute/20100805-1.c - - gcc.c-torture/execute/pr39339.c - - gcc.c-torture/execute/pr47925.c */ - /* if (delete_trivially_dead_insns(get_insns (), max_reg_num ())) { std::cerr << "\033[31m" << "rtl_ssa_dce did not delete everything :(" << "\033[0m" << "\n";