Index: flang/lib/Semantics/check-directive-structure.h =================================================================== --- flang/lib/Semantics/check-directive-structure.h +++ flang/lib/Semantics/check-directive-structure.h @@ -221,6 +221,18 @@ return nullptr; } + // Check if a gven construct set is present anywhere in the context hierarchy + bool FindDirInWholeContext( + common::EnumSet + dirSet) { + for (unsigned int i = 0; i < dirContext_.size(); i++) { + if (dirSet.test(dirContext_[i].directive)) { + return true; + } + } + return false; + } + std::pair FindClauses(C type) { auto it{GetContext().clauseInfo.equal_range(type)}; Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -194,6 +194,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 @@ -182,8 +182,17 @@ return false; } -void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) { - // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check +void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) { + // 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 (FindDirInWholeContext(llvm::omp::simdSet)) { + CheckSIMDNest(x); + } + } } void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { @@ -292,6 +301,76 @@ } } +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. + + // Check if the parent context has the SIMD clause + // Please not 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)}; Index: flang/test/Semantics/omp-nested-simd.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-nested-simd.f90 @@ -0,0 +1,212 @@ +! 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. + !$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. + !$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)