diff options
Diffstat (limited to 'gcc/testsuite')
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" } } |