summaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite')
-rw-r--r--gcc/testsuite/ChangeLog22
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-1.c92
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-10.c52
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-11.c29
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-12.c149
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-13.c109
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-14.c149
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-2.c73
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-3.c24
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-4.c39
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-5.c17
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-6.c31
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-7.c32
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-8.c43
-rw-r--r--gcc/testsuite/gcc.dg/loop-versioning-9.c48
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-43.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-45.c2
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_1.f9028
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_2.f9039
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_3.f9030
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_4.f9095
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_5.f9057
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_6.f9093
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_7.f9067
-rw-r--r--gcc/testsuite/gfortran.dg/loop_versioning_8.f9013
25 files changed, 1333 insertions, 2 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 42769790930..6fc2f0c9e5a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,25 @@
+2018-12-17 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.dg/loop-versioning-1.c: New test.
+ * gcc.dg/loop-versioning-10.c: Likewise.
+ * gcc.dg/loop-versioning-11.c: Likewise.
+ * gcc.dg/loop-versioning-2.c: Likewise.
+ * gcc.dg/loop-versioning-3.c: Likewise.
+ * gcc.dg/loop-versioning-4.c: Likewise.
+ * gcc.dg/loop-versioning-5.c: Likewise.
+ * gcc.dg/loop-versioning-6.c: Likewise.
+ * gcc.dg/loop-versioning-7.c: Likewise.
+ * gcc.dg/loop-versioning-8.c: Likewise.
+ * gcc.dg/loop-versioning-9.c: Likewise.
+ * gfortran.dg/loop_versioning_1.f90: Likewise.
+ * gfortran.dg/loop_versioning_2.f90: Likewise.
+ * gfortran.dg/loop_versioning_3.f90: Likewise.
+ * gfortran.dg/loop_versioning_4.f90: Likewise.
+ * gfortran.dg/loop_versioning_5.f90: Likewise.
+ * gfortran.dg/loop_versioning_6.f90: Likewise.
+ * gfortran.dg/loop_versioning_7.f90: Likewise.
+ * gfortran.dg/loop_versioning_8.f90: Likewise.
+
2018-12-16 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/88116
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-1.c b/gcc/testsuite/gcc.dg/loop-versioning-1.c
new file mode 100644
index 00000000000..e61ff7a5d10
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-1.c
@@ -0,0 +1,92 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* The simplest IV case. */
+
+void
+f1 (double *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+void
+f2 (double *x, int stepx, int limit)
+{
+ for (int i = 0; i < limit; i += stepx)
+ x[i] = 100;
+}
+
+void
+f3 (double *x, int stepx, int limit)
+{
+ for (double *y = x; y < x + limit; y += stepx)
+ *y = 100;
+}
+
+void
+f4 (double *x, int stepx, unsigned int n)
+{
+ for (unsigned int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+void
+f5 (double *x, int stepx, unsigned int limit)
+{
+ for (unsigned int i = 0; i < limit; i += stepx)
+ x[i] = 100;
+}
+
+void
+f6 (double *x, int stepx, unsigned int limit)
+{
+ for (double *y = x; y < x + limit; y += stepx)
+ *y = 100;
+}
+
+double x[10000];
+
+void
+g1 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+void
+g2 (int stepx, int limit)
+{
+ for (int i = 0; i < limit; i += stepx)
+ x[i] = 100;
+}
+
+void
+g3 (int stepx, int limit)
+{
+ for (double *y = x; y < x + limit; y += stepx)
+ *y = 100;
+}
+
+void
+g4 (int stepx, unsigned int n)
+{
+ for (unsigned int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+void
+g5 (int stepx, unsigned int limit)
+{
+ for (unsigned int i = 0; i < limit; i += stepx)
+ x[i] = 100;
+}
+
+void
+g6 (int stepx, unsigned int limit)
+{
+ for (double *y = x; y < x + limit; y += stepx)
+ *y = 100;
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 12 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 12 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-10.c b/gcc/testsuite/gcc.dg/loop-versioning-10.c
new file mode 100644
index 00000000000..f634448c253
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-10.c
@@ -0,0 +1,52 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Test that we can version a gather-like operation in which a variable
+ stride is applied to the index. */
+
+int
+f1 (int *x, int *index, int step, int n)
+{
+ int res = 0;
+ for (int i = 0; i < n; ++i)
+ res += x[index[i] * step];
+ return res;
+}
+
+int
+f2 (int *x, int *index, int step, int n)
+{
+ int res = 0;
+ for (int i = 0; i < n; ++i)
+ {
+ int *ptr = x + index[i] * step;
+ res += *ptr;
+ }
+ return res;
+}
+
+int x[1000];
+
+int
+g1 (int *index, int step, int n)
+{
+ int res = 0;
+ for (int i = 0; i < n; ++i)
+ res += x[index[i] * step];
+ return res;
+}
+
+int
+g2 (int *index, int step, int n)
+{
+ int res = 0;
+ for (int i = 0; i < n; ++i)
+ {
+ int *ptr = x + index[i] * step;
+ res += *ptr;
+ }
+ return res;
+}
+
+/* { dg-final { scan-tree-dump-times {address term [^\n]* \* loop-invariant} 4 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 4 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 4 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-11.c b/gcc/testsuite/gcc.dg/loop-versioning-11.c
new file mode 100644
index 00000000000..77ff484a4c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-11.c
@@ -0,0 +1,29 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Test that we don't try to version for something that is never 1. */
+
+void
+f1 (double *x, int stepx, int n)
+{
+ if (stepx == 1)
+ for (int i = 0; i < n; ++i)
+ x[i] = 100;
+ else
+ for (int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+void
+f2 (double *x, int stepx, int n)
+{
+ if (stepx <= 1)
+ for (int i = 0; i < n; ++i)
+ x[i] = 100;
+ else
+ for (int i = 0; i < n; ++i)
+ x[stepx * i] = 100;
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 2 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {can never be 1} 2 "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-12.c b/gcc/testsuite/gcc.dg/loop-versioning-12.c
new file mode 100644
index 00000000000..560acc4d80d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-12.c
@@ -0,0 +1,149 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Test that we don't try to version for a step of 1 when that would
+ cause the iterations to overlap. */
+
+void
+f1 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx] = 100;
+ x[i * stepx + 1] = 99;
+ }
+}
+
+void
+f2 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+f3 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx - 16] = 100;
+ x[i * stepx - 15] = 99;
+ }
+}
+
+void
+f4 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+f5 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx - 16] = 100;
+ x[i * stepx + 15] = 99;
+ }
+}
+
+void
+f6 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i - 16] = 100;
+ x[i + 15] = 99;
+ }
+}
+
+void
+f7 (unsigned short *x, int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+unsigned short x[1000];
+
+void
+g1 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx] = 100;
+ x[i * stepx + 1] = 99;
+ }
+}
+
+void
+g2 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+g3 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx - 16] = 100;
+ x[i * stepx - 15] = 99;
+ }
+}
+
+void
+g4 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+g5 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx - 16] = 100;
+ x[i * stepx + 15] = 99;
+ }
+}
+
+void
+g6 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx)
+ {
+ x[i - 16] = 100;
+ x[i + 15] = 99;
+ }
+}
+
+void
+g7 (int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-13.c b/gcc/testsuite/gcc.dg/loop-versioning-13.c
new file mode 100644
index 00000000000..c67da047fa6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-13.c
@@ -0,0 +1,109 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Test that we do version for a step of 1 when that would lead the
+ iterations to access consecutive groups. */
+
+void
+f1 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 2] = 100;
+ x[i * stepx * 2 + 1] = 99;
+ }
+}
+
+void
+f2 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 2)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+f3 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 2 - 16] = 100;
+ x[i * stepx * 2 - 15] = 99;
+ }
+}
+
+void
+f4 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 2)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+f5 (unsigned short *x, int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx * 2)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+unsigned short x[1000];
+
+void
+g1 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 2] = 100;
+ x[i * stepx * 2 + 1] = 99;
+ }
+}
+
+void
+g2 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 2)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+g3 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 2 - 16] = 100;
+ x[i * stepx * 2 - 15] = 99;
+ }
+}
+
+void
+g4 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 2)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+g5 (int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx * 2)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 10 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 10 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-14.c b/gcc/testsuite/gcc.dg/loop-versioning-14.c
new file mode 100644
index 00000000000..f2926e5650c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-14.c
@@ -0,0 +1,149 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Test that we don't try to version for a step of 1 when that would
+ cause the iterations to leave a gap between accesses. */
+
+void
+f1 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 4] = 100;
+ x[i * stepx * 4 + 1] = 99;
+ }
+}
+
+void
+f2 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 4)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+f3 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 4 - 16] = 100;
+ x[i * stepx * 4 - 15] = 99;
+ }
+}
+
+void
+f4 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 4)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+f5 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 64 - 16] = 100;
+ x[i * stepx * 64 + 15] = 99;
+ }
+}
+
+void
+f6 (unsigned short *x, int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 64)
+ {
+ x[i - 16] = 100;
+ x[i + 15] = 99;
+ }
+}
+
+void
+f7 (unsigned short *x, int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx * 4)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+unsigned short x[1000];
+
+void
+g1 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 4] = 100;
+ x[i * stepx * 4 + 1] = 99;
+ }
+}
+
+void
+g2 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 4)
+ {
+ x[i] = 100;
+ x[i + 1] = 99;
+ }
+}
+
+void
+g3 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 4 - 16] = 100;
+ x[i * stepx * 4 - 15] = 99;
+ }
+}
+
+void
+g4 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 4)
+ {
+ x[i - 16] = 100;
+ x[i - 15] = 99;
+ }
+}
+
+void
+g5 (int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[i * stepx * 64 - 16] = 100;
+ x[i * stepx * 64 + 15] = 99;
+ }
+}
+
+void
+g6 (int stepx, int n)
+{
+ for (int i = 0; i < n; i += stepx * 64)
+ {
+ x[i - 16] = 100;
+ x[i + 15] = 99;
+ }
+}
+
+void
+g7 (int stepx, int n)
+{
+ for (unsigned short *y = x; y < x + n; y += stepx * 4)
+ {
+ y[0] = 100;
+ y[1] = 99;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-2.c b/gcc/testsuite/gcc.dg/loop-versioning-2.c
new file mode 100644
index 00000000000..9416b540614
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-2.c
@@ -0,0 +1,73 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Versioning for step == 1 in these loops would allow loop interchange,
+ but otherwise isn't worthwhile. At the moment we decide not to version. */
+
+void
+f1 (double x[][100], int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step][i] = 100;
+}
+
+void
+f2 (double x[][100], int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j][i * step] = 100;
+}
+
+void
+f3 (double x[][100], int step, int limit)
+{
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < limit; j += step)
+ x[j][i] = 100;
+}
+
+void
+f4 (double x[][100], int step, int limit)
+{
+ for (int i = 0; i < limit; i += step)
+ for (int j = 0; j < 100; ++j)
+ x[j][i] = 100;
+}
+
+double x[100][100];
+
+void
+g1 (int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step][i] = 100;
+}
+
+void
+g2 (int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j][i * step] = 100;
+}
+
+void
+g3 (int step, int limit)
+{
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < limit; j += step)
+ x[j][i] = 100;
+}
+
+void
+g4 (int step, int limit)
+{
+ for (int i = 0; i < limit; i += step)
+ for (int j = 0; j < 100; ++j)
+ x[j][i] = 100;
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-3.c b/gcc/testsuite/gcc.dg/loop-versioning-3.c
new file mode 100644
index 00000000000..6565122cb1e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-3.c
@@ -0,0 +1,24 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Versioning these loops for when both steps are 1 allows loop
+ interchange, but otherwise isn't worthwhile. At the moment we decide
+ not to version. */
+
+void
+f1 (double x[][100], int step1, int step2, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step1][i * step2] = 100;
+}
+
+void
+f2 (double x[][100], int step1, int step2, int limit)
+{
+ for (int i = 0; i < limit; i += step1)
+ for (int j = 0; j < limit; j += step2)
+ x[j][i] = 100;
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-4.c b/gcc/testsuite/gcc.dg/loop-versioning-4.c
new file mode 100644
index 00000000000..0ebb2b0e86f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-4.c
@@ -0,0 +1,39 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* These shouldn't be versioned; it's extremely likely that the code
+ is emulating two-dimensional arrays. */
+
+void
+f1 (double *x, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[i * step + j] = 100;
+}
+
+void
+f2 (double *x, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step + i] = 100;
+}
+
+void
+f3 (double *x, int *offsets, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[i * step + j + offsets[i]] = 100;
+}
+
+void
+f4 (double *x, int *offsets, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step + i + offsets[i]] = 100;
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-5.c b/gcc/testsuite/gcc.dg/loop-versioning-5.c
new file mode 100644
index 00000000000..5d4cc2c3019
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-5.c
@@ -0,0 +1,17 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* There's no information about whether STEP1 or STEP2 is innermost,
+ so we should assume the code is sensible and version for the inner
+ evolution, i.e. when STEP2 is 1. */
+
+void
+f1 (double *x, int step1, int step2, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[i * step1 + j * step2] = 100;
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop for when step2} 1 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 1 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 1 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-6.c b/gcc/testsuite/gcc.dg/loop-versioning-6.c
new file mode 100644
index 00000000000..e718c233502
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-6.c
@@ -0,0 +1,31 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* The read from y in f1 will be hoisted to the outer loop. In general
+ it's not worth versioning outer loops when the inner loops don't also
+ benefit.
+
+ This test is meant to be a slight counterexample, since versioning
+ does lead to cheaper outer-loop vectorization. However, the benefit
+ isn't enough to justify the cost. */
+
+void
+f1 (double *restrict x, double *restrict y, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[i + j] = y[i * step];
+}
+
+/* A similar example in which the read can't be hoisted, but could
+ for example be handled by vectorizer alias checks. */
+
+void
+f2 (double *x, double *y, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[i + j] = y[i * step];
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-7.c b/gcc/testsuite/gcc.dg/loop-versioning-7.c
new file mode 100644
index 00000000000..ac0c2018795
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-7.c
@@ -0,0 +1,32 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Check that versioning can handle arrays of structures. */
+
+struct foo {
+ int a, b, c;
+};
+
+void
+f1 (struct foo *x, int stepx, int n)
+{
+ for (int i = 0; i < n; ++i)
+ {
+ x[stepx * i].a = 1;
+ x[stepx * i].b = 2;
+ x[stepx * i].c = 3;
+ }
+}
+
+void
+f2 (struct foo *x, int stepx, int limit)
+{
+ for (int i = 0; i < limit; i += stepx)
+ {
+ x[i].a = 1;
+ x[i].b = 2;
+ x[i].c = 3;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 2 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 2 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-8.c b/gcc/testsuite/gcc.dg/loop-versioning-8.c
new file mode 100644
index 00000000000..5645b13dc1a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-8.c
@@ -0,0 +1,43 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Versioning for step == 1 in these loops would allow loop interchange,
+ but otherwise isn't worthwhile. At the moment we decide not to version. */
+
+struct foo {
+ int a[100];
+};
+
+void
+f1 (struct foo *x, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j * step].a[i] = 100;
+}
+
+void
+f2 (struct foo *x, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ for (int j = 0; j < n; ++j)
+ x[j].a[i * step] = 100;
+}
+
+void
+f3 (struct foo *x, int step, int limit)
+{
+ for (int i = 0; i < 100; ++i)
+ for (int j = 0; j < limit; j += step)
+ x[j].a[i] = 100;
+}
+
+void
+f4 (struct foo *x, int step, int limit)
+{
+ for (int i = 0; i < limit; i += step)
+ for (int j = 0; j < 100; ++j)
+ x[j].a[i] = 100;
+}
+
+/* { dg-final { scan-tree-dump-not {want to version} "lversion" } } */
+/* { dg-final { scan-tree-dump-not {versioned} "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/loop-versioning-9.c b/gcc/testsuite/gcc.dg/loop-versioning-9.c
new file mode 100644
index 00000000000..cfbcd821b22
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/loop-versioning-9.c
@@ -0,0 +1,48 @@
+/* { dg-options "-O3 -fdump-tree-lversion-details" } */
+
+/* Check that versioning can handle small groups of accesses. */
+
+void
+f1 (int *x, int *y, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 2] + y[i * step * 2 + 1];
+}
+
+void
+f2 (int *x, int *y, __INTPTR_TYPE__ step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 2] + y[i * step * 2 + 1];
+}
+
+void
+f3 (int *x, int *y, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 3] + y[i * step * 3 + 2];
+}
+
+void
+f4 (int *x, int *y, __INTPTR_TYPE__ step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 3] + y[i * step * 3 + 2];
+}
+
+void
+f5 (int *x, int *y, int step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 4] + y[i * step * 4 + 3];
+}
+
+void
+f6 (int *x, int *y, __INTPTR_TYPE__ step, int n)
+{
+ for (int i = 0; i < n; ++i)
+ x[i] = y[i * step * 4] + y[i * step * 4 + 3];
+}
+
+/* { dg-final { scan-tree-dump-times {want to version containing loop} 6 "lversion" } } */
+/* { dg-final { scan-tree-dump-times {versioned this loop} 6 "lversion" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/slp-43.c b/gcc/testsuite/gcc.dg/vect/slp-43.c
index 880a2961ae1..0344cc98625 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-43.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-43.c
@@ -1,5 +1,5 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-additional-options "-O3" } */
+/* { dg-additional-options "-O3 -fno-version-loops-for-strides" } */
#include <string.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/slp-45.c b/gcc/testsuite/gcc.dg/vect/slp-45.c
index 20a9f815292..d83472ca095 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-45.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-45.c
@@ -1,5 +1,5 @@
/* { dg-require-effective-target vect_int } */
-/* { dg-additional-options "-O3" } */
+/* { dg-additional-options "-O3 -fno-version-loops-for-strides" } */
#include <string.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_1.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_1.f90
new file mode 100644
index 00000000000..e80f8920d00
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_1.f90
@@ -0,0 +1,28 @@
+! { dg-options "-O3 -fdump-tree-lversion-details" }
+
+! The simplest IV case.
+
+subroutine f1(x)
+ real :: x(:)
+ x(:) = 100
+end subroutine f1
+
+subroutine f2(x, n, step)
+ integer :: n, step
+ real :: x(n * step)
+ do i = 1, n
+ x(i * step) = 100
+ end do
+end subroutine f2
+
+subroutine f3(x, limit, step)
+ integer :: limit, step
+ real :: x(limit)
+ do i = 1, limit, step
+ x(i) = 100
+ end do
+end subroutine f3
+
+! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 1 "lversion" } }
+! { dg-final { scan-tree-dump-times {want to version containing loop} 3 "lversion" } }
+! { dg-final { scan-tree-dump-times {versioned this loop} 3 "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_2.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_2.f90
new file mode 100644
index 00000000000..522ef912947
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_2.f90
@@ -0,0 +1,39 @@
+! { dg-options "-O3 -fdump-tree-lversion-details -fno-frontend-loop-interchange" }
+
+! We could version the loop for when the first dimension has a stride
+! of 1, but at present there's no real benefit. The gimple loop
+! interchange pass couldn't handle the versioned loop, and interchange
+! is instead done by the frontend (but disabled by the options above).
+
+subroutine f1(x)
+ real :: x(:, :)
+ do i = lbound(x, 1), ubound(x, 1)
+ do j = lbound(x, 2), ubound(x, 2)
+ x(i, j) = 100
+ end do
+ end do
+end subroutine f1
+
+subroutine f2(x, n, step)
+ integer :: n, step
+ real :: x(100, 100)
+ do i = 1, n
+ do j = 1, n
+ x(i * step, j) = 100
+ end do
+ end do
+end subroutine f2
+
+subroutine f3(x, n, step)
+ integer :: n, step
+ real :: x(n * step, n)
+ do i = 1, n
+ do j = 1, n
+ x(i * step, j) = 100
+ end do
+ end do
+end subroutine f3
+
+! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 1 "lversion" } }
+! { dg-final { scan-tree-dump-not {want to version} "lversion" } }
+! { dg-final { scan-tree-dump-not {versioned} "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_3.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_3.f90
new file mode 100644
index 00000000000..040b30b5148
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_3.f90
@@ -0,0 +1,30 @@
+! { dg-options "-O3 -fdump-tree-lversion-details -fno-frontend-loop-interchange" }
+
+! Test a case in which the outer loop iterates over the inner dimension.
+! The options above prevent the frontend from interchanging the loops.
+
+subroutine f1(x, limit, step, n)
+ integer :: limit, step, n
+ real :: x(limit, n)
+ do i = 1, limit, step
+ do j = 1, n
+ x(i, j) = 100
+ end do
+ end do
+end subroutine f1
+
+subroutine f2(x, n, limit, step)
+ integer :: n, limit, step
+ real :: x(limit, n)
+ do i = 1, n
+ do j = 1, limit, step
+ x(j, i) = 100
+ end do
+ end do
+end subroutine f2
+
+! FIXME: The frontend doesn't give us enough information to tell which loop
+! is iterating over the innermost dimension, so we optimistically
+! assume the inner one is.
+! { dg-final { scan-tree-dump-not {want to version} "lversion" { xfail *-*-* } } }
+! { dg-final { scan-tree-dump-not {versioned} "lversion" { xfail *-*-* } } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_4.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_4.f90
new file mode 100644
index 00000000000..2fc4d12c9d1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_4.f90
@@ -0,0 +1,95 @@
+! { dg-options "-O3 -fdump-tree-lversion-details -fno-frontend-loop-interchange" }
+
+! Test cases in which versioning is useful for a two-dimensional array.
+
+subroutine f1(x)
+ real :: x(:, :)
+ x(:, :) = 100
+end subroutine f1
+
+subroutine f2(x)
+ real :: x(:, :)
+ do i = lbound(x, 1), ubound(x, 1)
+ do j = lbound(x, 2), ubound(x, 2)
+ x(j, i) = 100
+ end do
+ end do
+end subroutine f2
+
+subroutine f3(x, n, step)
+ integer :: n, step
+ real :: x(100, 100)
+ do i = 1, n
+ do j = 1, n
+ x(j * step, i) = 100
+ end do
+ end do
+end subroutine f3
+
+subroutine f4(x, n, step)
+ integer :: n, step
+ real :: x(n * step, n)
+ do i = 1, n
+ do j = 1, n
+ x(j * step, i) = 100
+ end do
+ end do
+end subroutine f4
+
+subroutine f5(x, n, limit, step)
+ integer :: n, limit, step
+ real :: x(limit, n)
+ do i = 1, n
+ do j = 1, limit, step
+ x(j, i) = 100
+ end do
+ end do
+end subroutine f5
+
+subroutine f6(x, y)
+ real :: x(:, :), y(:)
+ do i = lbound(x, 1), ubound(x, 1)
+ do j = lbound(x, 2), ubound(x, 2)
+ x(j, i) = 100
+ end do
+ y(i) = 200
+ end do
+end subroutine f6
+
+subroutine f7(x, y, n, step)
+ integer :: n, step
+ real :: x(100, 100), y(100)
+ do i = 1, n
+ do j = 1, n
+ x(j * step, i) = 100
+ end do
+ y(i * step) = 200
+ end do
+end subroutine f7
+
+subroutine f8(x, y, n, step)
+ integer :: n, step
+ real :: x(n * step, n), y(n * step)
+ do i = 1, n
+ do j = 1, n
+ x(j * step, i) = 100
+ end do
+ y(i * step) = 200
+ end do
+end subroutine f8
+
+subroutine f9(x, n, limit, step)
+ integer :: n, limit, step
+ real :: x(limit, n), y(limit)
+ do i = 1, n
+ do j = 1, limit, step
+ x(j, i) = 100
+ end do
+ y(i) = 200
+ end do
+end subroutine f9
+
+! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 3 "lversion" } }
+! { dg-final { scan-tree-dump-times {want to version containing loop} 9 "lversion" } }
+! { dg-final { scan-tree-dump-times {hoisting check} 9 "lversion" } }
+! { dg-final { scan-tree-dump-times {versioned this loop} 9 "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_5.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_5.f90
new file mode 100644
index 00000000000..b08c7163382
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_5.f90
@@ -0,0 +1,57 @@
+! { dg-options "-O3 -fdump-tree-lversion-details -fno-frontend-loop-interchange" }
+
+! Make sure that in a "badly nested" loop, we don't treat the inner loop
+! as iterating over the inner dimension with a variable stride.
+
+subroutine f1(x, n)
+ integer :: n
+ real :: x(100, 100)
+ do i = 1, n
+ do j = 1, n
+ x(i, j) = 100
+ end do
+ end do
+end subroutine f1
+
+subroutine f2(x, n, step)
+ integer :: n, step
+ real :: x(100, 100)
+ do i = 1, n
+ do j = 1, n
+ x(i, j * step) = 100
+ end do
+ end do
+end subroutine f2
+
+subroutine f3(x, n)
+ integer :: n
+ real :: x(n, n)
+ do i = 1, n
+ do j = 1, n
+ x(i, j) = 100
+ end do
+ end do
+end subroutine f3
+
+subroutine f4(x, n, step)
+ integer :: n, step
+ real :: x(n, n * step)
+ do i = 1, n
+ do j = 1, n
+ x(i, j * step) = 100
+ end do
+ end do
+end subroutine f4
+
+subroutine f5(x, n, limit, step)
+ integer :: n, limit, step
+ real :: x(n, limit)
+ do i = 1, n
+ do j = 1, limit, step
+ x(i, j) = 100
+ end do
+ end do
+end subroutine f5
+
+! { dg-final { scan-tree-dump-not {want to version} "lversion" } }
+! { dg-final { scan-tree-dump-not {versioned} "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_6.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_6.f90
new file mode 100644
index 00000000000..450a79c1fdf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_6.f90
@@ -0,0 +1,93 @@
+! { dg-options "-O3 -fdump-tree-lversion-details" }
+
+! Check that versioning can handle small groups of accesses.
+
+subroutine f1(x)
+ real :: x(:)
+ do i = lbound(x, 1), ubound(x, 1) / 2
+ x(i * 2) = 100
+ x(i * 2 + 1) = 101
+ end do
+end subroutine f1
+
+subroutine f2(x, n, step)
+ integer :: n, step
+ real :: x(n * step * 2)
+ do i = 1, n
+ x(i * step * 2) = 100
+ x(i * step * 2 + 1) = 101
+ end do
+end subroutine f2
+
+subroutine f3(x, limit, step)
+ integer :: limit, step
+ real :: x(limit * 2)
+ do i = 1, limit, step
+ x(i * 2) = 100
+ x(i * 2 + 1) = 101
+ end do
+end subroutine f3
+
+subroutine f4(x)
+ real :: x(:)
+ do i = lbound(x, 1), ubound(x, 1) / 3
+ x(i * 3) = 100
+ x(i * 3 + 1) = 101
+ x(i * 3 + 2) = 102
+ end do
+end subroutine f4
+
+subroutine f5(x, n, step)
+ integer :: n, step
+ real :: x(n * step * 3)
+ do i = 1, n
+ x(i * step * 3) = 100
+ x(i * step * 3 + 1) = 101
+ x(i * step * 3 + 2) = 102
+ end do
+end subroutine f5
+
+subroutine f6(x, limit, step)
+ integer :: limit, step
+ real :: x(limit * 3)
+ do i = 1, limit, step
+ x(i * 3) = 100
+ x(i * 3 + 1) = 101
+ x(i * 3 + 2) = 102
+ end do
+end subroutine f6
+
+subroutine f7(x)
+ real :: x(:)
+ do i = lbound(x, 1), ubound(x, 1) / 4
+ x(i * 4) = 100
+ x(i * 4 + 1) = 101
+ x(i * 4 + 2) = 102
+ x(i * 4 + 3) = 103
+ end do
+end subroutine f7
+
+subroutine f8(x, n, step)
+ integer :: n, step
+ real :: x(n * step * 4)
+ do i = 1, n
+ x(i * step * 4) = 100
+ x(i * step * 4 + 1) = 101
+ x(i * step * 4 + 2) = 102
+ x(i * step * 4 + 3) = 103
+ end do
+end subroutine f8
+
+subroutine f9(x, limit, step)
+ integer :: limit, step
+ real :: x(limit * 4)
+ do i = 1, limit, step
+ x(i * 4) = 100
+ x(i * 4 + 1) = 101
+ x(i * 4 + 2) = 102
+ x(i * 4 + 3) = 103
+ end do
+end subroutine f9
+
+! { dg-final { scan-tree-dump-times {want to version containing loop} 9 "lversion" } }
+! { dg-final { scan-tree-dump-times {versioned this loop} 9 "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_7.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_7.f90
new file mode 100644
index 00000000000..ba827ac3184
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_7.f90
@@ -0,0 +1,67 @@
+! { dg-options "-O3 -fdump-tree-lversion-details" }
+
+! Check that versioning can handle small groups of accesses, with the
+! group being a separate array dimension.
+
+subroutine f1(x, n, step)
+ integer :: n, step
+ real :: x(2, n * step)
+ do i = 1, n
+ x(1, i * step) = 100
+ x(2, i * step) = 101
+ end do
+end subroutine f1
+
+subroutine f2(x, limit, step)
+ integer :: limit, step
+ real :: x(2, limit)
+ do i = 1, limit, step
+ x(1, i) = 100
+ x(2, i) = 101
+ end do
+end subroutine f2
+
+subroutine f3(x, n, step)
+ integer :: n, step
+ real :: x(3, n * step)
+ do i = 1, n
+ x(1, i * step) = 100
+ x(2, i * step) = 101
+ x(3, i * step) = 102
+ end do
+end subroutine f3
+
+subroutine f4(x, limit, step)
+ integer :: limit, step
+ real :: x(3, limit)
+ do i = 1, limit, step
+ x(1, i) = 100
+ x(2, i) = 101
+ x(3, i) = 102
+ end do
+end subroutine f4
+
+subroutine f5(x, n, step)
+ integer :: n, step
+ real :: x(4, n * step)
+ do i = 1, n
+ x(1, i * step) = 100
+ x(2, i * step) = 101
+ x(3, i * step) = 102
+ x(4, i * step) = 103
+ end do
+end subroutine f5
+
+subroutine f6(x, limit, step)
+ integer :: limit, step
+ real :: x(4, limit)
+ do i = 1, limit, step
+ x(1, i) = 100
+ x(2, i) = 101
+ x(3, i) = 102
+ x(4, i) = 103
+ end do
+end subroutine f6
+
+! { dg-final { scan-tree-dump-times {want to version containing loop} 6 "lversion" } }
+! { dg-final { scan-tree-dump-times {versioned this loop} 6 "lversion" } }
diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_8.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_8.f90
new file mode 100644
index 00000000000..193479935f4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/loop_versioning_8.f90
@@ -0,0 +1,13 @@
+! { dg-options "-O3 -fdump-tree-lversion-details" }
+
+! Check that versioning is applied to a gather-like reduction operation.
+
+function f(x, index, n)
+ integer :: n
+ real :: x(:)
+ integer :: index(n)
+ f = sum(x(index(:)))
+end function f
+
+! { dg-final { scan-tree-dump-times {want to version containing loop} 1 "lversion" } }
+! { dg-final { scan-tree-dump-times {versioned this loop} 1 "lversion" } }