Skip to content

Commit 14cfb57

Browse files
PeixinQiaojeanPerier
authored andcommitted
[flang][OpenMP] Add semantic checks for cancellation nesting
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
1 parent 1a3ab4a commit 14cfb57

File tree

5 files changed

+633
-3
lines changed

5 files changed

+633
-3
lines changed

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,9 @@ void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &x) {
846846

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

852854
void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
@@ -867,15 +869,144 @@ void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
867869
void OmpStructureChecker::Enter(
868870
const parser::OpenMPCancellationPointConstruct &x) {
869871
const auto &dir{std::get<parser::Verbatim>(x.t)};
872+
const auto &type{std::get<parser::OmpCancelType>(x.t)};
870873
PushContextAndClauseSets(
871874
dir.source, llvm::omp::Directive::OMPD_cancellation_point);
875+
CheckCancellationNest(dir.source, type.v);
872876
}
873877

874878
void OmpStructureChecker::Leave(
875879
const parser::OpenMPCancellationPointConstruct &) {
876880
dirContext_.pop_back();
877881
}
878882

883+
void OmpStructureChecker::CheckCancellationNest(
884+
const parser::CharBlock &source, const parser::OmpCancelType::Type &type) {
885+
if (CurrentDirectiveIsNested()) {
886+
// If construct-type-clause is taskgroup, the cancellation construct must be
887+
// closely nested inside a task or a taskloop construct and the cancellation
888+
// region must be closely nested inside a taskgroup region. If
889+
// construct-type-clause is sections, the cancellation construct must be
890+
// closely nested inside a sections or section construct. Otherwise, the
891+
// cancellation construct must be closely nested inside an OpenMP construct
892+
// that matches the type specified in construct-type-clause of the
893+
// cancellation construct.
894+
895+
OmpDirectiveSet allowedTaskgroupSet{
896+
llvm::omp::Directive::OMPD_task, llvm::omp::Directive::OMPD_taskloop};
897+
OmpDirectiveSet allowedSectionsSet{llvm::omp::Directive::OMPD_sections,
898+
llvm::omp::Directive::OMPD_parallel_sections};
899+
OmpDirectiveSet allowedDoSet{llvm::omp::Directive::OMPD_do,
900+
llvm::omp::Directive::OMPD_distribute_parallel_do,
901+
llvm::omp::Directive::OMPD_parallel_do,
902+
llvm::omp::Directive::OMPD_target_parallel_do,
903+
llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do,
904+
llvm::omp::Directive::OMPD_teams_distribute_parallel_do};
905+
OmpDirectiveSet allowedParallelSet{llvm::omp::Directive::OMPD_parallel,
906+
llvm::omp::Directive::OMPD_target_parallel};
907+
908+
bool eligibleCancellation{false};
909+
switch (type) {
910+
case parser::OmpCancelType::Type::Taskgroup:
911+
if (allowedTaskgroupSet.test(GetContextParent().directive)) {
912+
eligibleCancellation = true;
913+
if (dirContext_.size() >= 3) {
914+
// Check if the cancellation region is closely nested inside a
915+
// taskgroup region when there are more than two levels of directives
916+
// in the directive context stack.
917+
if (GetContextParent().directive == llvm::omp::Directive::OMPD_task ||
918+
FindClauseParent(llvm::omp::Clause::OMPC_nogroup)) {
919+
for (int i = dirContext_.size() - 3; i >= 0; i--) {
920+
if (dirContext_[i].directive ==
921+
llvm::omp::Directive::OMPD_taskgroup) {
922+
break;
923+
}
924+
if (allowedParallelSet.test(dirContext_[i].directive)) {
925+
eligibleCancellation = false;
926+
break;
927+
}
928+
}
929+
}
930+
}
931+
}
932+
if (!eligibleCancellation) {
933+
context_.Say(source,
934+
"With %s clause, %s construct must be closely nested inside TASK "
935+
"or TASKLOOP construct and %s region must be closely nested inside "
936+
"TASKGROUP region"_err_en_US,
937+
parser::ToUpperCaseLetters(
938+
parser::OmpCancelType::EnumToString(type)),
939+
ContextDirectiveAsFortran(), ContextDirectiveAsFortran());
940+
}
941+
return;
942+
case parser::OmpCancelType::Type::Sections:
943+
if (allowedSectionsSet.test(GetContextParent().directive)) {
944+
eligibleCancellation = true;
945+
}
946+
break;
947+
case Fortran::parser::OmpCancelType::Type::Do:
948+
if (allowedDoSet.test(GetContextParent().directive)) {
949+
eligibleCancellation = true;
950+
}
951+
break;
952+
case parser::OmpCancelType::Type::Parallel:
953+
if (allowedParallelSet.test(GetContextParent().directive)) {
954+
eligibleCancellation = true;
955+
}
956+
break;
957+
default:
958+
break;
959+
}
960+
if (!eligibleCancellation) {
961+
context_.Say(source,
962+
"With %s clause, %s construct cannot be closely nested inside %s "
963+
"construct"_err_en_US,
964+
parser::ToUpperCaseLetters(parser::OmpCancelType::EnumToString(type)),
965+
ContextDirectiveAsFortran(),
966+
parser::ToUpperCaseLetters(
967+
getDirectiveName(GetContextParent().directive).str()));
968+
}
969+
} else {
970+
// The cancellation directive cannot be orphaned.
971+
switch (type) {
972+
case parser::OmpCancelType::Type::Taskgroup:
973+
context_.Say(source,
974+
"%s %s directive is not closely nested inside "
975+
"TASK or TASKLOOP"_err_en_US,
976+
ContextDirectiveAsFortran(),
977+
parser::ToUpperCaseLetters(
978+
parser::OmpCancelType::EnumToString(type)));
979+
break;
980+
case parser::OmpCancelType::Type::Sections:
981+
context_.Say(source,
982+
"%s %s directive is not closely nested inside "
983+
"SECTION or SECTIONS"_err_en_US,
984+
ContextDirectiveAsFortran(),
985+
parser::ToUpperCaseLetters(
986+
parser::OmpCancelType::EnumToString(type)));
987+
break;
988+
case Fortran::parser::OmpCancelType::Type::Do:
989+
context_.Say(source,
990+
"%s %s directive is not closely nested inside "
991+
"the construct that matches the DO clause type"_err_en_US,
992+
ContextDirectiveAsFortran(),
993+
parser::ToUpperCaseLetters(
994+
parser::OmpCancelType::EnumToString(type)));
995+
break;
996+
case parser::OmpCancelType::Type::Parallel:
997+
context_.Say(source,
998+
"%s %s directive is not closely nested inside "
999+
"the construct that matches the PARALLEL clause type"_err_en_US,
1000+
ContextDirectiveAsFortran(),
1001+
parser::ToUpperCaseLetters(
1002+
parser::OmpCancelType::EnumToString(type)));
1003+
break;
1004+
default:
1005+
break;
1006+
}
1007+
}
1008+
}
1009+
8791010
void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) {
8801011
const auto &dir{std::get<parser::OmpBlockDirective>(x.t)};
8811012
ResetPartialContext(dir.source);

flang/lib/Semantics/check-omp-structure.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ class OmpStructureChecker
225225
void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
226226
void CheckDistLinear(const parser::OpenMPLoopConstruct &x);
227227
void CheckSIMDNest(const parser::OpenMPConstruct &x);
228+
void CheckCancellationNest(
229+
const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
228230
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
229231
void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
230232
bool CheckReductionOperators(const parser::OmpClause::Reduction &);

flang/test/Semantics/omp-clause-validity01.f90

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -494,9 +494,6 @@
494494
!ERROR: RELAXED clause is not allowed on the FLUSH directive
495495
!$omp flush relaxed
496496

497-
!$omp cancel DO
498-
!$omp cancellation point parallel
499-
500497
! 2.13.2 critical Construct
501498

502499
! !$omp critical (first)

0 commit comments

Comments
 (0)