diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -549,6 +549,8 @@ NODE(parser, OpenMPDeclareSimdConstruct) NODE(parser, OpenMPDeclareTargetConstruct) NODE(parser, OmpMemoryOrderClause) + NODE(parser, OmpAtomicClause) + NODE(parser, OmpAtomicClauseList) NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPSimpleStandaloneConstruct) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3607,11 +3607,34 @@ std::tuple t; }; -// 2.17.7 atomic -> ATOMIC [clause[,]] atomic-clause [[,]clause] | -// ATOMIC [clause] -// clause -> memory-order-clause | HINT(hint-expression) -// memory-order-clause -> SEQ_CST | ACQ_REL | RELEASE | ACQUIRE | RELAXED -// atomic-clause -> READ | WRITE | UPDATE | CAPTURE +// 2.17.7 Atomic construct/2.17.8 Flush construct [OpenMP 5.0] +// memory-order-clause -> acq_rel +// release +// acquire +// seq_cst +// relaxed +struct OmpMemoryOrderClause { + WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause); + CharBlock source; +}; + +// 2.17.7 Atomic construct +// atomic-clause -> memory-order-clause | HINT(hint-expression) +struct OmpAtomicClause { + UNION_CLASS_BOILERPLATE(OmpAtomicClause); + CharBlock source; + std::variant u; +}; + +// atomic-clause-list -> [atomic-clause, [atomic-clause], ...] +struct OmpAtomicClauseList { + WRAPPER_CLASS_BOILERPLATE(OmpAtomicClauseList, std::list); + CharBlock source; +}; +// 2.17.7 atomic -> +// ATOMIC [atomic-clause-list] atomic-construct [atomic-clause-list] | +// ATOMIC [atomic-clause-list] +// atomic-construct -> READ | WRITE | UPDATE | CAPTURE // END ATOMIC EMPTY_CLASS(OmpEndAtomic); @@ -3620,8 +3643,8 @@ struct OmpAtomicRead { TUPLE_CLASS_BOILERPLATE(OmpAtomicRead); CharBlock source; - std::tuple, - std::optional> + std::tuple, std::optional> t; }; @@ -3629,8 +3652,8 @@ struct OmpAtomicWrite { TUPLE_CLASS_BOILERPLATE(OmpAtomicWrite); CharBlock source; - std::tuple, - std::optional> + std::tuple, std::optional> t; }; @@ -3638,8 +3661,8 @@ struct OmpAtomicUpdate { TUPLE_CLASS_BOILERPLATE(OmpAtomicUpdate); CharBlock source; - std::tuple, - std::optional> + std::tuple, std::optional> t; }; @@ -3649,7 +3672,8 @@ CharBlock source; WRAPPER_CLASS(Stmt1, Statement); WRAPPER_CLASS(Stmt2, Statement); - std::tuple + std::tuple t; }; @@ -3657,7 +3681,7 @@ struct OmpAtomic { TUPLE_CLASS_BOILERPLATE(OmpAtomic); CharBlock source; - std::tuple, + std::tuple, std::optional> t; }; @@ -3697,14 +3721,6 @@ std::tuple> t; }; -// 2.17.8 Flush Construct [OpenMP 5.0] -// memory-order-clause -> acq_rel -// release -// acquire -struct OmpMemoryOrderClause { - WRAPPER_CLASS_BOILERPLATE(OmpMemoryOrderClause, OmpClause); - CharBlock source; -}; // 2.17.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)] struct OpenMPFlushConstruct { diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -316,6 +316,18 @@ "ACQUIRE" >> construct(construct()) || "RELAXED" >> construct(construct()))))) +// 2.17.7 Atomic construct +// atomic-clause -> memory-order-clause | HINT(hint-expression) +TYPE_PARSER(sourced(construct( + construct(Parser{}) || + construct("HINT" >> + sourced(construct( + construct(parenthesized(constantExpr)))))))) + +// atomic-clause-list -> [atomic-clause, [atomic-clause], ...] +TYPE_PARSER(sourced(construct( + many(maybe(","_tok) >> sourced(Parser{}))))) + TYPE_PARSER(sourced(construct(verbatim("FLUSH"_tok), maybe(Parser{}), maybe(parenthesized(Parser{}))))) @@ -407,32 +419,32 @@ // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] READ [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> - construct(Parser{} / maybe(","_tok), - verbatim("READ"_tok), Parser{} / endOmpLine, + construct(Parser{} / maybe(","_tok), + verbatim("READ"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] CAPTURE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> - construct(Parser{} / maybe(","_tok), - verbatim("CAPTURE"_tok), Parser{} / endOmpLine, + construct(Parser{} / maybe(","_tok), + verbatim("CAPTURE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), statement(assignmentStmt), Parser{} / endOmpLine)) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] UPDATE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> - construct(Parser{} / maybe(","_tok), - verbatim("UPDATE"_tok), Parser{} / endOmpLine, + construct(Parser{} / maybe(","_tok), + verbatim("UPDATE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine))) -// OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] +// OMP ATOMIC [atomic-clause-list] TYPE_PARSER(construct(verbatim("ATOMIC"_tok), - Parser{} / endOmpLine, statement(assignmentStmt), + Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine))) // OMP ATOMIC [MEMORY-ORDER-CLAUSE-LIST] WRITE [MEMORY-ORDER-CLAUSE-LIST] TYPE_PARSER("ATOMIC" >> - construct(Parser{} / maybe(","_tok), - verbatim("WRITE"_tok), Parser{} / endOmpLine, + construct(Parser{} / maybe(","_tok), + verbatim("WRITE"_tok), Parser{} / endOmpLine, statement(assignmentStmt), maybe(Parser{} / endOmpLine))) // Atomic Construct diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2222,10 +2222,12 @@ break; } } + void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); } + void Unparse(const OmpAtomic &x) { BeginOpenMP(); Word("!$OMP ATOMIC"); - Walk(std::get(x.t)); + Walk(std::get(x.t)); Put("\n"); EndOpenMP(); Walk(std::get>(x.t)); @@ -2420,6 +2422,13 @@ EndOpenMP(); } void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); } + void Unparse(const OmpAtomicClause &x) { + std::visit(common::visitors{ + [&](const OmpMemoryOrderClause &y) { Walk(y); }, + [&](const OmpClause &z) { Walk(z); }, + }, + x.u); + } void Unparse(const OpenMPFlushConstruct &x) { BeginOpenMP(); Word("!$OMP FLUSH "); diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -117,6 +117,8 @@ void Leave(const parser::OpenMPCancellationPointConstruct &); void Enter(const parser::OpenMPCriticalConstruct &); void Leave(const parser::OpenMPCriticalConstruct &); + void Enter(const parser::OpenMPAtomicConstruct &); + void Leave(const parser::OpenMPAtomicConstruct &); void Leave(const parser::OmpClauseList &); void Enter(const parser::OmpClause &); @@ -156,7 +158,16 @@ void Enter(const parser::OmpClause::Release &); void Enter(const parser::OmpClause::Acquire &); void Enter(const parser::OmpClause::Relaxed &); - + void Enter(const parser::OmpClause::Hint &); + + void Enter(const parser::OmpAtomicRead &); + void Leave(const parser::OmpAtomicRead &); + void Enter(const parser::OmpAtomicWrite &); + void Leave(const parser::OmpAtomicWrite &); + void Enter(const parser::OmpAtomicUpdate &); + void Leave(const parser::OmpAtomicUpdate &); + void Enter(const parser::OmpAtomicCapture &); + void Leave(const parser::OmpAtomic &); void Enter(const parser::OmpAlignedClause &); void Enter(const parser::OmpAllocateClause &); void Enter(const parser::OmpDefaultClause &); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -262,6 +262,22 @@ } } +void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) { + std::visit( + common::visitors{ + [&](const auto &someAtomicConstruct) { + const auto &dir{std::get(someAtomicConstruct.t)}; + PushContextAndClauseSets( + dir.source, llvm::omp::Directive::OMPD_atomic); + }, + }, + x.u); +} + +void OmpStructureChecker::Leave(const parser::OpenMPAtomicConstruct &) { + dirContext_.pop_back(); +} + // Clauses // Mainly categorized as // 1. Checks on 'OmpClauseList' from 'parse-tree.h'. @@ -381,6 +397,7 @@ CHECK_SIMPLE_CLAUSE(SeqCst, OMPC_seq_cst) CHECK_SIMPLE_CLAUSE(Release, OMPC_release) CHECK_SIMPLE_CLAUSE(Relaxed, OMPC_relaxed) +CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint) CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize) CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks) @@ -448,7 +465,34 @@ CHECK_SIMPLE_PARSER_CLAUSE(OmpNowait, OMPC_nowait) CHECK_SIMPLE_PARSER_CLAUSE(OmpProcBindClause, OMPC_proc_bind) CHECK_SIMPLE_PARSER_CLAUSE(OmpReductionClause, OMPC_reduction) - +// Atomic-clause +CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read) +CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write) +CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicUpdate, OMPC_update) +CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicCapture, OMPC_capture) + +void OmpStructureChecker::Leave(const parser::OmpAtomicRead &) { + CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_read, + {llvm::omp::Clause::OMPC_release, llvm::omp::Clause::OMPC_acq_rel}); +} +void OmpStructureChecker::Leave(const parser::OmpAtomicWrite &) { + CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_write, + {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel}); +} +void OmpStructureChecker::Leave(const parser::OmpAtomicUpdate &) { + CheckNotAllowedIfClause(llvm::omp::Clause::OMPC_update, + {llvm::omp::Clause::OMPC_acquire, llvm::omp::Clause::OMPC_acq_rel}); +} +void OmpStructureChecker::Leave(const parser::OmpAtomic &) { + if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acquire)}) { + context_.Say(clause->source, + "Clause ACQUIRE is not allowed on the ATOMIC directive"_err_en_US); + } + if (const auto *clause{FindClause(llvm::omp::Clause::OMPC_acq_rel)}) { + context_.Say(clause->source, + "Clause ACQ_REL is not allowed on the ATOMIC directive"_err_en_US); + } +} // Restrictions specific to each clause are implemented apart from the // generalized restrictions. void OmpStructureChecker::Enter(const parser::OmpAlignedClause &x) { diff --git a/flang/test/Semantics/omp-atomic.f90 b/flang/test/Semantics/omp-atomic.f90 --- a/flang/test/Semantics/omp-atomic.f90 +++ b/flang/test/Semantics/omp-atomic.f90 @@ -34,6 +34,17 @@ !$omp atomic a = a + 1 + !ERROR: expected 'UPDATE' + !ERROR: expected 'WRITE' + !ERROR: expected 'CAPTURE' + !ERROR: expected 'READ' + !$omp atomic num_threads(4) + a = a + 1 + + !ERROR: expected end of line + !ERROR: expected end of line + !$omp atomic capture num_threads(4) + a = a + 1 !$omp atomic relaxed a = a + 1 diff --git a/flang/test/Semantics/omp-atomic01.f90 b/flang/test/Semantics/omp-atomic01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-atomic01.f90 @@ -0,0 +1,334 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! Semantic checks for OpenMP 5.0 standard 2.17.7 atomic Construct. + +use omp_lib + implicit none + integer :: i, j = 10, k=-100, a +! 2.17.7.1 +! Handled inside parser. +! OpenMP constructs may not be encountered during execution of an atomic region + +! 2.17.7.2 +! At most one memory-order-clause may appear on the construct. + +!READ + !ERROR: At most one SEQ_CST clause can appear on the READ directive + !$omp atomic seq_cst seq_cst read + i = j + !ERROR: At most one SEQ_CST clause can appear on the READ directive + !$omp atomic read seq_cst seq_cst + i = j + !ERROR: At most one SEQ_CST clause can appear on the READ directive + !$omp atomic seq_cst read seq_cst + i = j + + !ERROR: At most one ACQUIRE clause can appear on the READ directive + !$omp atomic acquire acquire read + i = j + !ERROR: At most one ACQUIRE clause can appear on the READ directive + !$omp atomic read acquire acquire + i = j + !ERROR: At most one ACQUIRE clause can appear on the READ directive + !$omp atomic acquire read acquire + i = j + + !ERROR: At most one RELAXED clause can appear on the READ directive + !$omp atomic relaxed relaxed read + i = j + !ERROR: At most one RELAXED clause can appear on the READ directive + !$omp atomic read relaxed relaxed + i = j + !ERROR: At most one RELAXED clause can appear on the READ directive + !$omp atomic relaxed read relaxed + i = j + +!UPDATE + !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !$omp atomic seq_cst seq_cst update + i = j + !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !$omp atomic update seq_cst seq_cst + i = j + !ERROR: At most one SEQ_CST clause can appear on the UPDATE directive + !$omp atomic seq_cst update seq_cst + i = j + + !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !$omp atomic release release update + i = j + !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !$omp atomic update release release + i = j + !ERROR: At most one RELEASE clause can appear on the UPDATE directive + !$omp atomic release update release + i = j + + !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !$omp atomic relaxed relaxed update + i = j + !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !$omp atomic update relaxed relaxed + i = j + !ERROR: At most one RELAXED clause can appear on the UPDATE directive + !$omp atomic relaxed update relaxed + i = j + +!CAPTURE + !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !$omp atomic seq_cst seq_cst capture + i = j + j = k + !$omp end atomic + + !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !$omp atomic capture seq_cst seq_cst + i = j + j = k + !$omp end atomic + + !ERROR: At most one SEQ_CST clause can appear on the CAPTURE directive + !$omp atomic seq_cst capture seq_cst + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !$omp atomic release release capture + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !$omp atomic capture release release + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELEASE clause can appear on the CAPTURE directive + !$omp atomic release capture release + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !$omp atomic relaxed relaxed capture + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !$omp atomic capture relaxed relaxed + i = j + j = k + !$omp end atomic + + !ERROR: At most one RELAXED clause can appear on the CAPTURE directive + !$omp atomic relaxed capture relaxed + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !$omp atomic acq_rel acq_rel capture + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !$omp atomic capture acq_rel acq_rel + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQ_REL clause can appear on the CAPTURE directive + !$omp atomic acq_rel capture acq_rel + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !$omp atomic acquire acquire capture + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !$omp atomic capture acquire acquire + i = j + j = k + !$omp end atomic + + !ERROR: At most one ACQUIRE clause can appear on the CAPTURE directive + !$omp atomic acquire capture acquire + i = j + j = k + !$omp end atomic + +!WRITE + !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !$omp atomic seq_cst seq_cst write + i = j + !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !$omp atomic write seq_cst seq_cst + i = j + !ERROR: At most one SEQ_CST clause can appear on the WRITE directive + !$omp atomic seq_cst write seq_cst + i = j + + !ERROR: At most one RELEASE clause can appear on the WRITE directive + !$omp atomic release release write + i = j + !ERROR: At most one RELEASE clause can appear on the WRITE directive + !$omp atomic write release release + i = j + !ERROR: At most one RELEASE clause can appear on the WRITE directive + !$omp atomic release write release + i = j + + !ERROR: At most one RELAXED clause can appear on the WRITE directive + !$omp atomic relaxed relaxed write + i = j + !ERROR: At most one RELAXED clause can appear on the WRITE directive + !$omp atomic write relaxed relaxed + i = j + !ERROR: At most one RELAXED clause can appear on the WRITE directive + !$omp atomic relaxed write relaxed + i = j + +!No atomic-clause + !ERROR: At most one RELAXED clause can appear on the ATOMIC directive + !$omp atomic relaxed relaxed + i = j + !ERROR: At most one SEQ_CST clause can appear on the ATOMIC directive + !$omp atomic seq_cst seq_cst + i = j + !ERROR: At most one RELEASE clause can appear on the ATOMIC directive + !$omp atomic release release + i = j + +! 2.17.7.3 +! At most one hint clause may appear on the construct. + + !ERROR: At most one HINT clause can appear on the READ directive + !$omp atomic hint(omp_sync_hint_speculative) hint(omp_sync_hint_speculative) read + i = j + !ERROR: At most one HINT clause can appear on the READ directive + !$omp atomic hint(omp_sync_hint_nonspeculative) read hint(omp_sync_hint_nonspeculative) + i = j + !ERROR: At most one HINT clause can appear on the READ directive + !$omp atomic read hint(omp_sync_hint_uncontended) hint (omp_sync_hint_uncontended) + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative) + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) write + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic hint(omp_sync_hint_nonspeculative) write hint(omp_sync_hint_nonspeculative) + i = j + !ERROR: At most one HINT clause can appear on the WRITE directive + !$omp atomic write hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) + i = j + !ERROR: At most one HINT clause can appear on the UPDATE directive + !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) update + i = j + !ERROR: At most one HINT clause can appear on the UPDATE directive + !$omp atomic hint(omp_sync_hint_nonspeculative) update hint(omp_sync_hint_nonspeculative) + i = j + !ERROR: At most one HINT clause can appear on the UPDATE directive + !$omp atomic update hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) + i = j + !ERROR: At most one HINT clause can appear on the ATOMIC directive + !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) + i = j + !ERROR: At most one HINT clause can appear on the ATOMIC directive + !$omp atomic hint(omp_sync_hint_none) hint(omp_sync_hint_nonspeculative) + i = j + !ERROR: At most one HINT clause can appear on the ATOMIC directive + !$omp atomic hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) + i = j + + !ERROR: At most one HINT clause can appear on the CAPTURE directive + !$omp atomic hint(omp_sync_hint_contended) hint(omp_sync_hint_speculative) capture + i = j + j = k + !$omp end atomic + !ERROR: At most one HINT clause can appear on the CAPTURE directive + !$omp atomic hint(omp_sync_hint_nonspeculative) capture hint(omp_sync_hint_nonspeculative) + i = j + j = k + !$omp end atomic + !ERROR: At most one HINT clause can appear on the CAPTURE directive + !$omp atomic capture hint(omp_sync_hint_none) hint (omp_sync_hint_uncontended) + i = j + j = k + !$omp end atomic +! 2.17.7.4 +! If atomic-clause is read then memory-order-clause must not be acq_rel or release. + + !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive + !$omp atomic acq_rel read + i = j + !ERROR: Clause ACQ_REL is not allowed if clause READ appears on the ATOMIC directive + !$omp atomic read acq_rel + i = j + + !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive + !$omp atomic release read + i = j + !ERROR: Clause RELEASE is not allowed if clause READ appears on the ATOMIC directive + !$omp atomic read release + i = j + +! 2.17.7.5 +! If atomic-clause is write then memory-order-clause must not be acq_rel or acquire. + + !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive + !$omp atomic acq_rel write + i = j + !ERROR: Clause ACQ_REL is not allowed if clause WRITE appears on the ATOMIC directive + !$omp atomic write acq_rel + i = j + + !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive + !$omp atomic acquire write + i = j + !ERROR: Clause ACQUIRE is not allowed if clause WRITE appears on the ATOMIC directive + !$omp atomic write acquire + i = j + + +! 2.17.7.6 +! If atomic-clause is update or not present then memory-order-clause must not be acq_rel or acquire. + + !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive + !$omp atomic acq_rel update + i = j + !ERROR: Clause ACQ_REL is not allowed if clause UPDATE appears on the ATOMIC directive + !$omp atomic update acq_rel + i = j + + !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive + !$omp atomic acquire update + i = j + + !ERROR: Clause ACQUIRE is not allowed if clause UPDATE appears on the ATOMIC directive + !$omp atomic update acquire + i = j + + !ERROR: Clause ACQ_REL is not allowed on the ATOMIC directive + !$omp atomic acq_rel + i = j + + !ERROR: Clause ACQUIRE is not allowed on the ATOMIC directive + !$omp atomic acquire + i = j +end program + diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -467,6 +467,8 @@ VersionedClause, VersionedClause, VersionedClause, + ]; + let allowedOnceClauses = [ VersionedClause, VersionedClause, VersionedClause,