For references with different bases, dependence analysis compares only
the structure-rooted access functions and sets DDR_COULD_BE_INDEPENDENT_P.
The distance vectors are then only valid for one fixed pair of objects,
which is the case when DDR_OBJECT_A is set because both objects are
invariant in the loop nest. In PR115869 res[k].v and res[k + d].v move
with k, so the vectors (0 0), (1 0) and (0 1) miss the (1, -d) dependence
and loop interchange wrongly swaps the nest. PR105771 is the same problem
in unroll-and-jam.
The vectorizer and prefetching handle such relations, but interchange and
unroll-and-jam use the vectors as they are and cannot check the objects at
runtime. The following makes both passes give up when DDR_OBJECT_A is not
set.
PR tree-optimization/115869
PR tree-optimization/105771
gcc/ChangeLog:
* gimple-loop-interchange.cc (tree_loop_interchange_compute_ddrs):
Give up if DDR_COULD_BE_INDEPENDENT_P is set and DDR_OBJECT_A is not.
* gimple-loop-jam.cc (adjust_unroll_factor): Likewise.
gcc/testsuite/ChangeLog:
* gcc.dg/torture/pr105771.c: New test.
* gcc.dg/torture/pr115869.c: New test.
Signed-off-by: Rohith Kapelli <[email protected]>
---
Bootstrapped and regression tested on aarch64-unknown-linux-gnu, and on
the gcc-14, gcc-15 and gcc-16 branches. An attempt to fix this in
tree-data-ref.cc instead regressed gcc.dg/vect/vect-alias-check-3.c.
OK for trunk and the branches?
gcc/gimple-loop-interchange.cc | 7 +++++
gcc/gimple-loop-jam.cc | 5 +++-
gcc/testsuite/gcc.dg/torture/pr105771.c | 36 +++++++++++++++++++++++++
gcc/testsuite/gcc.dg/torture/pr115869.c | 25 +++++++++++++++++
4 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/torture/pr105771.c
create mode 100644 gcc/testsuite/gcc.dg/torture/pr115869.c
diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
index 7f8ca2f9d57b..4091d1916ed1 100644
--- a/gcc/gimple-loop-interchange.cc
+++ b/gcc/gimple-loop-interchange.cc
@@ -1883,6 +1883,13 @@ tree_loop_interchange_compute_ddrs (vec<loop_p>
loop_nest,
&& DDR_NUM_DIR_VECTS (ddr) == 0))
return false;
+ /* The vectors describe one fixed pair of objects only when
+ DDR_OBJECT_A is set; this pass cannot check them at runtime. */
+ if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE
+ && DDR_COULD_BE_INDEPENDENT_P (ddr)
+ && !DDR_OBJECT_A (ddr))
+ return false;
+
/* If either data references is in outer loop of nest, we require
no dependence here because the data reference need to be moved
into inner loop during interchange. */
diff --git a/gcc/gimple-loop-jam.cc b/gcc/gimple-loop-jam.cc
index 2c4162d17a2a..7b39f40f229a 100644
--- a/gcc/gimple-loop-jam.cc
+++ b/gcc/gimple-loop-jam.cc
@@ -407,7 +407,10 @@ adjust_unroll_factor (class loop *inner, struct
data_dependence_relation *ddr,
bool ret = false;
if (DDR_ARE_DEPENDENT (ddr) != chrec_known)
{
- if (DDR_NUM_DIST_VECTS (ddr) == 0)
+ /* The vectors describe one fixed pair of objects only when
+ DDR_OBJECT_A is set; this pass cannot check them at runtime. */
+ if (DDR_NUM_DIST_VECTS (ddr) == 0
+ || (DDR_COULD_BE_INDEPENDENT_P (ddr) && !DDR_OBJECT_A (ddr)))
return false;
unsigned i;
lambda_vector dist_v;
diff --git a/gcc/testsuite/gcc.dg/torture/pr105771.c
b/gcc/testsuite/gcc.dg/torture/pr105771.c
new file mode 100644
index 000000000000..dc862f7e7cae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr105771.c
@@ -0,0 +1,36 @@
+/* PR tree-optimization/105771 */
+/* { dg-do run } */
+/* { dg-additional-options "-floop-unroll-and-jam" } */
+
+struct st { unsigned v; };
+
+__attribute__((noipa)) void
+f (struct st *p, int m, int n, int d)
+{
+ for (int i = 0; i < m; i++)
+ for (int k = 0; k + d < n; k++)
+ p[k + d].v = p[k + d].v * 3 + p[k].v + (unsigned) i;
+}
+
+__attribute__((noipa)) void
+g (volatile unsigned *q, int m, int n, int d)
+{
+ for (int i = 0; i < m; i++)
+ for (int k = 0; k + d < n; k++)
+ q[k + d] = q[k + d] * 3 + q[k] + (unsigned) i;
+}
+
+int
+main ()
+{
+ struct st p[16];
+ unsigned q[16];
+ for (int j = 0; j < 16; j++)
+ p[j].v = q[j] = (unsigned) j + 1;
+ f (p, 8, 16, 1);
+ g (q, 8, 16, 1);
+ for (int j = 0; j < 16; j++)
+ if (p[j].v != q[j])
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr115869.c
b/gcc/testsuite/gcc.dg/torture/pr115869.c
new file mode 100644
index 000000000000..083a6180cc30
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr115869.c
@@ -0,0 +1,25 @@
+/* PR tree-optimization/115869 */
+/* { dg-do run } */
+/* { dg-additional-options "-floop-interchange" } */
+
+struct st { int v; };
+
+__attribute__((noipa)) int
+f (struct st *res)
+{
+ res[0].v = 1;
+ for (int d = 1; d < 3; d++)
+ for (int i = 0; i < 2; i++)
+ for (int k = 0; k + d < 3; k++)
+ res[k + d].v += res[k].v;
+ return res[2].v;
+}
+
+int
+main ()
+{
+ struct st res[3] = { { 0 }, { 0 }, { 0 } };
+ if (f (res) != 5)
+ __builtin_abort ();
+ return 0;
+}
--
2.53.0