Index: flang/lib/Semantics/check-directive-structure.h =================================================================== --- flang/lib/Semantics/check-directive-structure.h +++ flang/lib/Semantics/check-directive-structure.h @@ -203,6 +203,12 @@ 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)}; @@ -314,6 +320,7 @@ 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 @@ -215,6 +215,7 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + void CheckSIMDNest(const parser::OpenMPConstruct &x); std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x); void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv); bool CheckReductionOperators(const parser::OmpClause::Reduction &); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -238,7 +238,16 @@ } void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) { - // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check + // Simd Construct with Ordered Construct Nesting check + // We cannot use CurrentDirectiveIsNested() here because + // PushContextAndClauseSets() has not been called yet, it is + // called individually for each construct. Therefore a + // dirContext_ size `1` means the current construct is nested + if (dirContext_.size() >= 1) { + if (GetSIMDNest() > 0) { + CheckSIMDNest(x); + } + } } void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { @@ -255,6 +264,9 @@ } PushContextAndClauseSets(beginDir.source, beginDir.v); + if (llvm::omp::simdSet.test(GetContext().directive)) { + EnterSIMDNest(); + } if (beginDir.v == llvm::omp::Directive::OMPD_do) { // 2.7.1 do-clause -> private-clause | @@ -344,6 +356,78 @@ } } +void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) { + // Check the following: + // 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. + // TODO: Expand the check to include `LOOP` construct as well when it is + // supported. + + // Check if the parent context has the SIMD clause + // Please note that we use GetContext() instead of GetContextParent() + // because PushContextAndClauseSets() has not been called on the + // current context yet. + // TODO: Check for declare simd regions. + bool eligibleSIMD{false}; + std::visit(Fortran::common::visitors{ + // Allow `!$OMP ORDERED SIMD` + [&](const parser::OpenMPBlockConstruct &c) { + const auto &beginBlockDir{ + std::get(c.t)}; + const auto &beginDir{ + std::get(beginBlockDir.t)}; + if (beginDir.v == llvm::omp::Directive::OMPD_ordered) { + const auto &clauses{ + std::get(beginBlockDir.t)}; + for (const auto &clause : clauses.v) { + if (std::get_if(&clause.u)) { + eligibleSIMD = true; + break; + } + } + } + }, + [&](const parser::OpenMPSimpleStandaloneConstruct &c) { + const auto &dir{ + std::get(c.t)}; + if (dir.v == llvm::omp::Directive::OMPD_ordered) { + const auto &clauses{std::get(c.t)}; + for (const auto &clause : clauses.v) { + if (std::get_if(&clause.u)) { + eligibleSIMD = true; + break; + } + } + } + }, + // Allowing SIMD construct + [&](const parser::OpenMPLoopConstruct &c) { + const auto &beginLoopDir{ + std::get(c.t)}; + const auto &beginDir{ + std::get(beginLoopDir.t)}; + if ((beginDir.v == llvm::omp::Directive::OMPD_simd) || + (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) { + eligibleSIMD = true; + } + }, + [&](const parser::OpenMPAtomicConstruct &c) { + // Allow `!$OMP ATOMIC` + eligibleSIMD = true; + }, + [&](const auto &c) {}, + }, + c.u); + if (!eligibleSIMD) { + context_.Say(parser::FindSourceLocation(c), + "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."_err_en_US); + } +} + std::int64_t OmpStructureChecker::GetOrdCollapseLevel( const parser::OpenMPLoopConstruct &x) { const auto &beginLoopDir{std::get(x.t)}; @@ -382,6 +466,9 @@ } void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) { + if (llvm::omp::simdSet.test(GetContext().directive)) { + ExitSIMDNest(); + } dirContext_.pop_back(); } Index: flang/test/Semantics/omp-do05.f90 =================================================================== --- flang/test/Semantics/omp-do05.f90 +++ flang/test/Semantics/omp-do05.f90 @@ -31,6 +31,7 @@ !$omp parallel do simd do i=1,10 + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region !$omp single do j=1,10 @@ -55,6 +56,7 @@ !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region. !$omp distribute parallel do simd do i=1,10 + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region !$omp single do j=1,10 @@ -77,6 +79,7 @@ !$omp target parallel do simd do i=1,10 + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region !$omp single do j=1,10 @@ -97,8 +100,9 @@ end do !$omp end target teams distribute parallel do - !$omp target teams distribute parallel do simd + !$omp target teams distribute parallel do simd do i=1,10 + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region !$omp single do j=1,10 Index: flang/test/Semantics/omp-nested-simd.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-nested-simd.f90 @@ -0,0 +1,214 @@ +! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp +! OpenMP Version 4.5 +! Various checks with the nesting of SIMD construct + +SUBROUTINE NESTED_GOOD(N) + INTEGER N, I, J, K, A(10), B(10) + !$OMP SIMD + DO I = 1,N + !$OMP ATOMIC + K = K + 1 + IF (I <= 10) THEN + !$OMP ORDERED SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END ORDERED + ENDIF + END DO + !$OMP END SIMD + + !$OMP SIMD + DO I = 1,N + IF (I <= 10) THEN + !$OMP SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END SIMD + ENDIF + END DO + !$OMP END SIMD +END SUBROUTINE NESTED_GOOD + +SUBROUTINE NESTED_BAD(N) + INTEGER N, I, J, K, A(10), B(10) + + !$OMP SIMD + DO I = 1,N + IF (I <= 10) THEN + !$OMP ORDERED SIMD + 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. + !$omp teams + DO K = 1,N + print *, 'Hello' + END DO + !$omp end teams + END DO + !$OMP END ORDERED + ENDIF + END DO + !$OMP END SIMD + + !$OMP SIMD + DO I = 1,N + !$OMP ATOMIC + K = K + 1 + IF (I <= 10) THEN + !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 task + do J = 1, N + K = 2 + 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 + end do + !$omp end target + !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 DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !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 PARALLEL DO + DO J = 1,N + A(J) = J + END DO + !$OMP END PARALLEL DO + ENDIF + END DO + !$OMP END SIMD + + !$OMP DO SIMD + DO I = 1,N + !$OMP ATOMIC + K = K + 1 + IF (I <= 10) THEN + !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 task + do J = 1, N + K = 2 + 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 + end do + !$omp end target + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !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 PARALLEL DO + DO J = 1,N + A(J) = J + END DO + !$OMP END PARALLEL DO + ENDIF + END DO + !$OMP END DO SIMD + + !$OMP PARALLEL DO SIMD + DO I = 1,N + !$OMP ATOMIC + K = K + 1 + IF (I <= 10) THEN + !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 task + do J = 1, N + K = 2 + 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 + end do + !$omp end target + !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: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !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 PARALLEL DO + DO J = 1,N + A(J) = J + END DO + !$OMP END PARALLEL DO + ENDIF + END DO + !$OMP END PARALLEL DO SIMD + + !$OMP TARGET SIMD + DO I = 1,N + !$OMP ATOMIC + K = K + 1 + IF (I <= 10) THEN + !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 task + do J = 1, N + K = 2 + 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 + end do + !$omp end target + !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 DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !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 PARALLEL DO + DO J = 1,N + A(J) = J + END DO + !$OMP END PARALLEL DO + ENDIF + END DO + !$OMP END TARGET SIMD + + +END SUBROUTINE NESTED_BAD Index: flang/test/Semantics/omp-ordered-simd.f90 =================================================================== --- flang/test/Semantics/omp-ordered-simd.f90 +++ flang/test/Semantics/omp-ordered-simd.f90 @@ -25,6 +25,7 @@ !$OMP DO SIMD DO I = 1,N IF (I <= 10) THEN + !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: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct. !$OMP ORDERED CALL WORK(I)