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 &); @@ -150,6 +152,21 @@ void Enter(const parser::OmpClause::Uniform &); void Enter(const parser::OmpClause::UseDevicePtr &); void Enter(const parser::OmpClause::IsDevicePtr &); + // Memory-order-clause + void Enter(const parser::OmpClause::SeqCst &); + void Enter(const parser::OmpClause::AcqRel &); + void Enter(const parser::OmpClause::Release &); + void Enter(const parser::OmpClause::Acquire &); + void Enter(const parser::OmpClause::Relaxed &); + // Atomic-clause + 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 &); 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "check-omp-structure.h" +#include "flang/Common/Fortran.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/tools.h" @@ -208,6 +209,20 @@ dirContext_.pop_back(); } +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(); +} void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) { const auto &dir{std::get(x.t)}; ResetPartialContext(dir.source); @@ -449,6 +464,58 @@ void OmpStructureChecker::Enter(const parser::OmpClause::IsDevicePtr &) { CheckAllowed(llvm::omp::Clause::OMPC_is_device_ptr); } +// Memory-order-clause +void OmpStructureChecker::Enter(const parser::OmpClause::SeqCst &) { + CheckAllowed(llvm::omp::Clause::OMPC_seq_cst); +} +void OmpStructureChecker::Enter(const parser::OmpClause::AcqRel &) { + CheckAllowed(llvm::omp::Clause::OMPC_acq_rel); +} +void OmpStructureChecker::Enter(const parser::OmpClause::Release &) { + CheckAllowed(llvm::omp::Clause::OMPC_release); +} +void OmpStructureChecker::Enter(const parser::OmpClause::Acquire &) { + CheckAllowed(llvm::omp::Clause::OMPC_acquire); +} +void OmpStructureChecker::Enter(const parser::OmpClause::Relaxed &) { + CheckAllowed(llvm::omp::Clause::OMPC_relaxed); +} + +// Atomic-clause +void OmpStructureChecker::Enter(const parser::OmpAtomicRead &) { + CheckAllowed(llvm::omp::Clause::OMPC_read); +} +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::Enter(const parser::OmpAtomicWrite &) { + CheckAllowed(llvm::omp::Clause::OMPC_write); +} +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::Enter(const parser::OmpAtomicUpdate &) { + CheckAllowed(llvm::omp::Clause::OMPC_update); +} +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::Enter(const parser::OmpAtomicCapture &) { + CheckAllowed(llvm::omp::Clause::OMPC_capture); +} +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); + } +} void OmpStructureChecker::Enter(const parser::OmpAlignedClause &x) { CheckAllowed(llvm::omp::Clause::OMPC_aligned); 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,274 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp + ! Semantic checks for OpenMP 5.0 standard 2.17.7 atomic Construct. + + !TODO: At most one hint clause may appear on the construct. +use omp_lib + implicit none + integer :: i, j = 10, k=-100, a + +! 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 +! TODO: Hint is currently not found in `actualClauses`. +! At most one hint clause may appear on the construct. + !$omp atomic hint(10) hint(10) read + i = j + !$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 @@ -442,7 +442,9 @@ VersionedClause, VersionedClause, VersionedClause, - VersionedClause, + ]; + let allowedOnceClauses = [ + VersionedClause, VersionedClause, VersionedClause, VersionedClause,