[flang-commits] [flang] [flang][OpenACC] Diagnose illegal routine calls in parallel loops (PR #190068)
Delaram Talaashrafi via flang-commits
flang-commits at lists.llvm.org
Thu Apr 9 10:55:56 PDT 2026
https://github.com/delaram-talaashrafi updated https://github.com/llvm/llvm-project/pull/190068
>From d300b623c0beee67cf1085d2d0d8911bee9629da Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Wed, 1 Apr 2026 14:35:43 -0700
Subject: [PATCH 1/2] [flang][OpenACC] Diagnose illegal routine calls in
parallel loops
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add routine call checking to AccStructureChecker to reject OpenACC routine
calls whose parallel level is incompatible with the enclosing loop directive
(e.g., calling a worker‑level routine from a vector‑parallel loop), as
required by the OpenACC specification.
---
flang/lib/Semantics/check-acc-structure.cpp | 63 +++++
flang/lib/Semantics/check-acc-structure.h | 1 +
.../OpenACC/acc-loop-routine-call.f90 | 218 ++++++++++++++++++
3 files changed, 282 insertions(+)
create mode 100644 flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 732531b1bdfcc..5064639211843 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -347,6 +347,69 @@ void AccStructureChecker::CheckNotInSameOrSubLevelLoopConstruct() {
}
}
+void AccStructureChecker::Enter(const parser::CallStmt &call) {
+ if (dirContext_.empty() || !call.typedCall) {
+ return;
+ }
+ const Symbol *sym{call.typedCall->proc().GetSymbol()};
+ if (!sym) {
+ return;
+ }
+ const Symbol &ult{sym->GetUltimate()};
+ const auto *subp{ult.detailsIf<SubprogramDetails>()};
+ if (!subp || subp->openACCRoutineInfos().empty()) {
+ return;
+ }
+ std::string routineParDim;
+ unsigned routineGangDim = 0;
+ for (const OpenACCRoutineInfo &ri : subp->openACCRoutineInfos()) {
+ if (ri.isGang()) {
+ if (unsigned gangDim = ri.gangDim()) {
+ routineGangDim = gangDim;
+ routineParDim = "GANG(" + std::to_string(gangDim) + ")";
+ } else {
+ routineGangDim = 1;
+ routineParDim = "GANG";
+ }
+ } else if (ri.isWorker()) {
+ routineParDim = "WORKER";
+ } else if (ri.isVector()) {
+ routineParDim = "VECTOR";
+ } else if (ri.isSeq()) {
+ routineParDim = "SEQ";
+ }
+ }
+
+ DirectiveContext &inner{dirContext_.back()};
+ for (llvm::acc::Clause cl : inner.actualClauses) {
+ if (cl == llvm::acc::Clause::ACCC_vector) {
+ if (!routineParDim.empty() && routineParDim != "SEQ") {
+ context_.Say(GetContext().clauseSource,
+ "Calling %s routine inside VECTOR loop is not allowed"_err_en_US,
+ routineParDim);
+ }
+ }
+ if (cl == llvm::acc::Clause::ACCC_worker) {
+ if (!routineParDim.empty() &&
+ (routineParDim != "SEQ" && routineParDim != "VECTOR")) {
+ context_.Say(GetContext().clauseSource,
+ "Calling %s routine inside WORKER loop is not allowed"_err_en_US,
+ routineParDim);
+ }
+ }
+ if (cl == llvm::acc::Clause::ACCC_gang) {
+ const std::optional<std::int64_t> loopGangDim{
+ getGangDimensionSize(inner)};
+ const std::int64_t loopDimNum{loopGangDim.value_or(1)};
+ if (routineGangDim && routineGangDim >= loopDimNum) {
+ context_.Say(GetContext().clauseSource,
+ "Calling %s routine inside GANG(%s) loop is not allowed"_err_en_US,
+ routineParDim, std::to_string(loopDimNum));
+ }
+ }
+ }
+}
+
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h
index 09399297ca4be..b040e14642ac9 100644
--- a/flang/lib/Semantics/check-acc-structure.h
+++ b/flang/lib/Semantics/check-acc-structure.h
@@ -78,6 +78,7 @@ class AccStructureChecker
void Enter(const parser::SeparateModuleSubprogram &);
void Enter(const parser::DoConstruct &);
void Leave(const parser::DoConstruct &);
+ void Enter(const parser::CallStmt &);
#define GEN_FLANG_CLAUSE_CHECK_ENTER
#include "llvm/Frontend/OpenACC/ACC.inc"
diff --git a/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90 b/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
new file mode 100644
index 0000000000000..cd6fd3d324fe1
--- /dev/null
+++ b/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
@@ -0,0 +1,218 @@
+! RUN: %python %S/../test_errors.py %s %flang -fopenacc
+
+! Semantic checks for calling !$acc routine procedures from LOOP bodies
+! (AccStructureChecker::Enter(const parser::CallStmt &)).
+
+module acc_loop_routine_call_m
+ implicit none
+contains
+
+ subroutine r_seq()
+ !$acc routine seq
+ end subroutine r_seq
+
+ subroutine r_vector()
+ !$acc routine vector
+ end subroutine r_vector
+
+ subroutine r_worker()
+ !$acc routine worker
+ end subroutine r_worker
+
+ subroutine r_gang()
+ !$acc routine gang
+ end subroutine r_gang
+
+ subroutine r_gang_dim1()
+ !$acc routine gang(dim:1)
+ end subroutine r_gang_dim1
+
+ subroutine r_gang_dim2()
+ !$acc routine gang(dim:2)
+ end subroutine r_gang_dim2
+
+ subroutine r_gang_dim3()
+ !$acc routine gang(dim:3)
+ end subroutine r_gang_dim3
+
+end module acc_loop_routine_call_m
+
+program acc_loop_routine_call
+ use acc_loop_routine_call_m
+ implicit none
+ integer, parameter :: n = 8
+ integer :: i
+
+ !$acc parallel
+ !$acc loop vector
+ do i = 1, n
+ call r_seq()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG routine inside VECTOR loop is not allowed
+ !$acc loop vector
+ do i = 1, n
+ call r_gang()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(1) routine inside VECTOR loop is not allowed
+ !$acc loop vector
+ do i = 1, n
+ call r_gang_dim1()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling WORKER routine inside VECTOR loop is not allowed
+ !$acc loop vector
+ do i = 1, n
+ call r_worker()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling VECTOR routine inside VECTOR loop is not allowed
+ !$acc loop vector
+ do i = 1, n
+ call r_vector()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(3) routine inside VECTOR loop is not allowed
+ !$acc loop vector
+ do i = 1, n
+ call r_gang_dim3()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !$acc loop worker
+ do i = 1, n
+ call r_seq()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !$acc loop worker
+ do i = 1, n
+ call r_vector()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG routine inside WORKER loop is not allowed
+ !$acc loop worker
+ do i = 1, n
+ call r_gang()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(2) routine inside WORKER loop is not allowed
+ !$acc loop worker
+ do i = 1, n
+ call r_gang_dim2()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(3) routine inside WORKER loop is not allowed
+ !$acc loop worker
+ do i = 1, n
+ call r_gang_dim3()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling WORKER routine inside WORKER loop is not allowed
+ !$acc loop worker
+ do i = 1, n
+ call r_worker()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !$acc loop gang(dim:2)
+ do i = 1, n
+ call r_seq()
+ call r_vector()
+ call r_gang_dim1()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(1) routine inside GANG(1) loop is not allowed
+ !$acc loop gang
+ do i = 1, n
+ call r_gang_dim1()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG routine inside GANG(1) loop is not allowed
+ !$acc loop gang
+ do i = 1, n
+ call r_gang()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !$acc loop gang(dim:2)
+ do i = 1, n
+ call r_gang_dim1()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(3) routine inside GANG(2) loop is not allowed
+ !$acc loop gang(dim:2)
+ do i = 1, n
+ call r_gang_dim3()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(2) routine inside GANG(2) loop is not allowed
+ !$acc loop gang(dim:2)
+ do i = 1, n
+ call r_gang_dim2()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !$acc loop gang(dim:3)
+ do i = 1, n
+ call r_gang_dim1()
+ call r_gang_dim2()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(3) routine inside GANG(3) loop is not allowed
+ !$acc loop gang(dim:3)
+ do i = 1, n
+ call r_gang_dim3()
+ end do
+ !$acc end parallel
+
+ !$acc parallel
+ !ERROR: Calling GANG(3) routine inside GANG(1) loop is not allowed
+ !$acc loop gang
+ do i = 1, n
+ call r_gang_dim3()
+ end do
+ !$acc end parallel
+
+ !ERROR: Calling WORKER routine inside VECTOR loop is not allowed
+ !$acc parallel loop vector
+ do i = 1, n
+ call r_worker()
+ end do
+ !$acc end parallel loop
+
+end program acc_loop_routine_call
>From 0ee520a3f5fbc0d4ff06831f098a68e17781b8ca Mon Sep 17 00:00:00 2001
From: Delaram Talaashrafi <dtalaashrafi at rome5.pgi.net>
Date: Wed, 8 Apr 2026 14:47:17 -0700
Subject: [PATCH 2/2] Address reviews
---
flang/lib/Semantics/check-acc-structure.cpp | 12 +++++++---
.../OpenACC/acc-loop-routine-call.f90 | 22 +++++++++----------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 5064639211843..9f5a343f3848b 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -402,9 +402,15 @@ void AccStructureChecker::Enter(const parser::CallStmt &call) {
getGangDimensionSize(inner)};
const std::int64_t loopDimNum{loopGangDim.value_or(1)};
if (routineGangDim && routineGangDim >= loopDimNum) {
- context_.Say(GetContext().clauseSource,
- "Calling %s routine inside GANG(%s) loop is not allowed"_err_en_US,
- routineParDim, std::to_string(loopDimNum));
+ if (loopGangDim) {
+ context_.Say(GetContext().clauseSource,
+ "Calling %s routine inside GANG(%s) loop is not allowed"_err_en_US,
+ routineParDim, std::to_string(*loopGangDim));
+ } else {
+ context_.Say(GetContext().clauseSource,
+ "Calling %s routine inside GANG loop is not allowed"_err_en_US,
+ routineParDim);
+ }
}
}
}
diff --git a/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90 b/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
index cd6fd3d324fe1..428bb5f4dc0e2 100644
--- a/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
+++ b/flang/test/Semantics/OpenACC/acc-loop-routine-call.f90
@@ -1,7 +1,6 @@
! RUN: %python %S/../test_errors.py %s %flang -fopenacc
! Semantic checks for calling !$acc routine procedures from LOOP bodies
-! (AccStructureChecker::Enter(const parser::CallStmt &)).
module acc_loop_routine_call_m
implicit none
@@ -112,6 +111,14 @@ program acc_loop_routine_call
end do
!$acc end parallel
+ !$acc parallel
+ !ERROR: Calling GANG(1) routine inside WORKER loop is not allowed
+ !$acc loop worker
+ do i = 1, n
+ call r_gang_dim1()
+ end do
+ !$acc end parallel
+
!$acc parallel
!ERROR: Calling GANG(2) routine inside WORKER loop is not allowed
!$acc loop worker
@@ -146,7 +153,7 @@ program acc_loop_routine_call
!$acc end parallel
!$acc parallel
- !ERROR: Calling GANG(1) routine inside GANG(1) loop is not allowed
+ !ERROR: Calling GANG(1) routine inside GANG loop is not allowed
!$acc loop gang
do i = 1, n
call r_gang_dim1()
@@ -154,7 +161,7 @@ program acc_loop_routine_call
!$acc end parallel
!$acc parallel
- !ERROR: Calling GANG routine inside GANG(1) loop is not allowed
+ !ERROR: Calling GANG routine inside GANG loop is not allowed
!$acc loop gang
do i = 1, n
call r_gang()
@@ -201,18 +208,11 @@ program acc_loop_routine_call
!$acc end parallel
!$acc parallel
- !ERROR: Calling GANG(3) routine inside GANG(1) loop is not allowed
+ !ERROR: Calling GANG(3) routine inside GANG loop is not allowed
!$acc loop gang
do i = 1, n
call r_gang_dim3()
end do
!$acc end parallel
- !ERROR: Calling WORKER routine inside VECTOR loop is not allowed
- !$acc parallel loop vector
- do i = 1, n
- call r_worker()
- end do
- !$acc end parallel loop
-
end program acc_loop_routine_call
More information about the flang-commits
mailing list