Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -71,6 +71,13 @@ Directive::OMPD_taskloop_simd, Directive::OMPD_teams_distribute_parallel_do_simd, Directive::OMPD_teams_distribute_simd}; +static OmpDirectiveSet teamSet{Directive::OMPD_teams, + Directive::OMPD_teams_distribute, + Directive::OMPD_teams_distribute_parallel_do, + Directive::OMPD_teams_distribute_parallel_do_simd, + Directive::OMPD_teams_distribute_parallel_for, + Directive::OMPD_teams_distribute_parallel_for_simd, + Directive::OMPD_teams_distribute_simd}; static OmpDirectiveSet taskGeneratingSet{ OmpDirectiveSet{Directive::OMPD_task} | taskloopSet}; static OmpDirectiveSet nestedOrderedErrSet{Directive::OMPD_critical, @@ -166,7 +173,9 @@ private: bool HasInvalidWorksharingNesting( const parser::CharBlock &, const OmpDirectiveSet &); - + void HasInvalidTeamsNesting( + const parser::OpenMPBlockConstruct &teamsConstruct); + void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); // specific clause related bool ScheduleModifierHasType(const parser::OmpScheduleClause &, const parser::OmpScheduleModifierType::ModType &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -141,6 +141,96 @@ return false; } +void OmpStructureChecker::HasInvalidDistributeNesting( + const parser::OpenMPLoopConstruct &x) { + bool violation = false; + + OmpDirectiveSet distributeSet{llvm::omp::Directive::OMPD_distribute, + llvm::omp::Directive::OMPD_distribute_parallel_do, + llvm::omp::Directive::OMPD_distribute_parallel_do_simd, + llvm::omp::Directive::OMPD_distribute_parallel_for, + llvm::omp::Directive::OMPD_distribute_parallel_for_simd, + llvm::omp::Directive::OMPD_distribute_simd}; + + const auto &beginLoopDir{std::get(x.t)}; + const auto &beginDir{std::get(beginLoopDir.t)}; + if (distributeSet.test(beginDir.v)) { + // `distribute` region has to be nested + if (!CurrentDirectiveIsNested()) { + violation = true; + } else { + // `distribute` region has to be strictly nested inside `teams` + if (!llvm::omp::teamSet.test(GetContextParent().directive)) { + violation = true; + } + } + } + if (violation) { + context_.Say(beginDir.source, + "`DISTRIBUTE` region has to be strictly nested inside `TEAMS` region."_err_en_US); + } +} + +void OmpStructureChecker::HasInvalidTeamsNesting( + const parser::OpenMPBlockConstruct &teamsConstruct) { + // Only ‘distribute’ or ‘parallel’ regions are allowed to be strictly nested + // inside ‘teams’ region + const auto &teamsBlock{std::get(teamsConstruct.t)}; + OmpDirectiveSet parallelAllowedSet{llvm::omp::Directive::OMPD_parallel, + llvm::omp::Directive::OMPD_parallel_do, + llvm::omp::Directive::OMPD_parallel_do_simd, + llvm::omp::Directive::OMPD_parallel_for, + llvm::omp::Directive::OMPD_parallel_for_simd, + llvm::omp::Directive::OMPD_parallel_master, + llvm::omp::Directive::OMPD_parallel_master_taskloop, + llvm::omp::Directive::OMPD_parallel_master_taskloop_simd, + llvm::omp::Directive::OMPD_parallel_sections, + llvm::omp::Directive::OMPD_parallel_workshare}; + + OmpDirectiveSet distributeAllowedSet{llvm::omp::Directive::OMPD_distribute, + llvm::omp::Directive::OMPD_distribute_parallel_do, + llvm::omp::Directive::OMPD_distribute_parallel_do_simd, + llvm::omp::Directive::OMPD_distribute_parallel_for, + llvm::omp::Directive::OMPD_distribute_parallel_for_simd, + llvm::omp::Directive::OMPD_distribute_simd}; + + for (auto it{teamsBlock.begin()}; it != teamsBlock.end(); ++it) { + if (const auto *ompConstruct{ + parser::Unwrap(*it)}) { + if (const auto *loopConstruct{ + std::get_if(&ompConstruct->u)}) { + const auto &beginLoopDir{ + std::get(loopConstruct->t)}; + const auto &beginDir{ + std::get(beginLoopDir.t)}; + + if ((!distributeAllowedSet.test(beginDir.v)) && + (!parallelAllowedSet.test(beginDir.v))) { + context_.Say(beginDir.source, + "Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region."_err_en_US); + } + + } else if (const auto *blockConstruct{ + std::get_if( + &ompConstruct->u)}) { + const auto &beginBlockDir{ + std::get(blockConstruct->t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if ((!distributeAllowedSet.test(beginDir.v)) && + (!parallelAllowedSet.test(beginDir.v))) { + context_.Say(beginDir.source, + "Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region."_err_en_US); + } + } else { + // Any other OpenMP construct will not be allowed + context_.Say(parser::FindSourceLocation(ompConstruct), + "Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region."_err_en_US); + } + } + } +} + void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) { // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check } @@ -192,6 +282,7 @@ CheckDoWhile(x); CheckLoopItrVariableIsInt(x); CheckCycleConstraints(x); + HasInvalidDistributeNesting(x); } const parser::Name OmpStructureChecker::GetLoopIndex( const parser::DoConstruct *x) { @@ -325,6 +416,10 @@ HasInvalidWorksharingNesting( beginDir.source, {llvm::omp::Directive::OMPD_do}); } + if (llvm::omp::teamSet.test(beginDir.v)) { + HasInvalidTeamsNesting(x); + } + if (CurrentDirectiveIsNested()) CheckIfDoOrderedClause(beginDir); Index: flang/test/Semantics/omp-combined-constructs.f90 =================================================================== --- flang/test/Semantics/omp-combined-constructs.f90 +++ flang/test/Semantics/omp-combined-constructs.f90 @@ -7,6 +7,7 @@ real(8) :: a(256), b(256) N = 256 + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. !$omp distribute simd do i = 1, N a(i) = 3.14 Index: flang/test/Semantics/omp-device-constructs.f90 =================================================================== --- flang/test/Semantics/omp-device-constructs.f90 +++ flang/test/Semantics/omp-device-constructs.f90 @@ -144,6 +144,7 @@ !$omp target exit data map(to:a) !$omp target + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. !$omp distribute do i = 1, N a = 3.14 @@ -152,6 +153,31 @@ !$omp end target !$omp target + !$omp teams + !$omp distribute + do i = 1, N + a = 3.14 + enddo + !$omp end distribute + !$omp end teams + !$omp end target + + !$omp target + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !ERROR: At most one COLLAPSE clause can appear on the DISTRIBUTE directive + !$omp distribute collapse(2) collapse(3) + do i = 1, N + do j = 1, N + do k = 1, N + a = 3.14 + enddo + enddo + enddo + !$omp end distribute + !$omp end target + + !$omp target + !$omp teams !ERROR: At most one COLLAPSE clause can appear on the DISTRIBUTE directive !$omp distribute collapse(2) collapse(3) do i = 1, N @@ -162,9 +188,11 @@ enddo enddo !$omp end distribute + !$omp end teams !$omp end target !$omp target + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. !$omp distribute dist_schedule(static, 2) do i = 1, N a = 3.14 @@ -173,6 +201,17 @@ !$omp end target !$omp target + !$omp teams + !$omp distribute dist_schedule(static, 2) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute + !$omp end teams + !$omp end target + + !$omp target + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. !ERROR: At most one DIST_SCHEDULE clause can appear on the DISTRIBUTE directive !$omp distribute dist_schedule(static, 2) dist_schedule(static, 3) do i = 1, N @@ -181,4 +220,15 @@ !$omp end distribute !$omp end target + !$omp target + !$omp teams + !ERROR: At most one DIST_SCHEDULE clause can appear on the DISTRIBUTE directive + !$omp distribute dist_schedule(static, 2) dist_schedule(static, 3) + do i = 1, N + a = 3.14 + enddo + !$omp end distribute + !$omp end teams + !$omp end target + end program main Index: flang/test/Semantics/omp-nested-distribute.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-nested-distribute.f90 @@ -0,0 +1,85 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! Check OpenMP clause validity for the following directives: +! 2.10 Device constructs +program main + + real(8) :: arrayA(256), arrayB(256) + integer :: N + + arrayA = 1.414 + arrayB = 3.14 + N = 256 + + !$omp task + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !$omp distribute + do i = 1, N + a = 3.14 + enddo + !$omp end distribute + !$omp end task + + !$omp parallel + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !$omp distribute + do i = 1, N + a = 3.14 + enddo + !$omp end distribute + !$omp end parallel + + !$omp teams + !ERROR: Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region. + !$omp target + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !$omp distribute + do i = 1, 10 + j = j + 1 + end do + !$omp end distribute + !$omp end target + !$omp end teams + + !$omp teams + !$omp parallel + do k = 1,10 + print *, "hello" + end do + !$omp end parallel + !$omp distribute firstprivate(a) + do i = 1, 10 + j = j + 1 + end do + !$omp end distribute + !$omp end teams + + !$omp teams + !ERROR: Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region. + !$omp task + do k = 1,10 + print *, "hello" + end do + !$omp end task + !$omp distribute firstprivate(a) + do i = 1, 10 + j = j + 1 + end do + !$omp end distribute + !$omp end teams + + !$omp task + !$omp parallel + do k = 1,10 + print *, "hello" + end do + !$omp end parallel + !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. + !$omp distribute firstprivate(a) + do i = 1, 10 + j = j + 1 + end do + !$omp end distribute + !$omp end task + + +end program main