tree-optimization/127130 - avoid peeled CHREC with UB

Message ID o9q99qs9-16no-ps54-9532-7647o83221o7@fhfr.qr
State Committed
Commit 7686bcbb2b7b08688008a6a0e29e6561af1a9a98
Headers
Series tree-optimization/127130 - avoid peeled CHREC with UB |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-arm-bootstrap fail Patch failed to apply
linaro-tcwg-bot/tcwg_simplebootstrap_build--master-aarch64-bootstrap fail Patch failed to apply

Commit Message

Richard Biener Sept. 1, 2026, 2:05 p.m. UTC
  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.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

I filed PR127180.

Pushed.

	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.
---
 .../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(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr127130-1.c
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr127130-2.c
  

Patch

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 12b508657fa..fe7cb31b5a1 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 00000000000..4f94d83160b
--- /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 00000000000..58b519abb08
--- /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 500e0a3567d..4386e288de1 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");