https://gcc.gnu.org/g:7686bcbb2b7b08688008a6a0e29e6561af1a9a98

commit r17-3818-g7686bcbb2b7b08688008a6a0e29e6561af1a9a98
Author: Richard Biener <[email protected]>
Date:   Tue Sep 1 15:09:42 2026 +0200

    tree-optimization/127130 - avoid peeled CHREC with UB
    
    The following properly guards the peeled CHREC optimization
    when we are analyzing a CHREC with non-wrapping overflow.
    Otherwise we can introduce UB which can manifest via
    infer_loop_bounds_from_signedness and thus wrong niter analysis.
    
    This regresses gcc.dg/gomp/static-chunk-size-one.c because we
    can no longer replace a signed IV via a peeled chrec and lack
    other means.
    
            PR tree-optimization/127130
            * tree-scalar-evolution.cc (simplify_peeled_chrec):
            Guard against signed integer overflow UB.
    
            * gcc.dg/torture/pr127130-1.c: New testcase.
            * gcc.dg/torture/pr127130-2.c: Likewise.
            * gcc.dg/gomp/static-chunk-size-one.c: Adjust.

Diff:
---
 gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c |  4 ++--
 gcc/testsuite/gcc.dg/torture/pr127130-1.c         | 29 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr127130-2.c         | 29 +++++++++++++++++++++++
 gcc/tree-scalar-evolution.cc                      | 16 +++++++++++--
 4 files changed, 74 insertions(+), 4 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c 
b/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
index 12b508657faf..fe7cb31b5a17 100644
--- a/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
+++ b/gcc/testsuite/gcc.dg/gomp/static-chunk-size-one.c
@@ -14,5 +14,5 @@ bar ()
 }
 
 /* Two phis for reduction, one in loop header, one in loop exit.  One phi for 
iv
-   in loop header.  */
-/* { dg-final { scan-tree-dump-times "PHI" 3 "optimized" } } */
+   in loop header.  One missed elided for a conversion.  */
+/* { dg-final { scan-tree-dump-times "PHI" 4 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr127130-1.c 
b/gcc/testsuite/gcc.dg/torture/pr127130-1.c
new file mode 100644
index 000000000000..4f94d83160be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr127130-1.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+
+short a, *b;
+signed char c, i = 11, j, k, l, m;
+signed char tt;
+__attribute__((noinline)) int t(signed char r) {
+    if (r != 5)
+      __builtin_abort();
+  return 0;
+}
+int main() {
+  short n = 20158;
+  while (1) {
+    b = &n;
+    a = ~n;
+    c = n;
+    if (a < -32255)
+      break;
+    j = n;
+    k = j % i;
+    m = l = 5;
+    m = m * k % i * k;
+    l = l + 8 * k + m;
+    l = l % i;
+    t(l);
+    *b = 6303 + n;
+  }
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr127130-2.c 
b/gcc/testsuite/gcc.dg/torture/pr127130-2.c
new file mode 100644
index 000000000000..58b519abb089
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr127130-2.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+
+short a, *b;
+signed char c, i = 11, j, k, l, m;
+signed char tt;
+__attribute__((noinline)) int t(signed char r) {
+  tt = 1;
+  return 0;
+}
+int main() {
+  short n = 20158;
+  while (1) {
+    a = ~n;
+    c = n;
+    if (a < -32255)
+      break;
+    j = n;
+    k = j % i;
+    m = l = 5;
+    m = m * k % i * k;
+    l = l + 8 * k + m;
+    l = l % i;
+    t(l);
+    n = 6303 + n;
+  }
+  if (l != 5)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
index 500e0a3567d7..4386e288de15 100644
--- a/gcc/tree-scalar-evolution.cc
+++ b/gcc/tree-scalar-evolution.cc
@@ -1425,7 +1425,13 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree 
init_cond)
 
   /* Transform (init, {left, right}_LOOP)_LOOP to {init, right}_LOOP
      if "left" equals to "init + right".  */
-  if (operand_equal_p (left, step_val, 0))
+  if (operand_equal_p (left, step_val, 0)
+      && ((!POINTER_TYPE_P (type) && !INTEGRAL_TYPE_P (type))
+         || TYPE_OVERFLOW_WRAPS (type)
+         /* When overflow in the type doesn't wrap, make sure the
+            resulting CHREC does not either.  */
+         || !scev_probably_wraps_p (NULL_TREE, init_cond, right, NULL,
+                                    loop, false)))
     {
       if (dump_file && (dump_flags & TDF_SCEV))
        fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n");
@@ -1447,7 +1453,13 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree 
init_cond)
 
   /* Transform (init, {left, right}_LOOP)_LOOP to {init, right}_LOOP
      if "left" equals to "init + right".  */
-  if (aff_combination_zero_p (&aff1))
+  if (aff_combination_zero_p (&aff1)
+      && ((!POINTER_TYPE_P (type) && !INTEGRAL_TYPE_P (type))
+         || TYPE_OVERFLOW_WRAPS (type)
+         /* When overflow in the type doesn't wrap, make sure the
+            resulting CHREC does not either.  */
+         || !scev_probably_wraps_p (NULL_TREE, init_cond, right, NULL,
+                                    loop, false)))
     {
       if (dump_file && (dump_flags & TDF_SCEV))
        fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n");

Reply via email to