https://gcc.gnu.org/g:57305e18fdf78a656efe1985d5a4e99d438edbd5
commit r15-10667-g57305e18fdf78a656efe1985d5a4e99d438edbd5 Author: Andrew MacLeod <[email protected]> Date: Wed Jan 7 10:55:49 2026 -0500 Early builtin_unreachable removal must examine dependencies. Even if all uses of a name are dominated by the unreachable branch, recomputation of a value in the defintion of a name might be reachable. PR tree-optimization/123300 gcc/ * gimple-range-gori.cc (gori_map::exports_and_deps): New. * gimple-range-gori.h (exports_and_deps): New prototype. (FOR_EACH_GORI_EXPORT_AND_DEP_NAME): New macro. * tree-vrp.cc (remove_unreachable:remove_unreachable): Initialize m_tmp bitmap. (remove_unreachable:~remove_unreachable): Dispose of m_tmp bitmap. (remove_unreachable:fully_replaceable): Move from static function and check reachability of exports and dependencies. gcc/testsuite/ * gcc.dg/pr123300.c: New. Diff: --- gcc/gimple-range-gori.cc | 22 ++++++++++++++++++++++ gcc/gimple-range-gori.h | 9 ++++++++- gcc/testsuite/gcc.dg/pr123300.c | 29 +++++++++++++++++++++++++++++ gcc/tree-vrp.cc | 16 ++++++++++------ 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 9761abffc005..9ce066692328 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -383,6 +383,28 @@ gori_map::exports (basic_block bb) return m_outgoing[bb->index]; } +// Return the bitmap vector of all exports AND their dependencies from BB +// in TMPBIT. Calculate if necessary. Return TMPBIT. + +bitmap +gori_map::exports_and_deps (basic_block bb, bitmap tmpbit) +{ + if (bb->index >= (signed int)m_outgoing.length () || !m_outgoing[bb->index]) + calculate_gori (bb); + bitmap_copy (tmpbit, m_outgoing[bb->index]); + if (!bitmap_empty_p (tmpbit)) + { + tree name; + FOR_EACH_GORI_EXPORT_NAME (this, bb, name) + { + bitmap dep = get_def_chain (name); + if (dep) + bitmap_ior_into (tmpbit, dep); + } + } + return tmpbit; +} + // Return the bitmap vector of all imports to BB. Calculate if necessary. bitmap diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index 15eaa91d7add..16a41bd882fd 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -99,6 +99,7 @@ public: bool is_export_p (tree name, basic_block bb = NULL); bool is_import_p (tree name, basic_block bb); bitmap exports (basic_block bb); + bitmap exports_and_deps (basic_block bb, bitmap tmpbit); bitmap imports (basic_block bb); void set_range_invariant (tree name, bool invariant = true); @@ -223,7 +224,7 @@ bool gori_on_edge (class ssa_cache &r, edge e, range_query *query = NULL); bool gori_name_on_edge (vrange &r, tree name, edge e, range_query *q = NULL); // For each name that is an import into BB's exports.. -#define FOR_EACH_GORI_IMPORT_NAME(gorimap, bb, name) \ +#define FOR_EACH_GORI_IMPORT_NAME(gorimap, bb, name) \ for (gori_export_iterator iter ((gorimap)->imports ((bb))); \ ((name) = iter.get_name ()); \ iter.next ()) @@ -234,6 +235,12 @@ bool gori_name_on_edge (vrange &r, tree name, edge e, range_query *q = NULL); ((name) = iter.get_name ()); \ iter.next ()) +// For each name and all their dependencies possibly exported from block BB. +#define FOR_EACH_GORI_EXPORT_AND_DEP_NAME(gorimap, bb, name, bm) \ + for (gori_export_iterator iter ((gorimap)->exports_and_deps ((bb),(bm))); \ + ((name) = iter.get_name ()); \ + iter.next ()) + // Used to assist with iterating over the GORI export list in various ways class gori_export_iterator { public: diff --git a/gcc/testsuite/gcc.dg/pr123300.c b/gcc/testsuite/gcc.dg/pr123300.c new file mode 100644 index 000000000000..7309f3dd9c0b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr123300.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-vrp1" } */ +[[gnu::noipa]] void +bar (int a, int b) +{ + if (a < 0) + __builtin_abort (); +} + +[[gnu::noipa]] void +foo (int n, bool p) +{ + for (int i = n; i-- > 0;) + { + const int x = 1 << i; + if (x <= 0) + __builtin_unreachable (); + if (p) + bar (i, x); + } +} + +int +main () +{ + foo (4, true); +} +/* { dg-final { scan-tree-dump "__builtin_unreachable" "vrp1" } } */ + diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc index 5aeb1e066cf9..9b2d3d708cc3 100644 --- a/gcc/tree-vrp.cc +++ b/gcc/tree-vrp.cc @@ -87,15 +87,17 @@ along with GCC; see the file COPYING3. If not see class remove_unreachable { public: remove_unreachable (range_query &r, bool all) : m_ranger (r), final_p (all) - { m_list.create (30); } - ~remove_unreachable () { m_list.release (); } + { m_list.create (30); m_tmp = BITMAP_ALLOC (NULL); } + ~remove_unreachable () { BITMAP_FREE (m_tmp); m_list.release (); } void handle_early (gimple *s, edge e); void maybe_register (gimple *s); bool remove (); bool remove_and_update_globals (); + bool fully_replaceable (tree name, basic_block bb); vec<std::pair<int, int> > m_list; range_query &m_ranger; bool final_p; + bitmap m_tmp; }; // Check if block BB has a __builtin_unreachable () call on one arm, and @@ -141,8 +143,8 @@ remove_unreachable::maybe_register (gimple *s) // goto <bb 3>; [0.00%] // Any additional use of _1 or _2 in this block invalidates early replacement. -static bool -fully_replaceable (tree name, basic_block bb) +bool +remove_unreachable::fully_replaceable (tree name, basic_block bb) { use_operand_p use_p; imm_use_iterator iter; @@ -213,9 +215,11 @@ remove_unreachable::handle_early (gimple *s, edge e) gcc_checking_assert (gimple_outgoing_range_stmt_p (e->src) == s); gcc_checking_assert (!final_p); - // Check if every export use is dominated by this branch. + // Check if every export and its dependencies are dominated by this branch. + // Dependencies are required as it needs to dominate potential + // recalculations. See PR 123300. tree name; - FOR_EACH_GORI_EXPORT_NAME (m_ranger.gori_ssa (), e->src, name) + FOR_EACH_GORI_EXPORT_AND_DEP_NAME (m_ranger.gori_ssa (), e->src, name, m_tmp) { if (!fully_replaceable (name, e->src)) return;
