Index: flang/include/flang/Parser/parse-tree.h =================================================================== --- flang/include/flang/Parser/parse-tree.h +++ flang/include/flang/Parser/parse-tree.h @@ -3439,9 +3439,9 @@ std::tuple> t; }; -// 2.13.9 depend-type -> IN | OUT | INOUT | SOURCE | SINK +// 2.13.9 depend-type -> IN | OUT | INOUT struct OmpDependenceType { - ENUM_CLASS(Type, In, Out, Inout, Source, Sink) + ENUM_CLASS(Type, In, Out, Inout) WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Type); }; Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -135,6 +135,7 @@ void Enter(const parser::OpenMPBlockConstruct &); void Leave(const parser::OpenMPBlockConstruct &); + void Leave(const parser::OmpBeginBlockDirective &); void Enter(const parser::OmpEndBlockDirective &); void Leave(const parser::OmpEndBlockDirective &); @@ -236,7 +237,9 @@ const parser::DefinedOperator::IntrinsicOperator &); void CheckReductionTypeList(const parser::OmpClause::Reduction &); void CheckMasterNesting(const parser::OpenMPBlockConstruct &x); + void ChecksOnOrderedAsBlock(); void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); + void ChecksOnOrderedAsStandalone(); void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); void CheckIntentInPointerAndDefinable( const parser::OmpObjectList &, const llvm::omp::Clause); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -769,6 +769,25 @@ dirContext_.pop_back(); } +void OmpStructureChecker::ChecksOnOrderedAsBlock() { + if (FindClause(llvm::omp::Clause::OMPC_depend)) { + context_.Say(GetContext().clauseSource, + "DEPEND(*) clauses are not allowed when ORDERED construct is a block" + " construct with an ORDERED region"_err_en_US); + } +} + +void OmpStructureChecker::Leave(const parser::OmpBeginBlockDirective &) { + switch (GetContext().directive) { + case llvm::omp::Directive::OMPD_ordered: + // [5.1] 2.19.9 Ordered Construct Restriction + ChecksOnOrderedAsBlock(); + break; + default: + break; + } +} + void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) { const auto &beginSectionsDir{ std::get(x.t)}; @@ -896,6 +915,48 @@ } } +void OmpStructureChecker::ChecksOnOrderedAsStandalone() { + if (FindClause(llvm::omp::Clause::OMPC_threads) || + FindClause(llvm::omp::Clause::OMPC_simd)) { + context_.Say(GetContext().clauseSource, + "THREADS, SIMD clauses are not allowed when ORDERED construct is a " + "standalone construct with no ORDERED region"_err_en_US); + } + + bool isSinkPresent{false}; + int dependSourceCount{0}; + auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_depend); + for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) { + const auto &dependClause{ + std::get(itr->second->u)}; + if (std::get_if(&dependClause.v.u)) { + dependSourceCount++; + if (isSinkPresent) { + context_.Say(itr->second->source, + "DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present " + "on ORDERED directive"_err_en_US); + } + if (dependSourceCount > 1) { + context_.Say(itr->second->source, + "At most one DEPEND(SOURCE) clause can appear on the ORDERED " + "directive"_err_en_US); + } + } else if (std::get_if(&dependClause.v.u)) { + isSinkPresent = true; + if (dependSourceCount > 0) { + context_.Say(itr->second->source, + "DEPEND(SINK: vec) is not allowed when DEPEND(SOURCE) is present " + "on ORDERED directive"_err_en_US); + } + } else { + context_.Say(itr->second->source, + "Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED " + "construct is a standalone construct with no ORDERED " + "region"_err_en_US); + } + } +} + void OmpStructureChecker::Enter( const parser::OpenMPSimpleStandaloneConstruct &x) { const auto &dir{std::get(x.t)}; @@ -905,6 +966,14 @@ void OmpStructureChecker::Leave( const parser::OpenMPSimpleStandaloneConstruct &) { + switch (GetContext().directive) { + case llvm::omp::Directive::OMPD_ordered: + // [5.1] 2.19.9 Ordered Construct Restriction + ChecksOnOrderedAsStandalone(); + break; + default: + break; + } dirContext_.pop_back(); } Index: flang/lib/Semantics/resolve-directives.cpp =================================================================== --- flang/lib/Semantics/resolve-directives.cpp +++ flang/lib/Semantics/resolve-directives.cpp @@ -298,6 +298,9 @@ GetContext().withinConstruct = true; } + bool Pre(const parser::OpenMPSimpleStandaloneConstruct &); + void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPLoopConstruct &); void Post(const parser::OpenMPLoopConstruct &) { PopContext(); } void Post(const parser::OmpBeginLoopDirective &) { @@ -407,6 +410,20 @@ ResolveOmpNameList(alignedNameList, Symbol::Flag::OmpAligned); return false; } + bool Pre(const parser::OmpDependClause &x) { + if (const auto *dependSink{ + std::get_if(&x.u)}) { + const auto &dependSinkVec{dependSink->v}; + for (const auto &dependSinkElement : dependSinkVec) { + const auto &name{std::get(dependSinkElement.t)}; + if (!ResolveName(&name)) { + context_.Say( + name.source, "No type declared for '%s'"_err_en_US, name.source); + } + } + } + return false; + } void Post(const parser::Name &); // Keep track of labels in the statements that causes jumps to target labels @@ -1125,6 +1142,27 @@ PopContext(); } +bool OmpAttributeVisitor::Pre( + const parser::OpenMPSimpleStandaloneConstruct &x) { + const auto &standaloneDir{ + std::get(x.t)}; + switch (standaloneDir.v) { + case llvm::omp::Directive::OMPD_barrier: + case llvm::omp::Directive::OMPD_ordered: + case llvm::omp::Directive::OMPD_target_enter_data: + case llvm::omp::Directive::OMPD_target_exit_data: + case llvm::omp::Directive::OMPD_target_update: + case llvm::omp::Directive::OMPD_taskwait: + case llvm::omp::Directive::OMPD_taskyield: + PushContext(standaloneDir.source, standaloneDir.v); + break; + default: + break; + } + ClearDataSharingAttributeObjects(); + return true; +} + bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) { const auto &beginLoopDir{std::get(x.t)}; const auto &beginDir{std::get(beginLoopDir.t)}; Index: flang/test/Semantics/omp-clause-validity01.f90 =================================================================== --- flang/test/Semantics/omp-clause-validity01.f90 +++ flang/test/Semantics/omp-clause-validity01.f90 @@ -481,8 +481,6 @@ ! !$omp target enter data map(to:arrayA) map(alloc:arrayB) ! !$omp target update from(arrayA) to(arrayB) ! !$omp target exit data map(from:arrayA) map(delete:arrayB) - !$omp ordered depend(source) - ! !$omp ordered depend(sink:i-1) !$omp flush (c) !$omp flush acq_rel !$omp flush release Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -489,10 +489,12 @@ } def OMP_Ordered : Directive<"ordered"> { let allowedClauses = [ - VersionedClause, - VersionedClause, VersionedClause ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause + ]; } def OMP_Atomic : Directive<"atomic"> { let allowedClauses = [ Index: test/Semantics/omp-ordered01.f90 =================================================================== --- /dev/null +++ test/Semantics/omp-ordered01.f90 @@ -0,0 +1,83 @@ +! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp +! REQUIRES: shell + +! OpenMP Version 5.1 +! Check OpenMP construct validity for the following directives: +! 2.19.9 Ordered Construct + +program main + integer :: i, N = 10 + real :: a, arrayA(10), arrayB(10), arrayC(10) + real, external :: foo, bar, baz + + !$omp do ordered + do i = 1, N + !ERROR: At most one THREADS clause can appear on the ORDERED directive + !$omp ordered threads threads + arrayA(i) = i + !$omp end ordered + end do + !$omp end do + + !$omp simd + do i = 1, N + !ERROR: At most one SIMD clause can appear on the ORDERED directive + !$omp ordered simd simd + arrayA(i) = i + !$omp end ordered + end do + !$omp end simd + + !$omp do simd ordered + do i = 1, N + !ERROR: At most one SIMD clause can appear on the ORDERED directive + !$omp ordered simd simd + arrayA(i) = i + !$omp end ordered + end do + !$omp end do simd + + !$omp do ordered(1) + do i = 1, N + !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region + !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive + !$omp ordered depend(source) depend(inout: arrayA) depend(source) + arrayA(i) = foo(i) + !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive + !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive + !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive + !$omp ordered depend(sink: i - 1) depend(source) depend(source) + arrayB(i) = bar(arrayA(i), arrayB(i-1)) + !ERROR: No type declared for 'undecvar' + !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region + !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region + !$omp ordered depend(sink: undecvar - 1) depend(out: arrayC) depend(in: arrayB) + arrayC(i) = baz(arrayB(i-1)) + end do + !$omp end do + + !$omp do ordered(1) + do i = 1, N + !ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region + !$omp ordered depend(source) + arrayA(i) = foo(i) + !$omp end ordered + !ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(arrayA(i), arrayB(i-1)) + !$omp end ordered + end do + !$omp end do + +contains + subroutine work1() + !ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region + !$omp ordered simd + end subroutine work1 + + subroutine work2() + !ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region + !$omp ordered threads + end subroutine work2 + +end program main