Index: flang/lib/Semantics/check-directive-structure.h =================================================================== --- flang/lib/Semantics/check-directive-structure.h +++ flang/lib/Semantics/check-directive-structure.h @@ -267,6 +267,15 @@ return nullptr; } + // Check if the given clause is present in the given context + const PC *FindClause(DirectiveContext &context, C type) { + auto it{context.clauseInfo.find(type)}; + if (it != context.clauseInfo.end()) { + return it->second; + } + return nullptr; + } + std::pair FindClauses(C type) { auto it{GetContext().clauseInfo.equal_range(type)}; Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -235,7 +235,6 @@ void CheckCancellationNest( const parser::CharBlock &source, const parser::OmpCancelType::Type &type); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); - void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); bool CheckReductionOperators(const parser::OmpClause::Reduction &); bool CheckIntrinsicOperator( const parser::DefinedOperator::IntrinsicOperator &); @@ -244,6 +243,7 @@ void ChecksOnOrderedAsBlock(); void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x); void ChecksOnOrderedAsStandalone(); + void CheckOrderedDependClause(std::optional orderedValue); 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 @@ -673,7 +673,6 @@ } if (CurrentDirectiveIsNested()) { - CheckIfDoOrderedClause(beginDir); if (llvm::omp::teamSet.test(GetContextParent().directive)) { HasInvalidTeamsNesting(beginDir.v, beginDir.source); } @@ -740,27 +739,6 @@ } } -void OmpStructureChecker::CheckIfDoOrderedClause( - const parser::OmpBlockDirective &blkDirective) { - if (blkDirective.v == llvm::omp::OMPD_ordered) { - // Loops - if (llvm::omp::doSet.test(GetContextParent().directive) && - !FindClauseParent(llvm::omp::Clause::OMPC_ordered)) { - context_.Say(blkDirective.source, - "The ORDERED clause must be present on the loop" - " construct if any ORDERED region ever binds" - " to a loop region arising from the loop construct."_err_en_US); - } - // Other disallowed nestings, these directives do not support - // ordered clause in them, so no need to check - else if (IsCloselyNestedRegion(llvm::omp::nestedOrderedErrSet)) { - context_.Say(blkDirective.source, - "`ORDERED` region may not be closely nested inside of " - "`CRITICAL`, `ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US); - } - } -} - void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { if (GetDirectiveNest(TargetBlockOnlyTeams)) { ExitDirectiveNest(TargetBlockOnlyTeams); @@ -776,6 +754,69 @@ context_.Say(GetContext().clauseSource, "DEPEND(*) clauses are not allowed when ORDERED construct is a block" " construct with an ORDERED region"_err_en_US); + return; + } + + OmpDirectiveSet notAllowedParallelSet{llvm::omp::Directive::OMPD_parallel, + llvm::omp::Directive::OMPD_target_parallel, + llvm::omp::Directive::OMPD_parallel_sections, + llvm::omp::Directive::OMPD_parallel_workshare}; + bool isNestedInDo = false; + bool isNestedInDoSIMD = false; + bool isNestedInSIMD = false; + bool noOrderedClause = false; + bool isOrderedClauseWithPara = false; + bool isCloselyNestedRegion = true; + if (CurrentDirectiveIsNested()) { + for (int i = (int)dirContext_.size() - 2; i >= 0; i--) { + if (llvm::omp::doSet.test(dirContext_[i].directive)) { + isNestedInDo = true; + if (llvm::omp::doSimdSet.test(dirContext_[i].directive)) + isNestedInDoSIMD = true; + if (const auto *clause{ + FindClause(dirContext_[i], llvm::omp::Clause::OMPC_ordered)}) { + const auto &orderedClause{ + std::get(clause->u)}; + const auto orderedValue{GetIntValue(orderedClause.v)}; + if (orderedValue > 0) + isOrderedClauseWithPara = true; + } else { + noOrderedClause = true; + } + break; + } + if (llvm::omp::simdSet.test(dirContext_[i].directive)) { + isNestedInSIMD = true; + break; + } + if (llvm::omp::nestedOrderedErrSet.test(dirContext_[i].directive)) + context_.Say(GetContext().directiveSource, + "`ORDERED` region may not be closely nested inside of `CRITICAL`, " + "`ORDERED`, explicit `TASK` or `TASKLOOP` region."_err_en_US); + if (notAllowedParallelSet.test(dirContext_[i].directive)) { + isCloselyNestedRegion = false; + break; + } + } + } + + if (!isCloselyNestedRegion) { + context_.Say(GetContext().directiveSource, + "An ORDERED directive without the DEPEND clause must be closely nested " + "in a SIMD, worksharing-loop, or worksharing-loop SIMD " + "region"_err_en_US); + } else { + if (CurrentDirectiveIsNested() && + FindClause(llvm::omp::Clause::OMPC_simd) && + (!isNestedInDoSIMD && !isNestedInSIMD)) + context_.Say(GetContext().directiveSource, + "An ORDERED directive with SIMD clause must be closely nested in a " + "SIMD or worksharing-loop SIMD region"_err_en_US); + if (isNestedInDo && (noOrderedClause || isOrderedClauseWithPara)) + context_.Say(GetContext().directiveSource, + "An ORDERED directive without the DEPEND clause must be closely " + "nested in a worksharing-loop (or worksharing-loop SIMD) region with " + "ORDERED clause without the parameter"_err_en_US); } } @@ -1025,6 +1066,48 @@ "region"_err_en_US); } } + + OmpDirectiveSet allowedDoSet{llvm::omp::Directive::OMPD_do, + llvm::omp::Directive::OMPD_parallel_do, + llvm::omp::Directive::OMPD_target_parallel_do}; + bool isNestedInDoOrderedWithPara = false; + if (CurrentDirectiveIsNested() && + allowedDoSet.test(GetContextParent().directive)) { + if (const auto *clause{ + FindClause(GetContextParent(), llvm::omp::Clause::OMPC_ordered)}) { + const auto &orderedClause{ + std::get(clause->u)}; + const auto orderedValue{GetIntValue(orderedClause.v)}; + if (orderedValue > 0) { + isNestedInDoOrderedWithPara = true; + CheckOrderedDependClause(orderedValue); + } + } + } + + if (FindClause(llvm::omp::Clause::OMPC_depend) && + !isNestedInDoOrderedWithPara) + context_.Say(GetContext().clauseSource, + "An ORDERED construct with the DEPEND clause must be closely nested " + "in a worksharing-loop (or parallel worksharing-loop) construct with " + "ORDERED clause with a parameter"_err_en_US); +} + +void OmpStructureChecker::CheckOrderedDependClause( + std::optional orderedValue) { + 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 (const auto *sinkVectors{ + std::get_if(&dependClause.v.u)}) { + std::int64_t numVar = sinkVectors->v.size(); + if (orderedValue != numVar) + context_.Say(itr->second->source, + "The number of variables in DEPEND(SINK: vec) clause does not " + "match the parameter specified in ORDERED clause"_err_en_US); + } + } } void OmpStructureChecker::Enter( Index: flang/test/Semantics/omp-do-ordered-positivecases.f90 =================================================================== --- flang/test/Semantics/omp-do-ordered-positivecases.f90 +++ flang/test/Semantics/omp-do-ordered-positivecases.f90 @@ -33,6 +33,7 @@ !$omp do ordered(1) !DEF: /omp_doordered/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) do i=1,10 + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered !REF: /omp_doordered/j do j=1,10 @@ -56,6 +57,7 @@ !$omp do ordered(1) collapse(1) !DEF: /omp_doordered/Block5/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) do i=1,10 + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered !DEF: /omp_doordered/Block5/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) do j=1,10 Index: flang/test/Semantics/omp-do-ordered.f90 =================================================================== --- flang/test/Semantics/omp-do-ordered.f90 +++ flang/test/Semantics/omp-do-ordered.f90 @@ -27,6 +27,7 @@ !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. !$omp do ordered(2) do i = 1,10 + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered do j = 1, 10 print *, "hello" @@ -48,6 +49,7 @@ !ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct. !$omp do ordered(2) collapse(1) do i = 1,10 + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered do j = 1, 10 print *, "hello" Index: flang/test/Semantics/omp-do06.f90 =================================================================== --- flang/test/Semantics/omp-do06.f90 +++ flang/test/Semantics/omp-do06.f90 @@ -9,7 +9,7 @@ !$omp do do i = 1, 10 - !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered call my_func() !$omp end ordered @@ -21,7 +21,7 @@ !$omp parallel do do j = 1, 10 print *,i - !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$omp ordered print *,i !$omp end ordered Index: flang/test/Semantics/omp-ordered-simd.f90 =================================================================== --- flang/test/Semantics/omp-ordered-simd.f90 +++ flang/test/Semantics/omp-ordered-simd.f90 @@ -26,7 +26,7 @@ DO I = 1,N IF (I <= 10) THEN !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause. - !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$OMP ORDERED CALL WORK(I) !$OMP END ORDERED @@ -37,7 +37,7 @@ !$OMP PARALLEL DO DO I = 1,N IF (I <= 10) THEN - !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter !$OMP ORDERED CALL WORK(I) !$OMP END ORDERED Index: flang/test/Semantics/omp-ordered02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-ordered02.f90 @@ -0,0 +1,137 @@ +! RUN: %python %S/test_errors.py %s %flang -fopenmp +! OpenMP Version 5.1 +! Check OpenMP construct validity for the following directives: +! 2.19.9 Ordered Construct + +subroutine sub1() + integer :: i, j, N = 10 + real :: arrayA(10), arrayB(10) + real, external :: foo, bar + + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + + !$omp ordered threads + arrayA(i) = foo(i) + !$omp end ordered + + !$omp ordered simd + arrayA(i) = foo(i) + !$omp end ordered + + !$omp sections + do i = 1, N + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end sections + + !$omp sections + do i = 1, N + !ERROR: An ORDERED directive with SIMD clause must be closely nested in a SIMD or worksharing-loop SIMD region + !$omp ordered simd + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end sections + + !$omp do ordered + do i = 1, N + !$omp parallel + do j = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a SIMD, worksharing-loop, or worksharing-loop SIMD region + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end parallel + end do + !$omp end do + + !$omp do ordered + do i = 1, N + !$omp target parallel + do j = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a SIMD, worksharing-loop, or worksharing-loop SIMD region + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end target parallel + end do + !$omp end do + + !$omp do + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end do + + !$omp do + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered threads + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end do + + !$omp do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end do + + !$omp do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered threads + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end do + + !$omp parallel do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end parallel do + + !$omp parallel do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered threads + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end parallel do + + !$omp target parallel do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end target parallel do + + !$omp target parallel do ordered(1) + do i = 1, N + !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter + !$omp ordered threads + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end target parallel do +end Index: flang/test/Semantics/omp-ordered03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-ordered03.f90 @@ -0,0 +1,122 @@ +! RUN: %python %S/test_errors.py %s %flang -fopenmp +! OpenMP Version 5.1 +! Check OpenMP construct validity for the following directives: +! 2.19.9 Ordered Construct + +subroutine sub1() + integer :: i, j, N = 10 + real :: arrayA(10), arrayB(10) + real, external :: foo, bar + + !$omp do ordered(1) + do i = 1, N + !$omp ordered depend(source) + arrayA(i) = foo(i) + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end do + + !$omp do ordered(1) + do i = 1, N + !$omp target + do j = 1, N + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + arrayA(i) = foo(i) + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end target + end do + !$omp end do + + !$omp target + !$omp parallel do ordered(1) + do i = 1, N + !$omp ordered depend(source) + arrayA(i) = foo(i) + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end parallel do + !$omp end target + + !$omp target parallel do ordered(1) + do i = 1, N + !$omp ordered depend(source) + arrayA(i) = foo(i) + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end target parallel do + + !$omp target teams distribute parallel do ordered(1) + do i = 1, N + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + arrayA(i) = foo(i) + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end target teams distribute parallel do + + !$omp do ordered + do i = 1, N + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + arrayA(i) = foo(i) + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end do + + !$omp parallel do ordered + do i = 1, N + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + arrayA(i) = foo(i) + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end parallel do + + !$omp target parallel do ordered + do i = 1, N + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + arrayA(i) = foo(i) + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) + arrayB(i) = bar(i - 1) + end do + !$omp end target parallel do + + !$omp do ordered(1) + do i = 1, N + !ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause + !$omp ordered depend(sink: i - 1) depend(sink: i - 1, j) + arrayB(i) = bar(i - 1, j) + end do + !$omp end do + + !$omp do ordered(2) + do i = 1, N + do j = 1, N + !ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause + !$omp ordered depend(sink: i - 1) depend(sink: i - 1, j) + arrayB(i) = foo(i - 1) + bar(i - 1, j) + end do + end do + !$omp end do + + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(source) + + !ERROR: An ORDERED construct with the DEPEND clause must be closely nested in a worksharing-loop (or parallel worksharing-loop) construct with ORDERED clause with a parameter + !$omp ordered depend(sink: i - 1) +end