https://gcc.gnu.org/g:1e578c16e98edeb6547b288a19537358d11f5f8a
commit r17-5660-g1e578c16e98edeb6547b288a19537358d11f5f8a Author: Xiaomei Xue <[email protected]> Date: Wed Oct 28 11:21:44 2026 +0000 loop-prefetch: Saturate reuse-volume multiplications [PR128232] The reuse-volume calculations can wrap to zero when their results exceed the range of unsigned, leading to incorrect prefetch and non-temporal store decisions. Use saturating multiplication to cap these estimates at UINT_MAX. gcc/ChangeLog: PR tree-optimization/128232 * tree-ssa-loop-prefetch.cc (saturating_mul): New function. (volume_of_dist_vector): Use it. (determine_loop_nest_reuse): Likewise. gcc/testsuite/ChangeLog: PR tree-optimization/128232 * gcc.dg/tree-ssa/pr128232-1.c: New test. * gcc.dg/tree-ssa/pr128232-2.c: New test. Signed-off-by: Xiaomei Xue <[email protected]> Diff: --- gcc/testsuite/gcc.dg/tree-ssa/pr128232-1.c | 26 ++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr128232-2.c | 16 ++++++++++++++++ gcc/tree-ssa-loop-prefetch.cc | 18 ++++++++++++++++-- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr128232-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr128232-1.c new file mode 100644 index 000000000000..ee3c6463e98f --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr128232-1.c @@ -0,0 +1,26 @@ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-require-effective-target double64 } */ +/* { dg-options "-O2 -fno-tree-vectorize -fprefetch-loop-arrays --param l1-cache-line-size=64 --param l2-cache-size=512 -fdump-tree-aprefetch-details" } */ + +/* The initial volume estimate, 64 * N * N = 4 GiB, must not wrap to zero. + Self-reuse reduces the saturated estimate to 64 * N = 512 KiB. */ +#define N 8192 + +double a[N][N]; + +double +sum_columns (void) +{ + unsigned i, j; + double sum = 0; + + for (i = 0; i < N; i++) + for (j = 0; j < N; j++) + sum += a[j][i]; + + return sum; +} + +/* { dg-final { scan-tree-dump-times {reference [0-9]+:[0-9]+ distance 524288} 1 "aprefetch" } } */ +/* { dg-final { scan-tree-dump-not {reference [0-9]+:[0-9]+ distance 0(\n|$)} "aprefetch" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr128232-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr128232-2.c new file mode 100644 index 000000000000..0925c5f6928a --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr128232-2.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */ +/* { dg-require-effective-target lp64 } */ +/* { dg-options "-O2 -fno-tree-vectorize -fno-tree-loop-distribute-patterns -fprefetch-loop-arrays -fdump-tree-aprefetch-details" } */ + +/* Each iteration reads and writes a 4-byte int. The 4 GiB total volume + must not wrap to zero and suppress non-temporal stores. */ + +void +store (int *__restrict b, const int *__restrict c, int scalar) +{ + for (unsigned long j = 0; j < 536870912UL; ++j) + b[j] = scalar * c[j]; +} + +/* { dg-final { scan-tree-dump-times {reference [0-9]+:[0-9]+ distance 4294967295} 2 "aprefetch" } } */ +/* { dg-final { scan-tree-dump-not {reference [0-9]+:[0-9]+ distance 0(\n|$)} "aprefetch" } } */ diff --git a/gcc/tree-ssa-loop-prefetch.cc b/gcc/tree-ssa-loop-prefetch.cc index c5437cfdc848..ab9824c48f38 100644 --- a/gcc/tree-ssa-loop-prefetch.cc +++ b/gcc/tree-ssa-loop-prefetch.cc @@ -1470,6 +1470,20 @@ volume_of_references (struct mem_ref_group *refs) return volume; } +/* Return VOLUME * COUNT, saturating at the largest representable reuse + distance. Distances above the L2 cache size are equivalent for + the reuse analysis, but wrapping them could make a streaming access look + cache-resident. Check before multiplying so even a wide COUNT is safe. */ + +static unsigned +saturating_mul (unsigned volume, unsigned HOST_WIDE_INT count) +{ + if (volume != 0 && count > UINT_MAX / volume) + return UINT_MAX; + + return volume * count; +} + /* Returns the volume of memory references accessed across VEC iterations of loops, whose sizes are described in the LOOP_SIZES array. N is the number of the loops in the nest (length of VEC and LOOP_SIZES vectors). */ @@ -1490,7 +1504,7 @@ volume_of_dist_vector (lambda_vector vec, unsigned *loop_sizes, unsigned n) /* We ignore the parts of the distance vector in subloops, since usually the numbers of iterations are much smaller. */ - return loop_sizes[i] * vec[i]; + return saturating_mul (loop_sizes[i], vec[i]); } /* Add the steps of ACCESS_FN multiplied by STRIDE to the array STRIDE @@ -1655,7 +1669,7 @@ determine_loop_nest_reuse (class loop *loop, struct mem_ref_group *refs, vol = estimated_stmt_executions_int (aloop); if (vol == -1) vol = expected_loop_iterations (aloop); - volume *= vol; + volume = saturating_mul (volume, vol); } /* Prepare the references in the form suitable for data dependence
