[gcc r17-2865] gimple-fold: fix follow_outer_ssa_edges for undefined overflow cases [PR126313]

Andrea Pinski via Gcc-cvs <[email protected]> Sat, 1 Aug 2026 06:24:07 +0000 (GMT)
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:8adc3726fe0c256f4ad36ba1c7d978261118e2f5

commit r17-2865-g8adc3726fe0c256f4ad36ba1c7d978261118e2f5
Author: Andrea Pinski <[email protected]>
Date:   Fri Jul 24 12:49:54 2026 -0700

    gimple-fold: fix follow_outer_ssa_edges for undefined overflow cases [PR126313]
    
    ifcombine uses match and match will use in some cases the global
    range causing wrong code as the range of the ssa name might be based
    on the outer condition.
    The case in the bug report is:
    ```
    
      # RANGE [irange] int [0, 255] MASK 0xff VALUE 0x0
      _2 = (int) a.0_1;
      if (_2 > 1)
        goto <bb 4>; [59.00%]
      else
        goto <bb 3>; [41.00%]
    
      <bb 3> [local count: 440234144]:
      # RANGE [irange] int [0, 1] MASK 0x1 VALUE 0x0
      _8 = (int) a.0_1;
      if (_2 > _8)
        goto <bb 4>; [50.00%]
      else
        goto <bb 5>; [50.00%]
    ```
    So this was `(_2 <= 1 && _2 <= _8) ? goto 5 else; goto 4;`
    This starts by combnining `_2 <= 1 && _2 <= _8` into `_2 <= min(1, _8)`.
    But since _8 has a range of [0,1], match invokes the pattern that was added
    in r14-868-gb06cfb62229f to giving `_2 <= (_8 & 1)` and then since _8 has a
    range of [0,1], that expression simpifies into `_2 < _8` which is wrong.
    as _2 is the same as _8. So we end up with not taking the condition any more.
    
    The problem comes follow_outer_ssa_edges is used to save off the global range
    but we return early if the variable had a type where overflow is undefined as we
    can't temporary rewrite it. So the fix is to swap around the saving the off
    the global range before returning early.
    
    Bootstrapped and tested on x86_64-linux-gnu with no regressions.
    
            PR tree-optimization/126313
    
    gcc/ChangeLog:
    
            * gimple-fold.cc (follow_outer_ssa_edges): Swap around returning
            for undefined overflow and saving off the global range.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/torture/pr126313.c: New test.
    
    Signed-off-by: Andrea Pinski <[email protected]>

Diff:
---
 gcc/gimple-fold.cc                      | 13 +++++++------
 gcc/testsuite/gcc.dg/torture/pr126313.c | 27 +++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index fdb9b4197662..24041466108f 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -7677,17 +7677,18 @@ follow_outer_ssa_edges (tree val)
 	      && (def_bb == fosa_bb
 		  || dominated_by_p (CDI_DOMINATORS, fosa_bb, def_bb))))
 	return val;
-      /* We cannot temporarily rewrite stmts with undefined overflow
-	 behavior, so avoid expanding them.  */
-      if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (val))
-	   || POINTER_TYPE_P (TREE_TYPE (val)))
-	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (val)))
-	return NULL_TREE;
       flow_sensitive_info_storage storage;
       storage.save_and_clear (val);
       /* If the definition does not dominate fosa_bb temporarily reset
 	 flow-sensitive info.  */
       fosa_unwind->safe_push (std::make_pair (val, storage));
+      /* We cannot temporarily rewrite stmts with undefined overflow
+	 behavior, so avoid expanding them. But still save off the
+	 flow-sensitive info as we might be using the ssa name as the leaf.  */
+      if ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (val))
+	   || POINTER_TYPE_P (TREE_TYPE (val)))
+	  && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (val)))
+	return NULL_TREE;
       return val;
     }
   return val;
diff --git a/gcc/testsuite/gcc.dg/torture/pr126313.c b/gcc/testsuite/gcc.dg/torture/pr126313.c
new file mode 100644
index 000000000000..f4b754775fde
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr126313.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* PR tree-optimization/126313 */
+unsigned char a = 3;
+short b, c, d;
+int e;
+static inline
+char(f)(signed char g, signed char p2) {
+  return p2 == 0 || g && p2 == 1 ? 0 : g % p2; 
+}
+static inline
+unsigned i(short g) {
+  d = g;
+  return c;
+}
+static inline
+void fn3(signed char g, int p2) {
+  if (!(1 >= p2 && p2 <= g))
+    e = b | i(f(1, p2) > 0xE151060F);
+  else {
+    { d = p2; }
+  }
+}
+int main() {
+  fn3(a, a);
+  if (d != 0)
+    __builtin_abort ();
+}