When we get a zero distance vector we still have to check for the
situation of a common inner loop with zero distance.  But we can
still allow a zero distance for the loop we distribute
(gcc.dg/tree-ssa/ldist-33.c is such a case).  This is because
zero distances in non-outermost loops are a misrepresentation
of dependence by dependence analysis.

Note that test coverage of loop distribution of loop nests is
very low.

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

Any comments?

        PR tree-optimization/112859
        PR tree-optimization/115347
        * tree-loop-distribution.cc
        (loop_distribution::pg_add_dependence_edges): For a zero
        distance vector still make sure to not have an inner
        loop with zero distance.

        * gcc.dg/torture/pr112859.c: New testcase.
        * gcc.dg/torture/pr115347.c: Likewise.
---
 gcc/testsuite/gcc.dg/torture/pr112859.c | 24 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/pr115347.c | 21 +++++++++++++++++++
 gcc/tree-loop-distribution.cc           | 27 +++++++++++++++----------
 3 files changed, 61 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr112859.c
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr115347.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr112859.c 
b/gcc/testsuite/gcc.dg/torture/pr112859.c
new file mode 100644
index 00000000000..18f5bf40cb7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr112859.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-loop-distribution" } */
+
+struct a {
+  char b;
+  int c;
+} f, *i = &f;
+static struct a e[4];
+int *d, **g = &d;
+static int h, j;
+int main()
+{
+  for (; h < 1; h++) {
+    struct a k = {1, 1};
+    for (j = 0; j < 2; j++) {
+      *i = e[h];
+      e[h] = k;
+    }
+    *g = 0;
+  }
+  if (f.c != 1)
+    __builtin_abort();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr115347.c 
b/gcc/testsuite/gcc.dg/torture/pr115347.c
new file mode 100644
index 00000000000..2299495144b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr115347.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-additional-options "-ftree-loop-distribution" } */
+
+struct a {
+  int b;
+  int c;
+} d, e[2];
+int f, g, h;
+int main()
+{
+  for (; f < 1; f++) {
+    for (h = 0; h < 2; h++) {
+      d = e[f];
+      g = e[1].c;
+      e[f].c = 1;
+    }
+  }
+  if (d.c != 1)
+    __builtin_abort();
+  return 0;
+}
diff --git a/gcc/tree-loop-distribution.cc b/gcc/tree-loop-distribution.cc
index 7c0e4a868e5..9d9d2ae592b 100644
--- a/gcc/tree-loop-distribution.cc
+++ b/gcc/tree-loop-distribution.cc
@@ -2178,25 +2178,30 @@ loop_distribution::pg_add_dependence_edges (struct 
graph *rdg, int dir,
                 gcc.dg/tree-ssa/pr94969.c.  */
              if (DDR_NUM_DIST_VECTS (ddr) != 1)
                this_dir = 2;
-             /* If the overlap is exact preserve stmt order.  */
-             else if (lambda_vector_zerop (DDR_DIST_VECT (ddr, 0),
-                                           DDR_NB_LOOPS (ddr)))
-               ;
-             /* Else as the distance vector is lexicographic positive swap
-                the dependence direction.  */
              else
                {
-                 if (DDR_REVERSED_P (ddr))
-                   this_dir = -this_dir;
-                 this_dir = -this_dir;
-
+                 /* If the overlap is exact preserve stmt order.  */
+                 if (lambda_vector_zerop (DDR_DIST_VECT (ddr, 0),
+                                          DDR_NB_LOOPS (ddr)))
+                   ;
+                 /* Else as the distance vector is lexicographic positive swap
+                    the dependence direction.  */
+                 else
+                   {
+                     if (DDR_REVERSED_P (ddr))
+                       this_dir = -this_dir;
+                     this_dir = -this_dir;
+                   }
                  /* When then dependence distance of the innermost common
                     loop of the DRs is zero we have a conflict.  */
                  auto l1 = gimple_bb (DR_STMT (dr1))->loop_father;
                  auto l2 = gimple_bb (DR_STMT (dr2))->loop_father;
                  int idx = index_in_loop_nest (find_common_loop (l1, l2)->num,
                                                DDR_LOOP_NEST (ddr));
-                 if (DDR_DIST_VECT (ddr, 0)[idx] == 0)
+                 if (DDR_DIST_VECT (ddr, 0)[idx] == 0
+                     /* Unless it is the outermost loop which is the one
+                        we eventually distribute.  */
+                     && idx != 0)
                    this_dir = 2;
                }
            }
-- 
2.43.0

Reply via email to