[flang-commits] [flang] 5b6ebc2 - [flang][cuda][openacc] Support CUDA calls to ACC routines (#210165)

via flang-commits flang-commits at lists.llvm.org
Tue Jul 21 12:47:29 PDT 2026


Author: nvptm
Date: 2026-07-21T12:47:25-07:00
New Revision: 5b6ebc25e08c35d30edbe6aa7b64d06c46686b18

URL: https://github.com/llvm/llvm-project/commit/5b6ebc25e08c35d30edbe6aa7b64d06c46686b18
DIFF: https://github.com/llvm/llvm-project/commit/5b6ebc25e08c35d30edbe6aa7b64d06c46686b18.diff

LOG: [flang][cuda][openacc] Support CUDA calls to ACC routines (#210165)

Enable CUDA device procedures to call !$acc routine procedures.

- Treat ACC routines as device-callable during CUDA semantic checking.
- Apply implicit-device dummy argument handling to ACC routines called
from CUDA device code.
- Defer CUDA cloning of ACC routines until ACC lowering materializes and
moves the specialized routine into the GPU module.
- Add a CUF device-function transform regression test.

Added: 
    

Modified: 
    flang/include/flang/Evaluate/characteristics.h
    flang/lib/Evaluate/characteristics.cpp
    flang/lib/Optimizer/Transforms/CUDA/CUFDeviceFuncTransform.cpp
    flang/lib/Semantics/check-call.cpp
    flang/lib/Semantics/check-cuda.cpp
    flang/test/Fir/CUDA/cuda-device-func-transform.mlir

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index af0d429b6aa3b..bc37f3d39c2ec 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -418,6 +418,8 @@ struct Procedure {
   DummyArguments dummyArguments;
   Attrs attrs;
   std::optional<common::CUDASubprogramAttrs> cudaSubprogramAttrs;
+  // Used only by CUDA semantic checks; this is not a CUDA procedure attribute.
+  bool hasOpenACCRoutine{false};
 };
 
 } // namespace Fortran::evaluate::characteristics

diff  --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index b679914f429c4..8750cd3c3ebb6 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -668,6 +668,7 @@ static std::optional<Procedure> CharacterizeProcedure(
               }
             }
             result.cudaSubprogramAttrs = subp.cudaSubprogramAttrs();
+            result.hasOpenACCRoutine = !subp.openACCRoutineInfos().empty();
             return std::move(result);
           },
           [&](const semantics::ProcEntityDetails &proc)
@@ -695,6 +696,9 @@ static std::optional<Procedure> CharacterizeProcedure(
                 // functions as their interfaces.
                 result->attrs.reset(Procedure::Attr::Elemental);
               }
+              if (result && !proc.openACCRoutineInfos().empty()) {
+                result->hasOpenACCRoutine = true;
+              }
               return result;
             } else {
               Procedure result;
@@ -716,6 +720,7 @@ static std::optional<Procedure> CharacterizeProcedure(
               } else if (symbol.test(semantics::Symbol::Flag::Function)) {
                 return std::nullopt;
               }
+              result.hasOpenACCRoutine = !proc.openACCRoutineInfos().empty();
               // The PASS name, if any, is not a characteristic.
               return std::move(result);
             }

diff  --git a/flang/lib/Optimizer/Transforms/CUDA/CUFDeviceFuncTransform.cpp b/flang/lib/Optimizer/Transforms/CUDA/CUFDeviceFuncTransform.cpp
index 2576dee47d079..307d41cb62a21 100644
--- a/flang/lib/Optimizer/Transforms/CUDA/CUFDeviceFuncTransform.cpp
+++ b/flang/lib/Optimizer/Transforms/CUDA/CUFDeviceFuncTransform.cpp
@@ -18,6 +18,7 @@
 #include "mlir/Dialect/GPU/IR/GPUDialect.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/Dialect/LLVMIR/NVVMDialect.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/IR/IRMapping.h"
 #include "mlir/Pass/Pass.h"
 #include "llvm/ADT/SetVector.h"
@@ -216,6 +217,10 @@ class CUFDeviceFuncTransform
       if (op.getCallee()) {
         auto func = symbolTable.lookup<mlir::func::FuncOp>(
             op.getCallee()->getLeafReference());
+        // ACCRoutineToGPUFunc moves the materialized specialized routine into
+        // the GPU module later in the pipeline.
+        if (mlir::acc::isAccRoutine(func))
+          return;
         if (deviceFuncs.count(func) == 0)
           funcsToClone.insert(func);
       }

diff  --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index b59053ec0481d..0680a48bac2be 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -1142,10 +1142,13 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
     }
     dummyDataAttr = dummy.cudaDataAttr;
     // Treat MANAGED like DEVICE for nonallocatable nonpointer arguments to
-    // device subprograms
-    if (procedure.cudaSubprogramAttrs.value_or(
-            common::CUDASubprogramAttrs::Host) !=
-            common::CUDASubprogramAttrs::Host &&
+    // device subprograms. An OpenACC routine called from CUDA device code has
+    // the same implicit-device dummy-argument behavior.
+    bool isDeviceCallee{procedure.cudaSubprogramAttrs.value_or(
+                            common::CUDASubprogramAttrs::Host) !=
+            common::CUDASubprogramAttrs::Host ||
+        (procedure.hasOpenACCRoutine && FindCUDADeviceContext(scope))};
+    if (isDeviceCallee &&
         !dummy.attrs.test(
             characteristics::DummyDataObject::Attr::Allocatable) &&
         !dummy.attrs.test(characteristics::DummyDataObject::Attr::Pointer)) {
@@ -1162,8 +1165,9 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
       if (!actualDataAttr &&
           (!actualFirstSymbol || IsValue(*actualFirstSymbol) ||
               IsFunctionResult(*actualFirstSymbol)) &&
-          (*procedure.cudaSubprogramAttrs ==
-              common::CUDASubprogramAttrs::Device)) {
+          (procedure.cudaSubprogramAttrs &&
+              *procedure.cudaSubprogramAttrs ==
+                  common::CUDASubprogramAttrs::Device)) {
         actualDataAttr = common::CUDADataAttr::Device;
       }
     }

diff  --git a/flang/lib/Semantics/check-cuda.cpp b/flang/lib/Semantics/check-cuda.cpp
index a257a47d92ca9..260e17262dcc0 100644
--- a/flang/lib/Semantics/check-cuda.cpp
+++ b/flang/lib/Semantics/check-cuda.cpp
@@ -98,6 +98,9 @@ struct DeviceExprChecker
                 "not yet implemented: CUDA dynamic parallelism"_err_en_US);
           }
         }
+        if (!subp->openACCRoutineInfos().empty()) {
+          return {};
+        }
       }
 
       const Symbol &ultimate{sym->GetUltimate()};

diff  --git a/flang/test/Fir/CUDA/cuda-device-func-transform.mlir b/flang/test/Fir/CUDA/cuda-device-func-transform.mlir
index fae01500edd72..427381732630d 100644
--- a/flang/test/Fir/CUDA/cuda-device-func-transform.mlir
+++ b/flang/test/Fir/CUDA/cuda-device-func-transform.mlir
@@ -201,3 +201,23 @@ func.func @_QPsub_maxtnid_only() attributes {cuf.launch_bounds = #cuf.launch_bou
 
 // CHECK: gpu.func @_QPsub_maxtnid_only() kernel attributes {nvvm.maxntid = array<i32: 256, 1, 1>}
 // CHECK-NOT: nvvm.minctasm
+
+// -----
+
+// ACC routines are materialized and moved to the GPU module later by the
+// OpenACC pipeline. Do not clone them while collecting CUDA device callees.
+func.func @acc_routine() attributes {acc.routine_info = #acc.routine_info<[@acc_routine_info]>} {
+  return
+}
+
+func.func @cuda_global() attributes {cuf.proc_attr = #cuf.cuda_proc<global>} {
+  fir.call @acc_routine() : () -> ()
+  return
+}
+
+// CHECK-LABEL: func.func @acc_routine()
+// CHECK-LABEL: gpu.module @cuda_device_mod
+// CHECK-NOT: func.func @acc_routine()
+// CHECK-NOT: gpu.func @acc_routine()
+// CHECK: gpu.func @cuda_global() kernel
+// CHECK: fir.call @acc_routine() : () -> ()


        


More information about the flang-commits mailing list