if (GetDirectiveNest(SIMDNest) > 0) {
CheckSIMDNest(x);
}
+ if (GetDirectiveNest(TargetNest) > 0) {
+ CheckTargetNest(x);
+ }
}
}
}
}
+void OmpStructureChecker::CheckTargetNest(const parser::OpenMPConstruct &c) {
+ // 2.12.5 Target Construct Restriction
+ bool eligibleTarget{true};
+ llvm::omp::Directive ineligibleTargetDir;
+ std::visit(
+ common::visitors{
+ [&](const parser::OpenMPBlockConstruct &c) {
+ const auto &beginBlockDir{
+ std::get<parser::OmpBeginBlockDirective>(c.t)};
+ const auto &beginDir{
+ std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+ if (beginDir.v == llvm::omp::Directive::OMPD_target_data) {
+ eligibleTarget = false;
+ ineligibleTargetDir = beginDir.v;
+ }
+ },
+ [&](const parser::OpenMPStandaloneConstruct &c) {
+ std::visit(
+ common::visitors{
+ [&](const parser::OpenMPSimpleStandaloneConstruct &c) {
+ const auto &dir{
+ std::get<parser::OmpSimpleStandaloneDirective>(c.t)};
+ if (dir.v == llvm::omp::Directive::OMPD_target_update ||
+ dir.v ==
+ llvm::omp::Directive::OMPD_target_enter_data ||
+ dir.v ==
+ llvm::omp::Directive::OMPD_target_exit_data) {
+ eligibleTarget = false;
+ ineligibleTargetDir = dir.v;
+ }
+ },
+ [&](const auto &c) {},
+ },
+ c.u);
+ },
+ [&](const auto &c) {},
+ },
+ c.u);
+ if (!eligibleTarget) {
+ context_.Say(parser::FindSourceLocation(c),
+ "If %s directive is nested inside TARGET region, the behaviour "
+ "is unspecified"_en_US,
+ parser::ToUpperCaseLetters(
+ getDirectiveName(ineligibleTargetDir).str()));
+ }
+}
+
std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
const parser::OpenMPLoopConstruct &x) {
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
CheckMatching<parser::OmpBlockDirective>(beginDir, endDir);
PushContextAndClauseSets(beginDir.source, beginDir.v);
+ if (GetContext().directive == llvm::omp::Directive::OMPD_target) {
+ EnterDirectiveNest(TargetNest);
+ }
if (CurrentDirectiveIsNested()) {
CheckIfDoOrderedClause(beginDir);
if (GetDirectiveNest(TargetBlockOnlyTeams)) {
ExitDirectiveNest(TargetBlockOnlyTeams);
}
+ if (GetContext().directive == llvm::omp::Directive::OMPD_target) {
+ ExitDirectiveNest(TargetNest);
+ }
dirContext_.pop_back();
}
void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
void CheckSIMDNest(const parser::OpenMPConstruct &x);
+ void CheckTargetNest(const parser::OpenMPConstruct &x);
void CheckCancellationNest(
const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
int GetDirectiveNest(const int index) { return directiveNest_[index]; }
- enum directiveNestType { SIMDNest, TargetBlockOnlyTeams, LastType };
+ enum directiveNestType {
+ SIMDNest,
+ TargetBlockOnlyTeams,
+ TargetNest,
+ LastType
+ };
int directiveNest_[LastType + 1] = {0};
};
} // namespace Fortran::semantics
--- /dev/null
+! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp
+! REQUIRES: shell
+
+! OpenMP Version 5.0
+! Check OpenMP construct validity for the following directives:
+! 2.12.5 Target Construct
+
+program main
+ integer :: i, j, N = 10
+ real :: a, arrayA(512), arrayB(512), ai(10)
+ real, allocatable :: B(:)
+
+ !$omp target
+ !WARNING: If TARGET UPDATE directive is nested inside TARGET region, the behaviour is unspecified
+ !$omp target update from(arrayA) to(arrayB)
+ do i = 1, 512
+ arrayA(i) = arrayB(i)
+ end do
+ !$omp end target
+
+ !$omp parallel
+ !$omp target
+ !$omp parallel
+ !WARNING: If TARGET UPDATE directive is nested inside TARGET region, the behaviour is unspecified
+ !$omp target update from(arrayA) to(arrayB)
+ do i = 1, 512
+ arrayA(i) = arrayB(i)
+ end do
+ !$omp end parallel
+ !$omp end target
+ !$omp end parallel
+
+ !$omp target
+ !WARNING: If TARGET DATA directive is nested inside TARGET region, the behaviour is unspecified
+ !$omp target data map(to: a)
+ do i = 1, N
+ a = 3.14
+ end do
+ !$omp end target data
+ !$omp end target
+
+ allocate(B(N))
+ !$omp target
+ !WARNING: If TARGET ENTER DATA directive is nested inside TARGET region, the behaviour is unspecified
+ !$omp target enter data map(alloc:B)
+ !$omp end target
+
+ !$omp target
+ !WARNING: If TARGET EXIT DATA directive is nested inside TARGET region, the behaviour is unspecified
+ !$omp target exit data map(delete:B)
+ !$omp end target
+ deallocate(B)
+
+end program main