diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h --- a/flang/lib/Semantics/check-directive-structure.h +++ b/flang/lib/Semantics/check-directive-structure.h @@ -250,9 +250,12 @@ } // Check if the given clause is present in the current context - const PC *FindClause(C type) { - auto it{GetContext().clauseInfo.find(type)}; - if (it != GetContext().clauseInfo.end()) { + const PC *FindClause(C type) { return FindClause(GetContext(), type); } + + // 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; 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 @@ -241,7 +241,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 &); @@ -250,6 +249,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); 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 @@ -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,68 @@ 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::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); + break; + } else if (llvm::omp::doSet.test(dirContext_[i].directive)) { + isNestedInDo = true; + isNestedInDoSIMD = llvm::omp::doSimdSet.test(dirContext_[i].directive); + 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)}; + isOrderedClauseWithPara = orderedValue > 0; + } else { + noOrderedClause = true; + } + break; + } else if (llvm::omp::simdSet.test(dirContext_[i].directive)) { + isNestedInSIMD = true; + break; + } else 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); + } } } @@ -1063,6 +1103,50 @@ "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( diff --git a/flang/test/Semantics/omp-do-ordered-positivecases.f90 b/flang/test/Semantics/omp-do-ordered-positivecases.f90 --- a/flang/test/Semantics/omp-do-ordered-positivecases.f90 +++ b/flang/test/Semantics/omp-do-ordered-positivecases.f90 @@ -30,7 +30,7 @@ end do end do - !$omp do ordered(1) + !$omp do ordered !DEF: /omp_doordered/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) do i=1,10 !$omp ordered @@ -53,7 +53,7 @@ !$omp end do !$omp parallel num_threads(4) - !$omp do ordered(1) collapse(1) + !$omp do ordered collapse(1) !DEF: /omp_doordered/Block5/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) do i=1,10 !$omp ordered diff --git a/flang/test/Semantics/omp-do-ordered.f90 b/flang/test/Semantics/omp-do-ordered.f90 --- a/flang/test/Semantics/omp-do-ordered.f90 +++ b/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" diff --git a/flang/test/Semantics/omp-do06.f90 b/flang/test/Semantics/omp-do06.f90 --- a/flang/test/Semantics/omp-do06.f90 +++ b/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 diff --git a/flang/test/Semantics/omp-ordered-simd.f90 b/flang/test/Semantics/omp-ordered-simd.f90 --- a/flang/test/Semantics/omp-ordered-simd.f90 +++ b/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 diff --git a/flang/test/Semantics/omp-ordered02.f90 b/flang/test/Semantics/omp-ordered02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-ordered02.f90 @@ -0,0 +1,146 @@ +! 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 do ordered + do i = 1, N + arrayB(i) = bar(i) + !$omp ordered + arrayA(i) = foo(i) + !$omp end ordered + end do + !$omp end do + + !$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 diff --git a/flang/test/Semantics/omp-ordered03.f90 b/flang/test/Semantics/omp-ordered03.f90 new file mode 100644 --- /dev/null +++ b/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