Skip to content

Commit

Permalink
[flang][OpenMP] Add semantic check for target nesting
Browse files Browse the repository at this point in the history
This patch implements the following check for TARGET construct:
```
OpenMP Version 5.0 Target construct restriction: If a target update,
target data, target enter data, or target exit data construct is
encountered during execution of a target region, the behavior is
unspecified.
```

Also add one test case for the check.

Reviewed By: kiranchandramohan, clementval

Differential Revision: https://reviews.llvm.org/D106165
  • Loading branch information
PeixinQiao committed Aug 18, 2021
1 parent 2379949 commit 3883e26
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
56 changes: 56 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Expand Up @@ -288,6 +288,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
if (GetDirectiveNest(SIMDNest) > 0) {
CheckSIMDNest(x);
}
if (GetDirectiveNest(TargetNest) > 0) {
CheckTargetNest(x);
}
}
}

Expand Down Expand Up @@ -473,6 +476,53 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
}
}

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)};
Expand Down Expand Up @@ -616,6 +666,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
CheckMatching<parser::OmpBlockDirective>(beginDir, endDir);

PushContextAndClauseSets(beginDir.source, beginDir.v);
if (GetContext().directive == llvm::omp::Directive::OMPD_target) {
EnterDirectiveNest(TargetNest);
}

if (CurrentDirectiveIsNested()) {
CheckIfDoOrderedClause(beginDir);
Expand Down Expand Up @@ -710,6 +763,9 @@ void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
if (GetDirectiveNest(TargetBlockOnlyTeams)) {
ExitDirectiveNest(TargetBlockOnlyTeams);
}
if (GetContext().directive == llvm::omp::Directive::OMPD_target) {
ExitDirectiveNest(TargetNest);
}
dirContext_.pop_back();
}

Expand Down
8 changes: 7 additions & 1 deletion flang/lib/Semantics/check-omp-structure.h
Expand Up @@ -226,6 +226,7 @@ class OmpStructureChecker
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);
Expand Down Expand Up @@ -253,7 +254,12 @@ class OmpStructureChecker
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
Expand Down
54 changes: 54 additions & 0 deletions flang/test/Semantics/omp-nested-target.f90
@@ -0,0 +1,54 @@
! 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

0 comments on commit 3883e26

Please sign in to comment.