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,9 @@ bool HasInvalidWorksharingNesting( const parser::CharBlock &, const OmpDirectiveSet &); bool IsCloselyNestedRegion(const OmpDirectiveSet &set); + void HasInvalidTeamsNesting( + const llvm::omp::Directive &dir, const parser::CharBlock &source); + 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,7 +182,62 @@ 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 llvm::omp::Directive &dir, const parser::CharBlock &source) { + 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}; + + if (!allowedSet.test(dir)) { + context_.Say(source, + "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 } @@ -233,6 +288,11 @@ CheckDoWhile(x); CheckLoopItrVariableIsInt(x); CheckCycleConstraints(x); + HasInvalidDistributeNesting(x); + if (CurrentDirectiveIsNested() && + llvm::omp::teamSet.test(GetContextParent().directive)) { + HasInvalidTeamsNesting(beginDir.v, beginDir.source); + } } const parser::Name OmpStructureChecker::GetLoopIndex( const parser::DoConstruct *x) { @@ -366,8 +426,12 @@ HasInvalidWorksharingNesting( beginDir.source, {llvm::omp::Directive::OMPD_do}); } - if (CurrentDirectiveIsNested()) + if (CurrentDirectiveIsNested()) { CheckIfDoOrderedClause(beginDir); + if (llvm::omp::teamSet.test(GetContextParent().directive)) { + HasInvalidTeamsNesting(beginDir.v, beginDir.source); + } + } CheckNoBranching(block, beginDir.v, beginDir.source); 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