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 @@ -141,8 +141,15 @@ 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) { + CheckSIMDNest(x); + } } void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) { @@ -251,6 +258,45 @@ } } +void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) { + // 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; + if (llvm::omp::simdSet.test(GetContext().directive)) { + std::visit( + Fortran::common::visitors{ + [&](const parser::OpenMPBlockConstruct &c) { + // Allow `!$OMP ORDERED SIMD` + const auto &beginBlockDir{ + std::get(c.t)}; + const auto &clauses{ + std::get(beginBlockDir.t)}; + for (const auto &clause : clauses.v) { + if (std::get_if(&clause.u)) { + eligibleSIMD = true; + break; + } + } + }, + [&](const parser::OpenMPAtomicConstruct &c) { + // Allow `!$OMP ATOMIC` + eligibleSIMD = true; + }, + [&](const auto &c) {}, + }, + c.u); + if (!eligibleSIMD) { + context_.Say( + parser::FindSourceLocation(c), + "OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC'" + " may not be nested inside 'SIMD' region."_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,206 @@ +! 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 +END SUBROUTINE NESTED_GOOD + +SUBROUTINE NESTED_BAD(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 + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END SIMD + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp task + do J = 1, N + K = 2 + end do + !$omp end task + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp teams + do J = 1, N + K = 2 + end do + !$omp end teams + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp target + do J = 1, N + K = 2 + end do + !$omp end target + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$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: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END SIMD + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp task + do J = 1, N + K = 2 + end do + !$omp end task + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp teams + do J = 1, N + K = 2 + end do + !$omp end teams + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp target + do J = 1, N + K = 2 + end do + !$omp end target + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$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: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END SIMD + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp task + do J = 1, N + K = 2 + end do + !$omp end task + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp teams + do J = 1, N + K = 2 + end do + !$omp end teams + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp target + do J = 1, N + K = 2 + end do + !$omp end target + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$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: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP SIMD + DO J = 1,N + A(J) = J + END DO + !$OMP END SIMD + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp task + do J = 1, N + K = 2 + end do + !$omp end task + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp teams + do J = 1, N + K = 2 + end do + !$omp end teams + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$omp target + do J = 1, N + K = 2 + end do + !$omp end target + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$OMP DO + DO J = 1,N + A(J) = J + END DO + !$OMP END DO + !ERROR: OpenMP constructs other than `!$OMP ORDERED SIMD` or '!$OMP ATOMIC' may not be nested inside 'SIMD' region. + !$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 @@ -22,17 +22,6 @@ SUBROUTINE ORDERED_BAD(N) INTEGER N, I, A(10), B(10), C(10) - !$OMP DO SIMD - DO I = 1,N - IF (I <= 10) THEN - !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) - !$OMP END ORDERED - ENDIF - END DO - !$OMP END DO SIMD - !$OMP PARALLEL DO DO I = 1,N IF (I <= 10) THEN