[flang-commits] [flang] [Flang][OpenMP] Add checks for EXIT from associated loops (PR #91315)
Kiran Chandramohan via flang-commits
flang-commits at lists.llvm.org
Tue May 7 03:18:42 PDT 2024
https://github.com/kiranchandramohan created https://github.com/llvm/llvm-project/pull/91315
Extend the checker that deals with CYCLE to handle EXIT also. The difference for EXIT is that it is not allowed to EXIT from the innermost associated loops while it is OK to CYCLE in the innermost associated loop. Also add an incrementer on leaving the DO loop for EXIT checks.
>From d62c52d34a736f5872d2a971f0406424b727bcc8 Mon Sep 17 00:00:00 2001
From: Kiran Chandramohan <kiran.chandramohan at arm.com>
Date: Tue, 7 May 2024 10:11:38 +0000
Subject: [PATCH] [Flang][OpenMP] Add checks for EXIT from associated loops
Extend the checker that deals with CYCLE to handle EXIT also. The
difference for EXIT is that it is not allowed to EXIT from the
innermost associated loops while it is OK to CYCLE in the innermost
associated loop. Also add an incrementer on leaving the DO loop
for EXIT checks.
---
flang/lib/Semantics/check-omp-structure.cpp | 47 ++++++++++++++-------
flang/test/Semantics/OpenMP/do08.f90 | 31 ++++++++++++++
2 files changed, 63 insertions(+), 15 deletions(-)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 70863c5f20e89..78d7a2eabcaf9 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -84,52 +84,69 @@ class OmpWorkshareBlockChecker {
parser::CharBlock source_;
};
-class OmpCycleChecker {
+class OmpCycleAndExitChecker {
public:
- OmpCycleChecker(SemanticsContext &context, std::int64_t cycleLevel)
- : context_{context}, cycleLevel_{cycleLevel} {}
+ OmpCycleAndExitChecker(SemanticsContext &context, std::int64_t level)
+ : context_{context}, level_{level} {}
template <typename T> bool Pre(const T &) { return true; }
template <typename T> void Post(const T &) {}
bool Pre(const parser::DoConstruct &dc) {
- cycleLevel_--;
+ level_--;
const auto &constructName{std::get<0>(std::get<0>(dc.t).statement.t)};
if (constructName) {
constructNamesAndLevels_.emplace(
- constructName.value().ToString(), cycleLevel_);
+ constructName.value().ToString(), level_);
}
return true;
}
+ void Post(const parser::DoConstruct &dc) { level_++; }
+
bool Pre(const parser::CycleStmt &cyclestmt) {
std::map<std::string, std::int64_t>::iterator it;
bool err{false};
if (cyclestmt.v) {
it = constructNamesAndLevels_.find(cyclestmt.v->source.ToString());
err = (it != constructNamesAndLevels_.end() && it->second > 0);
- } else {
- // If there is no label then the cycle statement is associated with the
- // closest enclosing DO. Use its level for the checks.
- err = cycleLevel_ > 0;
+ } else { // If there is no label then use the level of the last enclosing DO
+ err = level_ > 0;
}
if (err) {
- context_.Say(*cycleSource_,
+ context_.Say(*source_,
"CYCLE statement to non-innermost associated loop of an OpenMP DO "
"construct"_err_en_US);
}
return true;
}
+ bool Pre(const parser::ExitStmt &exitStmt) {
+ std::map<std::string, std::int64_t>::iterator it;
+ bool err{false};
+ if (exitStmt.v) {
+ it = constructNamesAndLevels_.find(exitStmt.v->source.ToString());
+ err = (it != constructNamesAndLevels_.end() && it->second >= 0);
+ } else { // If there is no label then use the level of the last enclosing DO
+ err = level_ >= 0;
+ }
+ if (err) {
+ context_.Say(*source_,
+ "EXIT statement to non-innermost associated loop of an OpenMP DO "
+ "construct"_err_en_US);
+ }
+ return true;
+ }
+
bool Pre(const parser::Statement<parser::ActionStmt> &actionstmt) {
- cycleSource_ = &actionstmt.source;
+ source_ = &actionstmt.source;
return true;
}
private:
SemanticsContext &context_;
- const parser::CharBlock *cycleSource_;
- std::int64_t cycleLevel_;
+ const parser::CharBlock *source_;
+ std::int64_t level_;
std::map<std::string, std::int64_t> constructNamesAndLevels_;
};
@@ -657,8 +674,8 @@ std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
void OmpStructureChecker::CheckCycleConstraints(
const parser::OpenMPLoopConstruct &x) {
std::int64_t ordCollapseLevel{GetOrdCollapseLevel(x)};
- OmpCycleChecker ompCycleChecker{context_, ordCollapseLevel};
- parser::Walk(x, ompCycleChecker);
+ OmpCycleAndExitChecker checker{context_, ordCollapseLevel};
+ parser::Walk(x, checker);
}
void OmpStructureChecker::CheckDistLinear(
diff --git a/flang/test/Semantics/OpenMP/do08.f90 b/flang/test/Semantics/OpenMP/do08.f90
index 3ba63072a80bd..46c52d7c341ff 100644
--- a/flang/test/Semantics/OpenMP/do08.f90
+++ b/flang/test/Semantics/OpenMP/do08.f90
@@ -4,6 +4,8 @@
program omp
integer i, j, k
+ logical cond(10,10,10)
+ cond = .false.
!ERROR: The value of the parameter in the COLLAPSE or ORDERED clause must not be larger than the number of nested loops following the construct.
!$omp do collapse(3)
@@ -135,4 +137,33 @@ program omp
end do foo
!$omp end do
+ !$omp do collapse(3)
+loopk: do k=1,10
+ loopj: do j=1,10
+ loopi: do i=1,10
+ ifi : if (.true.) then
+ !ERROR: EXIT statement to non-innermost associated loop of an OpenMP DO construct
+ if (cond(i,j,k)) exit
+ if (cond(i,j,k)) exit ifi
+ !ERROR: EXIT statement to non-innermost associated loop of an OpenMP DO construct
+ if (cond(i,j,k)) exit loopi
+ !ERROR: EXIT statement to non-innermost associated loop of an OpenMP DO construct
+ if (cond(i,j,k)) exit loopj
+ end if ifi
+ end do loopi
+ end do loopj
+ end do loopk
+ !$omp end do
+
+ !$omp do collapse(2)
+loopk: do k=1,10
+ loopj: do j=1,10
+ do i=1,10
+ end do
+ !ERROR: EXIT statement to non-innermost associated loop of an OpenMP DO construct
+ if (cond(i,j,k)) exit
+ end do loopj
+ end do loopk
+ !$omp end do
+
end program omp
More information about the flang-commits
mailing list