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.
---
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(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr128232-1.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr128232-2.c
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 00000000000..ee3c6463e98
--- /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 00000000000..0925c5f6928
--- /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 c5437cfdc84..ab9824c48f3 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
--
2.34.1