[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