[PATCH v2] gimple-fold: fix follow_outer_ssa_edges for undefined overflow cases [PR126313]

Andrea Pinski <[email protected]> Fri, 31 Jul 2026 22:41:19 -0700
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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]>
---
 gcc/gimple-fold.cc                      | 13 ++++++------
 gcc/testsuite/gcc.dg/torture/pr126313.c | 27 +++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr126313.c

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index fdb9b419766..24041466108 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 00000000000..f4b754775fd
--- /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 ();
+}
-- 
2.43.0