Index: flang/lib/Semantics/check-directive-structure.h =================================================================== --- flang/lib/Semantics/check-directive-structure.h +++ flang/lib/Semantics/check-directive-structure.h @@ -203,12 +203,6 @@ GetContext().actualClauses.push_back(type); } - void EnterSIMDNest() { simdNest_++; } - - void ExitSIMDNest() { simdNest_--; } - - int GetSIMDNest() { return simdNest_; } - // Check if the given clause is present in the current context const PC *FindClause(C type) { auto it{GetContext().clauseInfo.find(type)}; @@ -320,7 +314,6 @@ directiveClausesMap_; std::string ClauseSetToString(const common::EnumSet set); - int simdNest_{0}; }; template Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -218,6 +218,7 @@ void SetLoopInfo(const parser::OpenMPLoopConstruct &x); void CheckIsLoopIvPartOfClause( llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); + bool CheckTargetBlockOnlyTeams(const parser::Block &); void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); @@ -246,6 +247,12 @@ void CheckPredefinedAllocatorRestriction( const parser::CharBlock &source, const parser::Name &name); bool isPredefinedAllocator{false}; + void EnterDirectiveNest(const int index) { directiveNest_[index]++; } + void ExitDirectiveNest(const int index) { directiveNest_[index]--; } + int GetDirectiveNest(const int index) { return directiveNest_[index]; } + + int directiveNest_[3] = {0}; + enum directiveNestType { SIMDNest, TargetBlockOnlyTeams, LastType }; }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -285,7 +285,7 @@ // called individually for each construct. Therefore a // dirContext_ size `1` means the current construct is nested if (dirContext_.size() >= 1) { - if (GetSIMDNest() > 0) { + if (GetDirectiveNest(SIMDNest) > 0) { CheckSIMDNest(x); } } @@ -306,7 +306,7 @@ PushContextAndClauseSets(beginDir.source, beginDir.v); if (llvm::omp::simdSet.test(GetContext().directive)) { - EnterSIMDNest(); + EnterDirectiveNest(SIMDNest); } if (beginDir.v == llvm::omp::Directive::OMPD_do) { @@ -585,7 +585,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { if (llvm::omp::simdSet.test(GetContext().directive)) { - ExitSIMDNest(); + ExitDirectiveNest(SIMDNest); } dirContext_.pop_back(); } @@ -625,11 +625,35 @@ if (GetContext().directive == llvm::omp::Directive::OMPD_master) { CheckMasterNesting(x); } + // A teams region can only be strictly nested within the implicit parallel + // region or a target region. + if (GetContext().directive == llvm::omp::Directive::OMPD_teams && + GetContextParent().directive != llvm::omp::Directive::OMPD_target) { + context_.Say(parser::FindSourceLocation(x), + "%s region can only be strictly nested within the implicit parallel " + "region or TARGET region"_err_en_US, + ContextDirectiveAsFortran()); + } + // If a teams construct is nested within a target construct, that target + // construct must contain no statements, declarations or directives outside + // of the teams construct. + if (GetContext().directive == llvm::omp::Directive::OMPD_teams && + GetContextParent().directive == llvm::omp::Directive::OMPD_target && + !GetDirectiveNest(TargetBlockOnlyTeams)) { + context_.Say(GetContextParent().directiveSource, + "TARGET construct with nested TEAMS region contains statements or " + "directives outside of the TEAMS construct"_err_en_US); + } } CheckNoBranching(block, beginDir.v, beginDir.source); switch (beginDir.v) { + case llvm::omp::Directive::OMPD_target: + if (CheckTargetBlockOnlyTeams(block)) { + EnterDirectiveNest(TargetBlockOnlyTeams); + } + break; case llvm::omp::OMPD_workshare: case llvm::omp::OMPD_parallel_workshare: CheckWorkshareBlockStmts(block, beginDir.source); @@ -683,6 +707,9 @@ } void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { + if (GetDirectiveNest(TargetBlockOnlyTeams)) { + ExitDirectiveNest(TargetBlockOnlyTeams); + } dirContext_.pop_back(); } @@ -1790,6 +1817,30 @@ } } +bool OmpStructureChecker::CheckTargetBlockOnlyTeams( + const parser::Block &block) { + bool nestedTeams{false}; + auto it{block.begin()}; + + if (const auto *ompConstruct{parser::Unwrap(*it)}) { + if (const auto *ompBlockConstruct{ + std::get_if(&ompConstruct->u)}) { + const auto &beginBlockDir{ + std::get(ompBlockConstruct->t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if (beginDir.v == llvm::omp::Directive::OMPD_teams) { + nestedTeams = true; + } + } + } + + if (nestedTeams && ++it == block.end()) { + return true; + } + return false; +} + void OmpStructureChecker::CheckWorkshareBlockStmts( const parser::Block &block, parser::CharBlock source) { OmpWorkshareBlockChecker ompWorkshareBlockChecker{context_, source}; Index: flang/test/Semantics/omp-firstprivate01.f90 =================================================================== --- flang/test/Semantics/omp-firstprivate01.f90 +++ flang/test/Semantics/omp-firstprivate01.f90 @@ -12,6 +12,7 @@ a = 10 b = 20 + !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct !$omp target !$omp teams private(a, b) !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context Index: flang/test/Semantics/omp-nested-master.f90 =================================================================== --- flang/test/Semantics/omp-nested-master.f90 +++ flang/test/Semantics/omp-nested-master.f90 @@ -87,6 +87,7 @@ !$omp ordered do i = 1, 10 + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams !$omp distribute do k =1, 10 @@ -102,6 +103,7 @@ !$omp critical do i = 1, 10 + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams !$omp distribute do k =1, 10 @@ -117,6 +119,7 @@ !$omp taskloop do i = 1, 10 + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams !$omp distribute do k =1, 10 @@ -133,6 +136,7 @@ !$omp task do i = 1, 10 + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams !$omp distribute do k =1, 10 Index: flang/test/Semantics/omp-nested-simd.f90 =================================================================== --- flang/test/Semantics/omp-nested-simd.f90 +++ flang/test/Semantics/omp-nested-simd.f90 @@ -42,6 +42,7 @@ DO J = 1,N print *, "Hi" !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: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region !$omp teams DO K = 1,N print *, 'Hello' @@ -65,12 +66,6 @@ end do !$omp end task !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. - !$omp teams - do J = 1, N - K = 2 - end do - !$omp end teams - !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. !$omp target do J = 1, N K = 2 @@ -104,12 +99,6 @@ end do !$omp end task !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. - !$omp teams - do J = 1, N - K = 2 - end do - !$omp end teams - !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. !$omp target do J = 1, N K = 2 @@ -144,12 +133,6 @@ end do !$omp end task !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. - !$omp teams - do J = 1, N - K = 2 - end do - !$omp end teams - !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. !$omp target do J = 1, N K = 2 @@ -184,12 +167,6 @@ end do !$omp end task !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. - !$omp teams - do J = 1, N - K = 2 - end do - !$omp end teams - !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. !$omp target do J = 1, N K = 2 Index: flang/test/Semantics/omp-nested-teams.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-nested-teams.f90 @@ -0,0 +1,113 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! REQUIRES: shell + +! OpenMP Version 5.0 +! Check OpenMP construct validity for the following directives: +! 2.7 Teams Construct + +program main + integer :: i, j, N = 10 + real :: a, b, c + + !$omp teams + a = 3.14 + !$omp end teams + + !$omp target + !$omp teams + a = 3.14 + !$omp end teams + !$omp end target + + !$omp target + !$omp parallel + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end parallel + !$omp end target + + !$omp parallel + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end parallel + + !$omp do + do i = 1, N + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + end do + + !$omp master + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end master + + !$omp target parallel + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end target parallel + + !$omp target + !$omp teams + !ERROR: Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region. + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end teams + !$omp end target + + !$omp target teams + !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end target teams + + !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct + !$omp target + do i = 1, N + !$omp teams + a = 3.14 + !$omp end teams + enddo + !$omp end target + + !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct + !$omp target + if (i .GT. 1) then + if (j .GT. 1) then + !$omp teams + a = 3.14 + !$omp end teams + end if + end if + !$omp end target + + !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct + !$omp target + b = 3.14 + !$omp teams + a = 3.14 + !$omp end teams + !$omp end target + + !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct + !$omp target + !$omp teams + a = 3.14 + !$omp end teams + c = 3.14 + !$omp end target + +end program main