Skip to content

Commit

Permalink
[flang][OpenMP] Add semantic checks for cancellation nesting
Browse files Browse the repository at this point in the history
This patch implements the following semantic checks for cancellation constructs:
```
OpenMP Version 5.0 Section 2.18.1: CANCEL construct restriction:
If construct-type-clause is taskgroup, the cancel construct must be
closely nested inside a task or a taskloop construct and the cancel
region must be closely nested inside a taskgroup region. If
construct-type-clause is sections, the cancel construct must be closely
nested inside a sections or section construct. Otherwise, the cancel
construct must be closely nested inside an OpenMP construct that matches
the type specified in construct-type-clause of the cancel construct.

OpenMP Version 5.0 Section 2.18.2: CANCELLATION POINT restriction:
A cancellation point construct for which construct-type-clause is
taskgroup must be closely nested inside a task or taskloop construct,
and the cancellation point region must be closely nested inside a
taskgroup region. A cancellation point construct for which
construct-type-clause is sections must be closely nested inside a
sections or section construct. A cancellation point construct for which
construct-type-clause is neither sections nor taskgroup must be closely
nested inside an OpenMP construct that matches the type specified in
construct-type-clause.
```

Also add test cases for the check.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D106538
  • Loading branch information
PeixinQiao authored and Arnamoy Bhattacharyya committed Aug 13, 2021
1 parent d754b97 commit 70894c8
Show file tree
Hide file tree
Showing 5 changed files with 633 additions and 3 deletions.
131 changes: 131 additions & 0 deletions flang/lib/Semantics/check-omp-structure.cpp
Expand Up @@ -846,7 +846,9 @@ void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &x) {

void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
const auto &type{std::get<parser::OmpCancelType>(x.t)};
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_cancel);
CheckCancellationNest(dir.source, type.v);
}

void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
Expand All @@ -867,15 +869,144 @@ void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
void OmpStructureChecker::Enter(
const parser::OpenMPCancellationPointConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
const auto &type{std::get<parser::OmpCancelType>(x.t)};
PushContextAndClauseSets(
dir.source, llvm::omp::Directive::OMPD_cancellation_point);
CheckCancellationNest(dir.source, type.v);
}

void OmpStructureChecker::Leave(
const parser::OpenMPCancellationPointConstruct &) {
dirContext_.pop_back();
}

void OmpStructureChecker::CheckCancellationNest(
const parser::CharBlock &source, const parser::OmpCancelType::Type &type) {
if (CurrentDirectiveIsNested()) {
// If construct-type-clause is taskgroup, the cancellation construct must be
// closely nested inside a task or a taskloop construct and the cancellation
// region must be closely nested inside a taskgroup region. If
// construct-type-clause is sections, the cancellation construct must be
// closely nested inside a sections or section construct. Otherwise, the
// cancellation construct must be closely nested inside an OpenMP construct
// that matches the type specified in construct-type-clause of the
// cancellation construct.

OmpDirectiveSet allowedTaskgroupSet{
llvm::omp::Directive::OMPD_task, llvm::omp::Directive::OMPD_taskloop};
OmpDirectiveSet allowedSectionsSet{llvm::omp::Directive::OMPD_sections,
llvm::omp::Directive::OMPD_parallel_sections};
OmpDirectiveSet allowedDoSet{llvm::omp::Directive::OMPD_do,
llvm::omp::Directive::OMPD_distribute_parallel_do,
llvm::omp::Directive::OMPD_parallel_do,
llvm::omp::Directive::OMPD_target_parallel_do,
llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do,
llvm::omp::Directive::OMPD_teams_distribute_parallel_do};
OmpDirectiveSet allowedParallelSet{llvm::omp::Directive::OMPD_parallel,
llvm::omp::Directive::OMPD_target_parallel};

bool eligibleCancellation{false};
switch (type) {
case parser::OmpCancelType::Type::Taskgroup:
if (allowedTaskgroupSet.test(GetContextParent().directive)) {
eligibleCancellation = true;
if (dirContext_.size() >= 3) {
// Check if the cancellation region is closely nested inside a
// taskgroup region when there are more than two levels of directives
// in the directive context stack.
if (GetContextParent().directive == llvm::omp::Directive::OMPD_task ||
FindClauseParent(llvm::omp::Clause::OMPC_nogroup)) {
for (int i = dirContext_.size() - 3; i >= 0; i--) {
if (dirContext_[i].directive ==
llvm::omp::Directive::OMPD_taskgroup) {
break;
}
if (allowedParallelSet.test(dirContext_[i].directive)) {
eligibleCancellation = false;
break;
}
}
}
}
}
if (!eligibleCancellation) {
context_.Say(source,
"With %s clause, %s construct must be closely nested inside TASK "
"or TASKLOOP construct and %s region must be closely nested inside "
"TASKGROUP region"_err_en_US,
parser::ToUpperCaseLetters(
parser::OmpCancelType::EnumToString(type)),
ContextDirectiveAsFortran(), ContextDirectiveAsFortran());
}
return;
case parser::OmpCancelType::Type::Sections:
if (allowedSectionsSet.test(GetContextParent().directive)) {
eligibleCancellation = true;
}
break;
case Fortran::parser::OmpCancelType::Type::Do:
if (allowedDoSet.test(GetContextParent().directive)) {
eligibleCancellation = true;
}
break;
case parser::OmpCancelType::Type::Parallel:
if (allowedParallelSet.test(GetContextParent().directive)) {
eligibleCancellation = true;
}
break;
default:
break;
}
if (!eligibleCancellation) {
context_.Say(source,
"With %s clause, %s construct cannot be closely nested inside %s "
"construct"_err_en_US,
parser::ToUpperCaseLetters(parser::OmpCancelType::EnumToString(type)),
ContextDirectiveAsFortran(),
parser::ToUpperCaseLetters(
getDirectiveName(GetContextParent().directive).str()));
}
} else {
// The cancellation directive cannot be orphaned.
switch (type) {
case parser::OmpCancelType::Type::Taskgroup:
context_.Say(source,
"%s %s directive is not closely nested inside "
"TASK or TASKLOOP"_err_en_US,
ContextDirectiveAsFortran(),
parser::ToUpperCaseLetters(
parser::OmpCancelType::EnumToString(type)));
break;
case parser::OmpCancelType::Type::Sections:
context_.Say(source,
"%s %s directive is not closely nested inside "
"SECTION or SECTIONS"_err_en_US,
ContextDirectiveAsFortran(),
parser::ToUpperCaseLetters(
parser::OmpCancelType::EnumToString(type)));
break;
case Fortran::parser::OmpCancelType::Type::Do:
context_.Say(source,
"%s %s directive is not closely nested inside "
"the construct that matches the DO clause type"_err_en_US,
ContextDirectiveAsFortran(),
parser::ToUpperCaseLetters(
parser::OmpCancelType::EnumToString(type)));
break;
case parser::OmpCancelType::Type::Parallel:
context_.Say(source,
"%s %s directive is not closely nested inside "
"the construct that matches the PARALLEL clause type"_err_en_US,
ContextDirectiveAsFortran(),
parser::ToUpperCaseLetters(
parser::OmpCancelType::EnumToString(type)));
break;
default:
break;
}
}
}

void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) {
const auto &dir{std::get<parser::OmpBlockDirective>(x.t)};
ResetPartialContext(dir.source);
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Semantics/check-omp-structure.h
Expand Up @@ -225,6 +225,8 @@ class OmpStructureChecker
void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
void CheckSIMDNest(const parser::OpenMPConstruct &x);
void CheckCancellationNest(
const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
bool CheckReductionOperators(const parser::OmpClause::Reduction &);
Expand Down
3 changes: 0 additions & 3 deletions flang/test/Semantics/omp-clause-validity01.f90
Expand Up @@ -494,9 +494,6 @@
!ERROR: RELAXED clause is not allowed on the FLUSH directive
!$omp flush relaxed

!$omp cancel DO
!$omp cancellation point parallel

! 2.13.2 critical Construct

! !$omp critical (first)
Expand Down

0 comments on commit 70894c8

Please sign in to comment.