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

Reply via email to