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");
