[flang-commits] [flang] [flang][OpenACC] Preserve compute bindings for CUDA DEVICE arguments (PR #229420)
via flang-commits
flang-commits at lists.llvm.org
Wed Oct 7 00:10:56 PDT 2026
https://github.com/jeanPerier updated https://github.com/llvm/llvm-project/pull/229420
>From 49b81fae7bc4b472ab84898b1e6233e371b15ef2 Mon Sep 17 00:00:00 2001
From: Jean Perier <jperier at nvidia.com>
Date: Tue, 6 Oct 2026 06:04:47 -0700
Subject: [PATCH] [flang][OpenACC] Preserve compute bindings for CUDA DEVICE
arguments
Only use alternate bindings from enclosing structured data constructs for calls outside OpenACC compute constructs. Inside compute constructs, use the ordinary symbol binding so data legalization can find the mapping and explicit mappings or privatization are respected.
---
flang/lib/Lower/ConvertCall.cpp | 6 +
.../OpenACC/acc-data-cuda-device-compute.f90 | 135 ++++++++++++++++++
2 files changed, 141 insertions(+)
create mode 100644 flang/test/Lower/OpenACC/acc-data-cuda-device-compute.f90
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 6cb12b8208203..b6fc18dbe41d0 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -19,6 +19,7 @@
#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/CustomIntrinsicCall.h"
#include "flang/Lower/HlfirIntrinsics.h"
+#include "flang/Lower/OpenACC.h"
#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/StatementContext.h"
#include "flang/Lower/SymbolMap.h"
@@ -3337,8 +3338,13 @@ genProcedureRef(CallContext &callContext) {
// binding must be in place for this lowering, which is the only one of
// the actual argument: lowering it again would duplicate any side
// effect of its subscripts.
+ // Inside OpenACC compute constructs, keep the ordinary binding so that
+ // calls use the same mapping as other references, including any mapping
+ // or privatization on the compute construct itself. The OpenACC data
+ // legalization handles references to enclosing data constructs.
std::optional<Fortran::lower::SymMapScope> deviceScope;
if (!isKernelLaunch && isCUDADeviceDummy(arg.characteristics) &&
+ !Fortran::lower::isInsideOpenACCComputeConstruct(builder) &&
Fortran::evaluate::IsVariable(*expr)) {
deviceScope.emplace(callContext.symMap);
if (!mapOpenACCDeviceBindings(*expr, callContext.symMap))
diff --git a/flang/test/Lower/OpenACC/acc-data-cuda-device-compute.f90 b/flang/test/Lower/OpenACC/acc-data-cuda-device-compute.f90
new file mode 100644
index 0000000000000..97ab6569e7455
--- /dev/null
+++ b/flang/test/Lower/OpenACC/acc-data-cuda-device-compute.f90
@@ -0,0 +1,135 @@
+! RUN: bbc -fopenacc -fcuda -emit-hlfir %s -o - | FileCheck %s
+
+! Calls inside compute constructs must use the ordinary symbol binding, like
+! other references in the construct. A DEVICE dummy must not override it with
+! the alternate binding of an enclosing data construct.
+module compute_calls
+ interface
+ attributes(device) subroutine device_sub(a)
+ real :: a(*)
+ end subroutine
+ subroutine host_sub(a)
+ real, device :: a(*)
+ end subroutine
+ attributes(device) subroutine device_c(a) bind(c)
+ real :: a(*)
+ end subroutine
+ end interface
+contains
+ subroutine implicit_mapping(a, n)
+ real :: a(100)
+ integer :: n, i
+ !$acc data copy(a)
+ call host_sub(a)
+ !$acc parallel
+ if (n > 0) call device_sub(a)
+ !$acc end parallel
+ !$acc serial
+ call device_sub(a)
+ !$acc end serial
+ !$acc kernels
+ call device_sub(a)
+ !$acc end kernels
+ !$acc parallel loop
+ do i = 1, n
+ call device_sub(a)
+ end do
+ !$acc end parallel loop
+ !$acc serial loop
+ do i = 1, n
+ call device_sub(a)
+ end do
+ !$acc end serial loop
+ !$acc kernels loop
+ do i = 1, n
+ call device_sub(a)
+ end do
+ !$acc end kernels loop
+ call host_sub(a)
+ !$acc end data
+ end subroutine
+
+! CHECK-LABEL: func.func @_QMcompute_callsPimplicit_mapping
+! CHECK: %[[HOST:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QMcompute_callsFimplicit_mappingEa")
+! CHECK: %[[COPY:.*]] = acc.copyin varPtr(%[[HOST]]#0
+! CHECK: acc.data dataOperands(%[[COPY]]
+! CHECK: %[[DEVICE:.*]]:2 = hlfir.declare %[[COPY]]
+! CHECK: %[[ARG:.*]] = fir.convert %[[DEVICE]]#0
+! CHECK: fir.call @_QPhost_sub(%[[ARG]])
+! CHECK: acc.parallel
+! CHECK: fir.if
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: acc.serial
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: acc.kernels
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: acc.parallel combined(loop)
+! CHECK: acc.loop
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: acc.serial combined(loop)
+! CHECK: acc.loop
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: acc.kernels combined(loop)
+! CHECK: acc.loop
+! CHECK: %[[ARG:.*]] = fir.convert %[[HOST]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: %[[ARG:.*]] = fir.convert %[[DEVICE]]#0
+! CHECK: fir.call @_QPhost_sub(%[[ARG]])
+
+ subroutine explicit_mapping(a)
+ real :: a(100)
+ !$acc data copy(a)
+ !$acc parallel present(a)
+ call device_sub(a)
+ !$acc end parallel
+ !$acc serial private(a)
+ call device_sub(a)
+ !$acc end serial
+ !$acc kernels present(a)
+ call device_sub(a)
+ !$acc end kernels
+ !$acc end data
+ end subroutine
+
+! CHECK-LABEL: func.func @_QMcompute_callsPexplicit_mapping
+! CHECK: %[[HOST:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QMcompute_callsFexplicit_mappingEa")
+! CHECK: acc.data
+! CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[HOST]]#0
+! CHECK: acc.parallel dataOperands(%[[PRESENT]]
+! CHECK: %[[LOCAL:.*]]:2 = hlfir.declare %[[PRESENT]]
+! CHECK: %[[ARG:.*]] = fir.convert %[[LOCAL]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: %[[PRIVATE:.*]] = acc.private varPtr(%[[HOST]]#0
+! CHECK: acc.serial private(
+! CHECK: %[[LOCAL:.*]]:2 = hlfir.declare %[[PRIVATE]]
+! CHECK: %[[ARG:.*]] = fir.convert %[[LOCAL]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+! CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[HOST]]#0
+! CHECK: acc.kernels dataOperands(%[[PRESENT]]
+! CHECK: %[[LOCAL:.*]]:2 = hlfir.declare %[[PRESENT]]
+! CHECK: %[[ARG:.*]] = fir.convert %[[LOCAL]]#0
+! CHECK: fir.call @_QPdevice_sub(%[[ARG]])
+
+ subroutine allocatable_mapping(a)
+ real, allocatable :: a(:)
+ !$acc data copy(a)
+ !$acc parallel
+ call device_c(a)
+ !$acc end parallel
+ !$acc end data
+ end subroutine
+
+! CHECK-LABEL: func.func @_QMcompute_callsPallocatable_mapping
+! CHECK: %[[HOST:.*]]:2 = hlfir.declare %{{.*}} uniq_name("_QMcompute_callsFallocatable_mappingEa")
+! CHECK: acc.data
+! CHECK: acc.parallel
+! CHECK: %[[BOX:.*]] = fir.load %[[HOST]]#0
+! CHECK: %[[ADDR:.*]] = fir.box_addr %[[BOX]]
+! CHECK: %[[ARG:.*]] = fir.convert %[[ADDR]]
+! CHECK: fir.call @device_c(%[[ARG]])
+end module
More information about the flang-commits
mailing list