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 @@ -209,6 +209,12 @@ int GetSIMDNest() { return simdNest_; } + void EnterTargetBlockOnlyTeams() { targetBlockOnlyTeams_ = true; } + + void ExitTargetBlockOnlyTeams() { targetBlockOnlyTeams_ = false; } + + bool GetTargetBlockOnlyTeams() { return targetBlockOnlyTeams_; } + // Check if the given clause is present in the current context const PC *FindClause(C type) { auto it{GetContext().clauseInfo.find(type)}; @@ -321,6 +327,7 @@ std::string ClauseSetToString(const common::EnumSet set); int simdNest_{0}; + bool targetBlockOnlyTeams_{false}; }; template 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 @@ -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); 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 @@ -625,11 +625,36 @@ 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 && + GetContextParent().directive != llvm::omp::Directive::OMPD_teams) { + 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 && + !GetTargetBlockOnlyTeams()) { + context_.Say(GetContextParent().directiveSource, + "TARGET construct with nested TEAMS region contains statements " + "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)) { + EnterTargetBlockOnlyTeams(); + } + break; case llvm::omp::OMPD_workshare: case llvm::omp::OMPD_parallel_workshare: CheckWorkshareBlockStmts(block, beginDir.source); @@ -683,6 +708,9 @@ } void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) { + if (GetContext().directive == llvm::omp::Directive::OMPD_target) { + ExitTargetBlockOnlyTeams(); + } dirContext_.pop_back(); } @@ -1790,6 +1818,31 @@ } } +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; + } else { + return false; + } +} + void OmpStructureChecker::CheckWorkshareBlockStmts( const parser::Block &block, parser::CharBlock source) { OmpWorkshareBlockChecker ompWorkshareBlockChecker{context_, source}; diff --git a/flang/test/Semantics/omp-teams01.f90 b/flang/test/Semantics/omp-teams01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-teams01.f90 @@ -0,0 +1,112 @@ +! 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 parallelregion 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 parallelregion 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 parallelregion 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 parallelregion 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 parallelregion 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. + !$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 parallelregion or TARGET region + !$omp teams + a = 3.14 + !$omp end teams + !$omp end target teams + + !ERROR: TARGET construct with nested TEAMS region contains statements 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 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 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 outside of the TEAMS construct + !$omp target + !$omp teams + a = 3.14 + !$omp end teams + c = 3.14 + !$omp end target + +end program main