From 410df0843dbf08280813165bca72cfdaa21c8f23 Mon Sep 17 00:00:00 2001 From: Sandra Loosemore <sandra@codesourcery.com> Date: Thu, 24 Aug 2023 17:35:01 +0000 Subject: [PATCH] OpenMP: New C/C++ testcases for imperfectly nested loops. 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 000000000000..776295ce22a4 --- /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 000000000000..dfd40b6cb2d7 --- /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 000000000000..0fea58faf789 --- /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 000000000000..a8a8f9ebe1df --- /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 000000000000..897eed275ecb --- /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 000000000000..5c24aae07cca --- /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 000000000000..b7a7a4c83586 --- /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 000000000000..571e067091b7 --- /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 000000000000..a9f552241580 --- /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 000000000000..705626ad169e --- /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 000000000000..dff17dd3ca52 --- /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 000000000000..b2b46c1993e2 --- /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 000000000000..1a0c07cd48e0 --- /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 000000000000..da92578ed252 --- /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 000000000000..cafdcaf25b0e --- /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 000000000000..e2098006eabc --- /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 000000000000..feb5e32d1d65 --- /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 000000000000..e29301bfbad2 --- /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 000000000000..7bd4f12d472b --- /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 000000000000..808c65408900 --- /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 000000000000..53bc611ace3a --- /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 000000000000..bc2901a517e6 --- /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 000000000000..ddcfcf4b7ebc --- /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 000000000000..ede488977b88 --- /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 (); +} -- GitLab