From: Sandra Loosemore <sandra@codesourcery.com>
To: <gcc-patches@gcc.gnu.org>
Cc: <jakub@redhat.com>, <tobias@codesourcery.com>
Subject: [COMMITTED V3 4/6] OpenMP: New C/C++ testcases for imperfectly nested loops.
Date: Fri, 25 Aug 2023 13:47:12 -0600 [thread overview]
Message-ID: <20230825194714.627157-5-sandra@codesourcery.com> (raw)
In-Reply-To: <20230825194714.627157-1-sandra@codesourcery.com>
gcc/testsuite/ChangeLog
* c-c++-common/gomp/imperfect-attributes.c: New.
* c-c++-common/gomp/imperfect-badloops.c: New.
* c-c++-common/gomp/imperfect-blocks.c: New.
* c-c++-common/gomp/imperfect-extension.c: New.
* c-c++-common/gomp/imperfect-gotos.c: New.
* c-c++-common/gomp/imperfect-invalid-scope.c: New.
* c-c++-common/gomp/imperfect-labels.c: New.
* c-c++-common/gomp/imperfect-legacy-syntax.c: New.
* c-c++-common/gomp/imperfect-pragmas.c: New.
* c-c++-common/gomp/imperfect1.c: New.
* c-c++-common/gomp/imperfect2.c: New.
* c-c++-common/gomp/imperfect3.c: New.
* c-c++-common/gomp/imperfect4.c: New.
* c-c++-common/gomp/imperfect5.c: New.
libgomp/ChangeLog
* testsuite/libgomp.c-c++-common/imperfect1.c: New.
* testsuite/libgomp.c-c++-common/imperfect2.c: New.
* testsuite/libgomp.c-c++-common/imperfect3.c: New.
* testsuite/libgomp.c-c++-common/imperfect4.c: New.
* testsuite/libgomp.c-c++-common/imperfect5.c: New.
* testsuite/libgomp.c-c++-common/imperfect6.c: New.
* testsuite/libgomp.c-c++-common/target-imperfect1.c: New.
* testsuite/libgomp.c-c++-common/target-imperfect2.c: New.
* testsuite/libgomp.c-c++-common/target-imperfect3.c: New.
* testsuite/libgomp.c-c++-common/target-imperfect4.c: New.
---
.../c-c++-common/gomp/imperfect-attributes.c | 81 ++++++++
.../c-c++-common/gomp/imperfect-badloops.c | 50 +++++
.../c-c++-common/gomp/imperfect-blocks.c | 75 ++++++++
.../c-c++-common/gomp/imperfect-extension.c | 55 ++++++
.../c-c++-common/gomp/imperfect-gotos.c | 174 ++++++++++++++++++
.../gomp/imperfect-invalid-scope.c | 77 ++++++++
.../c-c++-common/gomp/imperfect-labels.c | 85 +++++++++
.../gomp/imperfect-legacy-syntax.c | 44 +++++
.../c-c++-common/gomp/imperfect-pragmas.c | 85 +++++++++
gcc/testsuite/c-c++-common/gomp/imperfect1.c | 38 ++++
gcc/testsuite/c-c++-common/gomp/imperfect2.c | 34 ++++
gcc/testsuite/c-c++-common/gomp/imperfect3.c | 52 ++++++
gcc/testsuite/c-c++-common/gomp/imperfect4.c | 33 ++++
gcc/testsuite/c-c++-common/gomp/imperfect5.c | 95 ++++++++++
.../libgomp.c-c++-common/imperfect1.c | 76 ++++++++
.../libgomp.c-c++-common/imperfect2.c | 114 ++++++++++++
.../libgomp.c-c++-common/imperfect3.c | 119 ++++++++++++
.../libgomp.c-c++-common/imperfect4.c | 117 ++++++++++++
.../libgomp.c-c++-common/imperfect5.c | 49 +++++
.../libgomp.c-c++-common/imperfect6.c | 115 ++++++++++++
.../libgomp.c-c++-common/target-imperfect1.c | 81 ++++++++
.../libgomp.c-c++-common/target-imperfect2.c | 122 ++++++++++++
.../libgomp.c-c++-common/target-imperfect3.c | 125 +++++++++++++
.../libgomp.c-c++-common/target-imperfect4.c | 122 ++++++++++++
24 files changed, 2018 insertions(+)
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-extension.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-labels.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect1.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect2.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect3.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect4.c
create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect5.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect1.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect2.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect3.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect4.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect5.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect6.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c
new file mode 100644
index 00000000000..776295ce22a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c
@@ -0,0 +1,81 @@
+/* { dg-do compile { target { c || c++11 } } } */
+
+/* Check that a nested FOR loop with standard c/c++ attributes on it
+ is treated as intervening code, since it doesn't match the grammar
+ for canonical loop nest form. */
+
+extern void do_something (void);
+
+void imperfect1 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+ [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+void perfect1 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+ [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+/* Similar, but put the attributes on a block wrapping the nested loop
+ instead. */
+
+void imperfect2 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+ [[]]
+ {
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+ }
+}
+
+void perfect2 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+ [[]]
+ {
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+ }
+}
+
+/* Make sure attributes are accepted in the innermost loop body, which has
+ no intervening code restrictions. */
+
+void imperfect3 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ [[]] do_something ();
+ }
+}
+
+void perfect3 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ [[]] do_something ();
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c
new file mode 100644
index 00000000000..dfd40b6cb2d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+int f1 (int depth, int iter);
+int f2 (int depth, int iter);
+void do_something (void);
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ if (a1 < a2)
+ {
+ int z = 0;
+ while (z < i) /* { dg-error "loop not permitted in intervening code " } */
+ {
+ do_something ();
+ z++;
+ }
+ do /* { dg-error "loop not permitted in intervening code " } */
+ {
+ do_something ();
+ z--;
+ } while (z >= 0);
+ }
+ for (j = 0; j < a2; j++)
+ {
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ if (a1 < a3)
+ {
+ int z;
+ for (z = 0; z < i; z++) /* { dg-error "loop not permitted in intervening code " } */
+ {
+ do_something ();
+ }
+ }
+ f2 (0, i);
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c
new file mode 100644
index 00000000000..0fea58faf78
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c
@@ -0,0 +1,75 @@
+/* { dg-do compile } */
+
+/* Check that compound statements in intervening code are correctly
+ handled. */
+
+extern void do_something (void);
+
+void imperfect1 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ {
+ {}
+ for (int j = 0; j < y; j++)
+ do_something ();
+ }
+}
+
+void perfect1 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ {}
+ for (int j = 0; j < y; j++)
+ do_something ();
+ }
+}
+
+void imperfect2 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ {
+ for (int j = 0; j < y; j++)
+ do_something ();
+ {}
+ }
+}
+
+void perfect2 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ for (int j = 0; j < y; j++)
+ do_something ();
+ {}
+ }
+}
+
+void imperfect3 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ {
+ { do_something (); }
+ for (int j = 0; j < y; j++)
+ do_something ();
+ { do_something (); }
+ }
+}
+
+void perfect3 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ { do_something (); }
+ for (int j = 0; j < y; j++)
+ do_something ();
+ { do_something (); }
+ }
+}
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c
new file mode 100644
index 00000000000..a8a8f9ebe1d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+
+/* Check that __extension__ introduces intervening code. */
+
+extern void do_something (void);
+
+void imperfect1 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+ __extension__ ({
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ });
+ }
+}
+
+void perfect1 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+ __extension__ ({
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ });
+ }
+}
+
+/* Check that we don't barf on __extension__ in the inner loop body. */
+void imperfect2 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ __extension__ ({
+ do_something ();
+ });
+ }
+}
+
+void perfect2 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ __extension__ ({
+ do_something ();
+ });
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c
new file mode 100644
index 00000000000..897eed275ec
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c
@@ -0,0 +1,174 @@
+/* { dg-do compile } */
+
+/* This file contains tests that are expected to fail. */
+
+
+/* These jumps are all OK since they are to/from the same structured block. */
+
+void f1a (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump around loop body to/from different structured blocks of intervening
+ code. */
+void f2a (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ goto a; a:;
+ if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump into loop body from intervening code. */
+void f3a (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ goto a; a:;
+ if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ for (int j = 0; j < 64; ++j)
+ {
+ c:
+ ;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump out of loop body to intervening code. */
+void f4a (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ c:
+ ;
+ goto b; b:;
+ }
+}
+
+/* The next group of tests use the GNU extension for local labels. Expected
+ behavior is the same as the above group. */
+
+/* These jumps are all OK since they are to/from the same structured block. */
+
+void f1b (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ __label__ a, b, c;
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump around loop body to/from different structured blocks of intervening
+ code. */
+void f2b (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ __label__ a, b, c;
+ goto a; a:;
+ if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump into loop body from intervening code. */
+void f3b (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ __label__ a, b, c;
+ goto a; a:;
+ if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ for (int j = 0; j < 64; ++j)
+ {
+ c:
+ ;
+ }
+ goto b; b:;
+ }
+}
+
+/* Jump out of loop body to intervening code. */
+void f4b (void)
+{
+#pragma omp for collapse(2)
+ for (int i = 0; i < 64; ++i)
+ {
+ __label__ a, b, c;
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */
+ c:
+ ;
+ goto b; b:;
+ }
+}
+
+/* Test that the even the valid jumps are rejected when intervening code
+ is not allowed at all. */
+
+void f1c (void)
+{
+#pragma omp for ordered(2)
+ for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
+void f1d (void)
+{
+#pragma omp for ordered(2)
+ for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ __label__ a, b, c;
+ goto a; a:;
+ for (int j = 0; j < 64; ++j)
+ {
+ goto c; c:;
+ }
+ goto b; b:;
+ }
+}
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c
new file mode 100644
index 00000000000..5c24aae07cc
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c
@@ -0,0 +1,77 @@
+/* { dg-do compile } */
+
+/* Check that various cases of invalid references to variables bound
+ in an intervening code scope are diagnosed and do not ICE. This test
+ is expected to produce errors. */
+
+extern void foo (int, int);
+
+void f1 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int v = (i + 4) * 2;
+ for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */
+ foo (i, j);
+ }
+}
+
+void f2 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int v = (i + 4) * 2;
+ for (int j = 0; j < v; j++) /* { dg-error "end test is bound in intervening code" } */
+ foo (i, j);
+ }
+}
+
+void f3 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int v = (i + 4) * 2;
+ for (int j = 0; j < 64; j = j + v) /* { dg-error "increment expression is bound in intervening code" } */
+ foo (i, j);
+ }
+}
+
+void f4 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int v = 8;
+ for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */
+ foo (i, j);
+ }
+}
+
+void f5 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int j;
+ for (j = 0; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */
+ foo (i, j);
+ }
+}
+
+void f6 (void)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < 64; i++)
+ {
+ int j;
+ {
+ int v = 8;
+ for (j = v; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */
+ /* { dg-error "initializer is bound in intervening code" "" { target *-*-* } .-1 } */
+ foo (i, j);
+ }
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c
new file mode 100644
index 00000000000..b7a7a4c8358
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+
+/* Check that a nested FOR loop with a label on it is treated as
+ intervening code, since it doesn't match the grammar for canonical
+ loop nest form. */
+
+extern void do_something (void);
+
+void imperfect1 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+ foo:
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+void perfect1 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+ foo:
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+
+/* Similar, but put the label on a block wrapping the nested loop instead. */
+
+void imperfect2 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+ foo:
+ {
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+ }
+}
+
+void perfect2 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+ foo:
+ {
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+ }
+}
+
+/* Sanity check that labels are allowed in the innermost loop body. */
+
+void imperfect3 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ foo:
+ do_something ();
+ }
+}
+
+void perfect3 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+ foo:
+ do_something ();
+ }
+}
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c
new file mode 100644
index 00000000000..571e067091b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+
+/* Braces may enclose a nested FOR even when intervening code is not
+ permitted. Before GCC implemented OpenMP 5.1 canonical loop syntax
+ and support for intervening code, it used to ignore empty statements
+ instead of treating them as intervening code; as an extension, those
+ are still accepted without complaint even in constructs where intervening
+ code is not supposed to be valid. */
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for ordered(3)
+ for (i = 0; i < a1; i++)
+ {
+ for (j = 0; j < a2; j++)
+ {
+ for (k = 0; k < a3; k++)
+ {
+ }
+ }
+ }
+}
+
+void s2 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for ordered(3)
+ for (i = 0; i < a1; i++)
+ {
+ ;
+ for (j = 0; j < a2; j++)
+ {
+ ;
+ for (k = 0; k < a3; k++)
+ {
+ }
+ ;
+ }
+ ;
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c
new file mode 100644
index 00000000000..a9f55224158
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+
+/* Check that non-statement pragmas are accepted in a canonical loop nest
+ even when perfect nesting is required. */
+
+extern void do_something (void);
+
+void imperfect1 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ {
+#pragma GCC diagnostic push
+ for (int j = 0; j < y; j++)
+ do_something ();
+#pragma GCC diagnostic pop
+ }
+}
+
+void perfect1 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++)
+ {
+#pragma GCC diagnostic push
+ for (int j = 0; j < y; j++)
+ do_something ();
+#pragma GCC diagnostic pop
+ }
+}
+
+
+/* "GCC unroll" is a statement pragma that consumes the following loop as
+ a substatement. Thus, the inner loop should be treated as intervening
+ code rather than part of the loop nest. */
+
+void imperfect2 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ {
+#pragma GCC unroll 4
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+void perfect2 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */
+ /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */
+ {
+#pragma GCC unroll 4
+ for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */
+ do_something ();
+ }
+}
+
+
+/* Check that statement pragmas are accepted in the innermost loop body. */
+
+void imperfect3 (int x, int y)
+{
+#pragma omp for collapse (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+#pragma GCC unroll 4
+ for (int k = 0; k < 4; k++)
+ do_something ();
+ }
+}
+
+void perfect3 (int x, int y)
+{
+#pragma omp for ordered (2)
+ for (int i = 0; i < x; i++)
+ for (int j = 0; j < y; j++)
+ {
+#pragma GCC unroll 4
+ for (int k = 0; k < 4; k++)
+ do_something ();
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect1.c b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
new file mode 100644
index 00000000000..705626ad169
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+int f1 (int depth, int iter);
+int f2 (int depth, int iter);
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */
+ f1 (1, j);
+ if (i == 2)
+ continue; /* { dg-error "invalid exit" } */
+ else
+ break; /* { dg-error "invalid exit" } */
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ for (k = 0; k < a3; k++) /* { dg-error "loop not permitted in intervening code " } */
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (0, i);
+ }
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect2.c b/gcc/testsuite/c-c++-common/gomp/imperfect2.c
new file mode 100644
index 00000000000..dff17dd3ca5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect2.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+/* These functions that are part of the OpenMP runtime API would ordinarily
+ be declared in omp.h, but we don't have that here. */
+extern int omp_get_num_threads(void);
+extern int omp_get_max_threads(void);
+
+int f1 (int depth, int iter);
+int f2 (int depth, int iter);
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < omp_get_num_threads (); j++) /* This is OK */
+ {
+ f1 (1, omp_get_num_threads ()); /* { dg-error "not permitted in intervening code" } */
+ for (k = omp_get_num_threads (); k < a3; k++) /* This is OK */
+ {
+ f1 (2, omp_get_num_threads ());
+ f2 (2, omp_get_max_threads ());
+ }
+ f2 (1, omp_get_max_threads ()); /* { dg-error "not permitted in intervening code" } */
+ }
+ f2 (0, i);
+ }
+}
+
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect3.c b/gcc/testsuite/c-c++-common/gomp/imperfect3.c
new file mode 100644
index 00000000000..b2b46c1993e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect3.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+/* Test that the imperfectly-nested loops with the ordered clause gives
+ an error, and that there is only one error (and not one on every
+ intervening statement). */
+
+int f1 (int depth, int iter);
+int f2 (int depth, int iter);
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+ /* This loop without intervening code ought to be OK. */
+#pragma omp for ordered(3)
+ for (i = 0; i < a1; i++)
+ {
+ for (j = 0; j < a2; j++)
+ {
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+#pragma omp ordered doacross(source:omp_cur_iteration)
+#pragma omp ordered doacross(sink: i - 2, j + 2, k - 1)
+ }
+ }
+ }
+
+ /* Now add intervening code. */
+#pragma omp for ordered(3)
+ for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+#pragma omp ordered doacross(source:omp_cur_iteration)
+#pragma omp ordered doacross(sink: i - 2, j + 2, k - 1)
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect4.c b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
new file mode 100644
index 00000000000..1a0c07cd48e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+int f1 (int depth, int iter);
+int f2 (int depth, int iter);
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(4)
+ for (i = 0; i < a1; i++) /* { dg-error "not enough nested loops" } */
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ /* According to the grammar, this is intervening code; we
+ don't know that we are also missing a nested for loop
+ until we have parsed this whole compound expression. */
+#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect5.c b/gcc/testsuite/c-c++-common/gomp/imperfect5.c
new file mode 100644
index 00000000000..da92578ed25
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect5.c
@@ -0,0 +1,95 @@
+/* { dg-do compile } */
+
+/* This test case is expected to fail due to errors. */
+
+#define N 30
+#define M 3
+
+int a[N][M], b[N][M], c[N][M];
+
+extern void dostuff (int, int);
+
+/* good1 and good2 should compile without error. */
+void
+good1 (void)
+{
+ int x, shift;
+
+ x = 0;
+ #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift)
+ for (int i = 0; i < N; i++)
+ {
+ for (int j = 0; j < M; j++)
+ {
+ x += a[i][j];
+ x += b[i][j];
+#pragma omp scan inclusive(x)
+ shift = i + 29*j;
+ c[i][j] = x + shift;
+ }
+ }
+}
+
+void
+good2 (void)
+{
+ int x, shift;
+ x = 0;
+
+ #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift)
+ for (int i = 0; i < N; i++)
+ {
+ for (int j = 0; j < M; j++)
+ {
+ shift = i + 29*j;
+ c[i][j] = x + shift;
+#pragma omp scan exclusive(x)
+ x += a[i][j];
+ x += b[i][j];
+ }
+ }
+}
+
+/* Adding intervening code should trigger an error. */
+
+void
+bad1 (void)
+{
+ int x, shift;
+
+ x = 0;
+ #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift)
+ for (int i = 0; i < N; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ dostuff (i, 0);
+ for (int j = 0; j < M; j++)
+ {
+ x += a[i][j];
+ x += b[i][j];
+#pragma omp scan inclusive(x)
+ shift = i + 29*j;
+ c[i][j] = x + shift;
+ }
+ }
+}
+
+void
+bad2 (void)
+{
+ int x, shift;
+ x = 0;
+
+ #pragma omp parallel for simd collapse(2) reduction(inscan,+: x) private(shift)
+ for (int i = 0; i < N; i++) /* { dg-error "inner loops must be perfectly nested" } */
+ {
+ for (int j = 0; j < M; j++)
+ {
+ shift = i + 29*j;
+ c[i][j] = x + shift;
+#pragma omp scan exclusive(x)
+ x += a[i][j];
+ x += b[i][j];
+ }
+ dostuff (i, 1);
+ }
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c
new file mode 100644
index 00000000000..cafdcaf25b0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c
@@ -0,0 +1,76 @@
+/* { dg-do run } */
+
+static int f1count[3], f2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c
new file mode 100644
index 00000000000..e2098006eab
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c
@@ -0,0 +1,114 @@
+/* { dg-do run } */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ {
+ g1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ {
+ g1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ {
+ g1 (2, k);
+ g2 (2, k);
+ }
+ f2 (2, k);
+ }
+ g2 (1, j);
+ }
+ f2 (1, j);
+ }
+ g2 (0, i);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c
new file mode 100644
index 00000000000..feb5e32d1d6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c
@@ -0,0 +1,119 @@
+/* { dg-do run } */
+
+/* Like imperfect2.c, but includes bindings in the blocks. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ int local0 = 0;
+ f1 (local0, i);
+ {
+ g1 (local0, i);
+ for (j = 0; j < a2; j++)
+ {
+ int local1 = 1;
+ f1 (local1, j);
+ {
+ g1 (local1, j);
+ for (k = 0; k < a3; k++)
+ {
+ int local2 = 2;
+ f1 (local2, k);
+ {
+ g1 (local2, k);
+ g2 (local2, k);
+ }
+ f2 (local2, k);
+ }
+ g2 (local1, j);
+ }
+ f2 (local1, j);
+ }
+ g2 (local0, i);
+ }
+ f2 (local0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c
new file mode 100644
index 00000000000..e29301bfbad
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c
@@ -0,0 +1,117 @@
+/* { dg-do run } */
+
+/* Like imperfect2.c, but includes blocks that are themselves intervening
+ code. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp for collapse(3)
+ for (i = 0; i < a1; i++)
+ {
+ { f1 (0, i); }
+ {
+ g1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ { f1 (1, j); }
+ {
+ { g1 (1, j); }
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ {
+ g1 (2, k);
+ g2 (2, k);
+ }
+ f2 (2, k);
+ }
+ { g2 (1, j); }
+ }
+ { f2 (1, j); }
+ }
+ { g2 (0, i); }
+ }
+ { f2 (0, i); }
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c
new file mode 100644
index 00000000000..7bd4f12d472
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+static int inner_loop_count = 0;
+static int intervening_code_count = 0;
+
+void
+g (int x, int y)
+{
+ inner_loop_count++;
+}
+
+int
+foo (int imax, int jmax)
+{
+ int j = 0;
+
+#pragma omp for collapse(2)
+ for (int i = 0; i < imax; ++i)
+ {
+ /* All the intervening code at the same level must be executed
+ the same number of times. */
+ ++intervening_code_count;
+ for (int j = 0; j < jmax; ++j)
+ {
+ g (i, j);
+ }
+ /* This is the outer j, not the one from the inner collapsed loop. */
+ ++j;
+ }
+ return j;
+}
+
+int
+main (void)
+{
+ int j = foo (5, 3);
+ if (j != intervening_code_count)
+ abort ();
+ if (inner_loop_count != 5 * 3)
+ abort ();
+ if (intervening_code_count < 5 || intervening_code_count > 5 * 3)
+ abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c
new file mode 100644
index 00000000000..808c6540890
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c
@@ -0,0 +1,115 @@
+/* { dg-do run } */
+
+/* Like imperfect4.c, but bind the iteration variables in the loops. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+
+#pragma omp for collapse(3)
+ for (int i = 0; i < a1; i++)
+ {
+ { f1 (0, i); }
+ {
+ g1 (0, i);
+ for (int j = 0; j < a2; j++)
+ {
+ { f1 (1, j); }
+ {
+ { g1 (1, j); }
+ for (int k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ {
+ g1 (2, k);
+ g2 (2, k);
+ }
+ f2 (2, k);
+ }
+ { g2 (1, j); }
+ }
+ { f2 (1, j); }
+ }
+ { g2 (0, i); }
+ }
+ { f2 (0, i); }
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c
new file mode 100644
index 00000000000..53bc611ace3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c
@@ -0,0 +1,81 @@
+/* { dg-do run } */
+
+/* Like imperfect1.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+#pragma omp declare target enter (f1count, f2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ f2 (2, k);
+ }
+ f2 (1, j);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c
new file mode 100644
index 00000000000..bc2901a517e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c
@@ -0,0 +1,122 @@
+/* { dg-do run } */
+
+/* Like imperfect2.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+#pragma omp declare target enter (f1count, f2count)
+#pragma omp declare target enter (g1count, g2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ #pragma omp atomic
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ #pragma omp atomic
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count)
+ for (i = 0; i < a1; i++)
+ {
+ f1 (0, i);
+ {
+ g1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ f1 (1, j);
+ {
+ g1 (1, j);
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ {
+ g1 (2, k);
+ g2 (2, k);
+ }
+ f2 (2, k);
+ }
+ g2 (1, j);
+ }
+ f2 (1, j);
+ }
+ g2 (0, i);
+ }
+ f2 (0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c
new file mode 100644
index 00000000000..ddcfcf4b7eb
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c
@@ -0,0 +1,125 @@
+/* { dg-do run } */
+
+/* Like imperfect3.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+#pragma omp declare target enter (f1count, f2count)
+#pragma omp declare target enter (g1count, g2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ #pragma omp atomic
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ #pragma omp atomic
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count)
+ for (i = 0; i < a1; i++)
+ {
+ int local0 = 0;
+ f1 (local0, i);
+ {
+ g1 (local0, i);
+ for (j = 0; j < a2; j++)
+ {
+ int local1 = 1;
+ f1 (local1, j);
+ {
+ g1 (local1, j);
+ for (k = 0; k < a3; k++)
+ {
+ int local2 = 2;
+ f1 (local2, k);
+ {
+ g1 (local2, k);
+ g2 (local2, k);
+ }
+ f2 (local2, k);
+ }
+ g2 (local1, j);
+ }
+ f2 (local1, j);
+ }
+ g2 (local0, i);
+ }
+ f2 (local0, i);
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c
new file mode 100644
index 00000000000..ede488977b8
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c
@@ -0,0 +1,122 @@
+/* { dg-do run } */
+
+/* Like imperfect4.c, but enables offloading. */
+
+static int f1count[3], f2count[3];
+static int g1count[3], g2count[3];
+#pragma omp declare target enter (f1count, f2count)
+#pragma omp declare target enter (g1count, g2count)
+
+#ifndef __cplusplus
+extern void abort (void);
+#else
+extern "C" void abort (void);
+#endif
+
+int f1 (int depth, int iter)
+{
+ #pragma omp atomic
+ f1count[depth]++;
+ return iter;
+}
+
+int f2 (int depth, int iter)
+{
+ #pragma omp atomic
+ f2count[depth]++;
+ return iter;
+}
+
+int g1 (int depth, int iter)
+{
+ #pragma omp atomic
+ g1count[depth]++;
+ return iter;
+}
+
+int g2 (int depth, int iter)
+{
+ #pragma omp atomic
+ g2count[depth]++;
+ return iter;
+}
+
+void s1 (int a1, int a2, int a3)
+{
+ int i, j, k;
+
+#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count)
+ for (i = 0; i < a1; i++)
+ {
+ { f1 (0, i); }
+ {
+ g1 (0, i);
+ for (j = 0; j < a2; j++)
+ {
+ { f1 (1, j); }
+ {
+ { g1 (1, j); }
+ for (k = 0; k < a3; k++)
+ {
+ f1 (2, k);
+ {
+ g1 (2, k);
+ g2 (2, k);
+ }
+ f2 (2, k);
+ }
+ { g2 (1, j); }
+ }
+ { f2 (1, j); }
+ }
+ { g2 (0, i); }
+ }
+ { f2 (0, i); }
+ }
+}
+
+int
+main (void)
+{
+ f1count[0] = 0;
+ f1count[1] = 0;
+ f1count[2] = 0;
+ f2count[0] = 0;
+ f2count[1] = 0;
+ f2count[2] = 0;
+
+ g1count[0] = 0;
+ g1count[1] = 0;
+ g1count[2] = 0;
+ g2count[0] = 0;
+ g2count[1] = 0;
+ g2count[2] = 0;
+
+ s1 (3, 4, 5);
+
+ /* All intervening code at the same depth must be executed the same
+ number of times. */
+ if (f1count[0] != f2count[0]) abort ();
+ if (f1count[1] != f2count[1]) abort ();
+ if (f1count[2] != f2count[2]) abort ();
+ if (g1count[0] != f1count[0]) abort ();
+ if (g2count[0] != f1count[0]) abort ();
+ if (g1count[1] != f1count[1]) abort ();
+ if (g2count[1] != f1count[1]) abort ();
+ if (g1count[2] != f1count[2]) abort ();
+ if (g2count[2] != f1count[2]) abort ();
+
+ /* Intervening code must be executed at least as many times as the loop
+ that encloses it. */
+ if (f1count[0] < 3) abort ();
+ if (f1count[1] < 3 * 4) abort ();
+
+ /* Intervening code must not be executed more times than the number
+ of logical iterations. */
+ if (f1count[0] > 3 * 4 * 5) abort ();
+ if (f1count[1] > 3 * 4 * 5) abort ();
+
+ /* Check that the innermost loop body is executed exactly the number
+ of logical iterations expected. */
+ if (f1count[2] != 3 * 4 * 5) abort ();
+}
--
2.31.1
next prev parent reply other threads:[~2023-08-25 19:48 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-25 19:47 [COMMITTED V3 0/6] Support for imperfectly-nested loops Sandra Loosemore
2023-08-25 19:47 ` [COMMITTED V3 1/6] OpenMP: Add OMP_STRUCTURED_BLOCK and GIMPLE_OMP_STRUCTURED_BLOCK Sandra Loosemore
2023-08-25 19:47 ` [COMMITTED V3 2/6] OpenMP: C front end support for imperfectly-nested loops Sandra Loosemore
2023-08-25 19:47 ` [COMMITTED V3 3/6] OpenMP: C++ " Sandra Loosemore
2023-08-25 19:47 ` Sandra Loosemore [this message]
2023-08-25 19:47 ` [COMMITTED V3 5/6] OpenMP: Fortran " Sandra Loosemore
2023-08-25 19:47 ` [COMMITTED V3 6/6] OpenMP: Document " Sandra Loosemore
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230825194714.627157-5-sandra@codesourcery.com \
--to=sandra@codesourcery.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=tobias@codesourcery.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).