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, @@ -167,6 +174,8 @@ bool HasInvalidWorksharingNesting( const parser::CharBlock &, const OmpDirectiveSet &); bool IsCloselyNestedRegion(const OmpDirectiveSet &set); + void HasInvalidTeamsNesting(const parser::OpenMPConstruct &x); + 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 @@ -182,8 +182,94 @@ return false; } -void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) { +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::OpenMPConstruct &c) { + // Only ‘distribute’ or ‘parallel’ regions are allowed to be strictly nested + // inside ‘teams’ region + + bool eligibleTeams{false}; + OmpDirectiveSet allowedSet{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, + 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}; + + std::visit(Fortran::common::visitors{ + [&](const parser::OpenMPBlockConstruct &c) { + const auto &beginBlockDir{ + std::get(c.t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if (allowedSet.test(beginDir.v)) { + eligibleTeams = true; + } + }, + [&](const parser::OpenMPLoopConstruct &c) { + const auto &beginLoopDir{ + std::get(c.t)}; + const auto &beginDir{ + std::get(beginLoopDir.t)}; + if (allowedSet.test(beginDir.v)) { + eligibleTeams = true; + } + }, + [&](const auto &c) {}, + }, + c.u); + if (!eligibleTeams) { + context_.Say(parser::FindSourceLocation(c), + "Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region."_err_en_US); + } +} + +void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) { // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check + if (dirContext_.size() >= 1) { + if (llvm::omp::teamSet.test(GetContext().directive)) { + HasInvalidTeamsNesting(x); + } + } } void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { @@ -233,6 +319,7 @@ CheckDoWhile(x); CheckLoopItrVariableIsInt(x); CheckCycleConstraints(x); + HasInvalidDistributeNesting(x); } const parser::Name OmpStructureChecker::GetLoopIndex( const parser::DoConstruct *x) { 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,106 @@ +! 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 teams + do i = 1, N + !ERROR: Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region. + !$omp task + do k = 1, N + a = 3.14 + enddo + !$omp end task + enddo + !$omp end teams + + !$omp teams + do i = 1, N + !$omp parallel + do k = 1, N + a = 3.14 + enddo + !$omp end parallel + enddo + !$omp end teams + + !$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