As permitted by OpenMP 6, accept an 'omp nothing' directive as intervening code.
Also handle the special case where a metadirective can be resolved at parse time
to 'omp nothing'.
This fixes a build issue that affects 10 out 12 SPECaccel benchmarks.
PR c/120180
gcc/c/ChangeLog:
* c-parser.cc (c_parser_pragma): Do not emit an error for 'omp nothing'
and metadirectives as intervening code.
(c_parser_omp_metadirective): Return early if only one selector matches
and it resolves to 'omp nothing'.
gcc/cp/ChangeLog:
* parser.cc (cp_parser_omp_metadirective): Return early if only one
selector matches and it resolves to 'omp nothing'.
(cp_parser_pragma): Do not emit an error for 'omp nothing' and
metadirectives as intervening code.
gcc/fortran/ChangeLog:
* openmp.cc (match_omp_metadirective): Skip variants with a
user-condition selector that statically resolves to false.
* parse.cc (parse_omp_metadirective_body): Return early if there is only
one variant and it resolves to 'omp nothing'.
gcc/testsuite/ChangeLog:
* c-c++-common/gomp/imperfect1.c: Adjust dg-error.
* c-c++-common/gomp/imperfect4.c: Likewise.
* c-c++-common/gomp/pr120180.c: Move to...
* c-c++-common/gomp/pr120180-1.c: ...here. Remove dg-error.
* g++.dg/gomp/attrs-imperfect1.C: Adjust dg-error.
* g++.dg/gomp/attrs-imperfect4.C: Likewise.
* c-c++-common/gomp/pr120180-2.c: New test.
* g++.dg/gomp/pr120180-1.C: New test.
* g++.dg/gomp/pr120180-2.C: New test.
* gfortran.dg/gomp/pr120180-1.f90: New test.
* gfortran.dg/gomp/pr120180-2.f90: New test.
---
gcc/c/c-parser.cc | 22 ++++++++++---
gcc/cp/parser.cc | 21 ++++++++++---
gcc/fortran/openmp.cc | 10 ++++++
gcc/fortran/parse.cc | 11 ++++++-
gcc/testsuite/c-c++-common/gomp/imperfect1.c | 2 +-
gcc/testsuite/c-c++-common/gomp/imperfect4.c | 2 +-
.../gomp/{pr120180.c => pr120180-1.c} | 6 ++--
gcc/testsuite/c-c++-common/gomp/pr120180-2.c | 19 ++++++++++++
gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C | 2 +-
gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C | 2 +-
gcc/testsuite/g++.dg/gomp/pr120180-1.C | 26 ++++++++++++++++
gcc/testsuite/g++.dg/gomp/pr120180-2.C | 19 ++++++++++++
gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90 | 31 +++++++++++++++++++
gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90 | 31 +++++++++++++++++++
14 files changed, 187 insertions(+), 17 deletions(-)
rename gcc/testsuite/c-c++-common/gomp/{pr120180.c => pr120180-1.c} (79%)
create mode 100644 gcc/testsuite/c-c++-common/gomp/pr120180-2.c
create mode 100644 gcc/testsuite/g++.dg/gomp/pr120180-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/pr120180-2.C
create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 7c2452644bd..7b2990062aa 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -15761,11 +15761,12 @@ c_parser_pragma (c_parser *parser, enum
pragma_context context, bool *if_p,
gcc_assert (id != PRAGMA_NONE);
if (parser->omp_for_parse_state
&& parser->omp_for_parse_state->in_intervening_code
- && id >= PRAGMA_OMP__START_
- && id <= PRAGMA_OMP__LAST_)
+ && id >= PRAGMA_OMP__START_ && id <= PRAGMA_OMP__LAST_
+ && id != PRAGMA_OMP_METADIRECTIVE && id != PRAGMA_OMP_NOTHING)
{
- error_at (input_location,
- "intervening code must not contain OpenMP directives");
+ error_at (
+ input_location,
+ "intervening code must not contain executable OpenMP directives");
parser->omp_for_parse_state->fail = true;
c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
return false;
@@ -29837,6 +29838,17 @@ c_parser_omp_metadirective (c_parser *parser, bool
*if_p)
}
c_parser_skip_to_pragma_eol (parser);
+ /* If only one selector matches and it evaluates to 'omp nothing', no need to
+ * proceed. */
+ if (ctxs.length () == 1)
+ {
+ tree ctx = ctxs[0];
+ if (ctx == NULL_TREE
+ || (omp_context_selector_matches (ctx, NULL_TREE, false) == 1
+ && directive_tokens[0].pragma_kind == PRAGMA_OMP_NOTHING))
+ return;
+ }
+
if (!default_seen)
{
/* Add a default clause that evaluates to 'omp nothing'. */
@@ -29917,7 +29929,7 @@ c_parser_omp_metadirective (c_parser *parser, bool
*if_p)
if (standalone_body == NULL_TREE)
{
standalone_body = push_stmt_list ();
- c_parser_statement (parser, if_p);
+ c_parser_statement (parser, if_p); // TODO skip this
standalone_body = pop_stmt_list (standalone_body);
}
else
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 362cddbaf69..1e1fe65dce8 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -52609,6 +52609,18 @@ cp_parser_omp_metadirective (cp_parser *parser,
cp_token *pragma_tok,
}
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+ /* If only one selector matches and it evaluates to 'omp nothing', no need to
+ * proceed. */
+ if (ctxs.length () == 1)
+ {
+ tree ctx = ctxs[0];
+ if (ctx == NULL_TREE
+ || (omp_context_selector_matches (ctx, NULL_TREE, false) == 1
+ && cp_parser_pragma_kind (&directive_tokens[0])
+ == PRAGMA_OMP_NOTHING))
+ return;
+ }
+
if (!default_seen)
{
/* Add a default clause that evaluates to 'omp nothing'. */
@@ -54638,11 +54650,12 @@ cp_parser_pragma (cp_parser *parser, enum
pragma_context context, bool *if_p)
id = cp_parser_pragma_kind (pragma_tok);
if (parser->omp_for_parse_state
&& parser->omp_for_parse_state->in_intervening_code
- && id >= PRAGMA_OMP__START_
- && id <= PRAGMA_OMP__LAST_)
+ && id >= PRAGMA_OMP__START_ && id <= PRAGMA_OMP__LAST_
+ && id != PRAGMA_OMP_METADIRECTIVE && id != PRAGMA_OMP_NOTHING)
{
- error_at (pragma_tok->location,
- "intervening code must not contain OpenMP directives");
+ error_at (
+ pragma_tok->location,
+ "intervening code must not contain executable OpenMP directives");
parser->omp_for_parse_state->fail = true;
cp_parser_skip_to_pragma_eol (parser, pragma_tok);
return false;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 9e282c7b9f1..cb6ff2262cd 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -7089,6 +7089,16 @@ match_omp_metadirective (bool begin_p)
return MATCH_ERROR;
}
+ /* Don't record the variant if the selector is a false user condition.
*/
+ if (selectors != NULL && selectors->code == OMP_TRAIT_SET_USER
+ && selectors->trait_selectors->code == OMP_TRAIT_USER_CONDITION
+ && selectors->trait_selectors->properties->property_kind
+ == OMP_TRAIT_PROPERTY_BOOL_EXPR
+ && selectors->trait_selectors->properties->expr->expr_type
+ == EXPR_CONSTANT
+ && selectors->trait_selectors->properties->expr->value.logical == 0)
+ continue;
+
if (default_p)
default_seen = true;
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index b29f6900841..e16030f0ec4 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -6518,7 +6518,16 @@ parse_omp_metadirective_body (gfc_statement omp_st)
locus body_locus = gfc_current_locus;
bool saw_error = false;
- accept_statement (omp_st);
+ /* If there is only one variant and it evaluates to 'omp nothing', no need to
+ proceed. */
+ if (variant->selectors == NULL && variant->stmt == ST_NONE
+ && variant->next == NULL)
+ {
+ reject_statement ();
+ return next_statement ();
+ }
+ else
+ accept_statement (omp_st);
gfc_statement next_st = ST_NONE;
locus next_loc;
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect1.c
b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
index 705626ad169..bef783bb907 100644
--- a/gcc/testsuite/c-c++-common/gomp/imperfect1.c
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect1.c
@@ -15,7 +15,7 @@ void s1 (int a1, int a2, int a3)
f1 (0, i);
for (j = 0; j < a2; j++)
{
-#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP
directives" } */
+#pragma omp barrier /* { dg-error "intervening code must not contain
executable OpenMP directives" } */
f1 (1, j);
if (i == 2)
continue; /* { dg-error "invalid exit" } */
diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect4.c
b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
index 1a0c07cd48e..30d1cc66235 100644
--- a/gcc/testsuite/c-c++-common/gomp/imperfect4.c
+++ b/gcc/testsuite/c-c++-common/gomp/imperfect4.c
@@ -21,7 +21,7 @@ void s1 (int a1, int a2, int a3)
/* 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" } */
+#pragma omp barrier /* { dg-error "intervening code must not contain
executable OpenMP directives" } */
f1 (2, k);
f2 (2, k);
}
diff --git a/gcc/testsuite/c-c++-common/gomp/pr120180.c
b/gcc/testsuite/c-c++-common/gomp/pr120180-1.c
similarity index 79%
rename from gcc/testsuite/c-c++-common/gomp/pr120180.c
rename to gcc/testsuite/c-c++-common/gomp/pr120180-1.c
index cb5a0d5a819..52b5082b4e7 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr120180.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr120180-1.c
@@ -1,7 +1,7 @@
/* { dg-do compile } */
-/* This test used to ICE after erroring on the metadirective in the
- loop nest. */
+/* This test case checks that the inner metadirective is accepted as
intervening
+ code since it resolves to 'omp nothing'. */
int main()
{
@@ -14,7 +14,7 @@ int main()
when(user={condition(1)}: target teams loop
collapse(2) map(qq[:0]) private(i))
for(k=0; k<blksize; k++)
{
-#pragma omp metadirective when(user={condition(0)}: simd) default() // {
dg-error "intervening code must not contain OpenMP directives" }
+#pragma omp metadirective when(user={condition(0)}: simd) default()
for (i=0; i<nq; i++)
qq[k*nq + i] = 0.0;
}
diff --git a/gcc/testsuite/c-c++-common/gomp/pr120180-2.c
b/gcc/testsuite/c-c++-common/gomp/pr120180-2.c
new file mode 100644
index 00000000000..6c52e6c3dcb
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/pr120180-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+
+/* This test case checks that a non-executable OpenMP directive is accepted
+ as intervening code. */
+
+int main()
+{
+ int blksize = 15000;
+ double *qq;
+ int i, k, nq;
+#pragma omp target parallel for collapse(2) map(qq[:0]) private(i)
+ for(k=0; k<blksize; k++)
+ {
+ #pragma omp nothing
+ for (i=0; i<nq; i++)
+ qq[k*nq + i] = 0.0;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
index cf293b5081c..b43139c8968 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect1.C
@@ -15,7 +15,7 @@ void s1 (int a1, int a2, int a3)
f1 (0, i);
for (j = 0; j < a2; j++)
{
- [[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code
must not contain OpenMP directives" } */
+ [[ omp :: directive (barrier) ]] ; /* { dg-error "intervening code
must not contain executable OpenMP directives" } */
f1 (1, j);
if (i == 2)
continue; /* { dg-error "invalid exit" } */
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
index 16636ab3eb6..94b4db856a9 100644
--- a/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
+++ b/gcc/testsuite/g++.dg/gomp/attrs-imperfect4.C
@@ -21,7 +21,7 @@ void s1 (int a1, int a2, int a3)
/* 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. */
- [[ omp :: directive (barrier) ]] ; /* { dg-error
"intervening code must not contain OpenMP directives" } */
+ [[ omp :: directive (barrier) ]] ; /* { dg-error
"intervening code must not contain executable OpenMP directives" } */
f1 (2, k);
f2 (2, k);
}
diff --git a/gcc/testsuite/g++.dg/gomp/pr120180-1.C
b/gcc/testsuite/g++.dg/gomp/pr120180-1.C
new file mode 100644
index 00000000000..819b3ee9045
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr120180-1.C
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-additional-options "-std=c++11" }
+
+// This test case checks that the inner metadirective is accepted as
intervening
+// code since it resolves to 'omp nothing'.
+
+int main()
+{
+ constexpr int use_teams = 1;
+ constexpr int use_simd = 0;
+
+ int blksize = 15000;
+ double *qq;
+ int i, k, nq;
+
+ #pragma omp metadirective when(user={condition(use_teams)}: teams distribute
parallel for collapse(2)) \
+ otherwise(parallel for collapse(1))
+ for(k=0; k<blksize; k++)
+ {
+ #pragma omp metadirective when(user={condition(use_simd)}: simd) \
+ otherwise(nothing)
+ for (i=0; i<nq; i++)
+ qq[k*nq + i] = 0.0;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr120180-2.C
b/gcc/testsuite/g++.dg/gomp/pr120180-2.C
new file mode 100644
index 00000000000..2a74ad6b94a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr120180-2.C
@@ -0,0 +1,19 @@
+// { dg-do compile }
+
+// This test case checks that a non-executable OpenMP directive is accepted
+// as intervening code.
+
+int main()
+{
+ int blksize = 15000;
+ double *qq;
+ int i, k, nq;
+#pragma omp target parallel for collapse(2) map(qq[:0]) private(i)
+ for(k=0; k<blksize; k++)
+ {
+ #pragma omp nothing
+ for (i=0; i<nq; i++)
+ qq[k*nq + i] = 0.0;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
b/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
new file mode 100644
index 00000000000..a6dd68d3d36
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr120180-1.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+
+! This test case checks that the inner metadirective is accepted as intervening
+! code since it resolves to 'omp nothing'.
+
+SUBROUTINE test(x_min, x_max, y_min, y_max, xarea, vol_flux_x)
+
+ IMPLICIT NONE
+
+ INTEGER, INTENT(IN) :: x_min, x_max, y_min, y_max
+
+ REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: xarea
+ REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: vol_flux_x
+
+ INTEGER :: j,k
+
+!$omp metadirective &
+!$omp when(user={condition(.false.)}: &
+!$omp target teams distribute parallel do simd collapse(2)) &
+!$omp when(user={condition(.false.)}: &
+!$omp target teams distribute parallel do) &
+!$omp default( &
+!$omp target teams loop collapse(2))
+ DO k=y_min,y_max
+!$omp metadirective when(user={condition(.false.)}: simd)
+ DO j=x_min,x_max
+ vol_flux_x(j,k)=0.25_8*xarea(j,k)
+ ENDDO
+ ENDDO
+
+END SUBROUTINE test
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
b/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
new file mode 100644
index 00000000000..9f3389b4987
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr120180-2.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+
+! This test case checks that a non-executable OpenMP directive is accepted
+! as intervening code.
+
+SUBROUTINE test(x_min, x_max, y_min, y_max, xarea, vol_flux_x)
+
+ IMPLICIT NONE
+
+ INTEGER, INTENT(IN) :: x_min, x_max, y_min, y_max
+
+ REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: xarea
+ REAL(KIND=8), DIMENSION(x_min:x_max,y_min:y_max) :: vol_flux_x
+
+ INTEGER :: j,k
+
+!$omp metadirective &
+!$omp when(user={condition(.false.)}: &
+!$omp target teams distribute parallel do simd collapse(2)) &
+!$omp when(user={condition(.false.)}: &
+!$omp target teams distribute parallel do) &
+!$omp default( &
+!$omp target teams loop collapse(2))
+ DO k=y_min,y_max
+!$omp nothing
+ DO j=x_min,x_max
+ vol_flux_x(j,k)=0.25_8*xarea(j,k)
+ ENDDO
+ ENDDO
+
+END SUBROUTINE test
--
2.51.0