https://gcc.gnu.org/g:de2d80d1101e1921d719918d57589ea2668dcc1f
commit r17-3205-gde2d80d1101e1921d719918d57589ea2668dcc1f Author: Andrew MacLeod <[email protected]> Date: Thu Aug 6 14:15:21 2026 -0400 Check for abnoraml ranges on full dom search. Inferred ranges are not adde dif the predecessor was an abnormal edge. This is extended to finding a taken abnrmal edge anywhere in the dominator search. PR tree-optimization/126531 gcc/ * gimple-range-cache.cc (ranger_cache::range_from_dom): Track abnormal edges throughout the dom search. gcc/testsuite/ * g++.dg/pr126531.C: New. Diff: --- gcc/gimple-range-cache.cc | 26 +++++++++++++++++----- gcc/testsuite/g++.dg/pr126531.C | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index c5a19c866fb0..a540a10ce588 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -1813,11 +1813,28 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, else bb = get_immediate_dominator (CDI_DOMINATORS, start_bb); + bool abnormal_dominator = false; // Search until a value is found, pushing blocks which may need calculating. for ( ; bb; prev_bb = bb, bb = get_immediate_dominator (CDI_DOMINATORS, bb)) { - // Accumulate any block exit inferred ranges. - infer_oracle ().maybe_adjust_range (infer, name, bb); + if (has_abnormal_call_or_eh_pred_edge_p (prev_bb)) + abnormal_dominator = true; + + // find the taken outgoing edge and check if it is abnormal. + if (!abnormal_dominator) + { + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->succs) + if (dominated_by_p (CDI_DOMINATORS, prev_bb, e->dest)) + { + if (e->flags & (EDGE_ABNORMAL | EDGE_EH)) + abnormal_dominator = true; + break; + } + // Accumulate any block exit inferred ranges. + infer_oracle ().maybe_adjust_range (infer, name, bb); + } // This block has an outgoing range. if (gori ().has_edge_range_p (name, bb)) @@ -1904,9 +1921,8 @@ ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb, } } - // Apply non-null if appropriate. - if (!has_abnormal_call_or_eh_pred_edge_p (start_bb)) - r.intersect (infer); + // Apply any inferred ranges discovered. + r.intersect (infer); if (DEBUG_RANGE_CACHE) { diff --git a/gcc/testsuite/g++.dg/pr126531.C b/gcc/testsuite/g++.dg/pr126531.C new file mode 100644 index 000000000000..4401dbf8fafe --- /dev/null +++ b/gcc/testsuite/g++.dg/pr126531.C @@ -0,0 +1,49 @@ +// { dg-do run } +// +/* More than 16 bytes, so S is returned in memory. *p becomes the return slot + of the call and GIMPLE keeps a single statement "*p_7(D) = h (k_8(D));", + a call that can throw whose store operand infers p != 0. */ + +struct S { int a[8]; }; + +__attribute__((noipa)) S +h (int k) +{ + if (k) + throw 1; /* Thrown before anything is stored. */ + S s = {}; + s.a[0] = 5; + return s; +} + +__attribute__((noipa)) int +f (S *p, int k) +{ + int r = 0; + try + { + *p = h (k); /* Infers p != 0, but only if it completes. */ + r = 1; + } + catch (...) + { + if (p == 0) /* Must not fold: the store never ran. */ + r = 12; + else + r = 2; + } + return r; +} + +S obj; + +int +main (void) +{ + if (f (&obj, 0) != 1) /* Normal path, p is &obj. */ + __builtin_abort (); + if (f (0, 1) != 12) /* h throws, no store, p is null. */ + __builtin_abort (); + return 0; +} +
