[flang-commits] [flang] [flang][cuda] Allocate adjustable automatic arrays in unified/managed memory (PR #212965)

via flang-commits flang-commits at lists.llvm.org
Thu Jul 30 02:12:36 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Matsu (khaki3)

<details>
<summary>Changes</summary>

Example:
```fortran
subroutine work(n)
  integer :: n
  complex(8) :: ar_tmp(n)   ! adjustable/VLA automatic
  !$acc host_data use_device(ar_tmp)
  ! ... device use ...
  !$acc end host_data
end
```

In this code, under `-gpu=mem:unified` (or `managed`) a dynamic-extent automatic array must be allocated in CUDA unified/managed memory so the host pointer is device-shared. Fixed-size locals (`ar_tmp(128)`) stay on the stack. Leaving VLAs on the ordinary host heap breaks unified-memory OpenACC device access.

Fix: under those GPU mem features, tag non-dummy explicit-shape automatic arrays with a non-constant bound as Unified/Managed in semantics so lowering uses `cuf.alloc`/`cuf.free`.


---
Full diff: https://github.com/llvm/llvm-project/pull/212965.diff


2 Files Affected:

- (modified) flang/lib/Semantics/resolve-names.cpp (+31) 
- (added) flang/test/Lower/CUDA/cuda-gpu-unified-automatic-array.f90 (+58) 


``````````diff
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 83d92f253e626..a3514ccf72e5c 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10648,6 +10648,37 @@ void ResolveNamesVisitor::FinishSpecificationPart(
             context().languageFeatures().IsEnabled(
                 common::LanguageFeature::CudaPinned))
           object->set_cudaDataAttr(common::CUDADataAttr::Pinned);
+      } else if (!object->cudaDataAttr() && !IsDummy(symbol) &&
+          !IsAllocatable(symbol) && !IsPointer(symbol) && !IsSaved(symbol) &&
+          !IsCUDADeviceContext(&symbol.owner()) &&
+          object->shape().IsExplicitShape()) {
+        // Under -gpu=mem:unified|managed, allocate adjustable / VLA automatic
+        // arrays in CUDA unified/managed memory (fixed-size automatic arrays
+        // stay on the stack). Tag those locals so lowering uses
+        // cuf.alloc/cuf.free. Unlike the allocatable managed tagging above,
+        // this does not require -fcuda: OpenACC + -gpu=mem:unified relies on
+        // it, and cuf.alloc does not go through the CUDA Fortran
+        // managed-descriptor pipeline that motivated the -fcuda gate.
+        std::optional<common::CUDADataAttr> attr;
+        if (context().languageFeatures().IsEnabled(
+                common::LanguageFeature::CudaUnified))
+          attr = common::CUDADataAttr::Unified;
+        else if (context().languageFeatures().IsEnabled(
+                     common::LanguageFeature::CudaManaged))
+          attr = common::CUDADataAttr::Managed;
+        if (attr) {
+          auto boundIsNonConstant{[](const Bound &b) {
+            return !b.isExplicit() || !b.GetExplicit() ||
+                !evaluate::IsConstantExpr(*b.GetExplicit());
+          }};
+          for (const ShapeSpec &ss : object->shape()) {
+            if (boundIsNonConstant(ss.lbound()) ||
+                boundIsNonConstant(ss.ubound())) {
+              object->set_cudaDataAttr(*attr);
+              break;
+            }
+          }
+        }
       }
     }
   }
diff --git a/flang/test/Lower/CUDA/cuda-gpu-unified-automatic-array.f90 b/flang/test/Lower/CUDA/cuda-gpu-unified-automatic-array.f90
new file mode 100644
index 0000000000000..07638b0ca8dfa
--- /dev/null
+++ b/flang/test/Lower/CUDA/cuda-gpu-unified-automatic-array.f90
@@ -0,0 +1,58 @@
+! RUN: bbc -emit-hlfir -gpu=unified %s -o - | FileCheck %s
+! RUN: bbc -emit-hlfir -gpu=managed %s -o - | FileCheck %s --check-prefix=MANAGED
+
+! Under -gpu=mem:unified|managed, allocate adjustable / VLA automatic arrays
+! in CUDA unified/managed memory. Fixed-size automatic arrays stay on the
+! stack so host pointers remain shared under unified memory (e.g. OpenACC).
+
+module m_adj
+  integer :: nx = 32
+end module
+
+! CHECK-LABEL: func.func @_QPvla(
+! CHECK: %[[ALLOC:.*]] = cuf.alloc !fir.array<?xf32>, %{{.*}} : index {bindc_name = "a", data_attr = #cuf.cuda<unified>, uniq_name = "_QFvlaEa"}
+! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ALLOC]](%{{.*}}) {data_attr = #cuf.cuda<unified>, uniq_name = "_QFvlaEa"}
+! CHECK: cuf.free %[[DECL]]#1 : !fir.ref<!fir.array<?xf32>> {data_attr = #cuf.cuda<unified>}
+! MANAGED-LABEL: func.func @_QPvla(
+! MANAGED: cuf.alloc !fir.array<?xf32>, %{{.*}} : index {{{.*}}data_attr = #cuf.cuda<managed>
+! MANAGED: cuf.free %{{.*}} : !fir.ref<!fir.array<?xf32>> {data_attr = #cuf.cuda<managed>}
+subroutine vla(n)
+  integer :: n
+  real :: a(n)
+  a(1) = 1.0
+end subroutine
+
+! CHECK-LABEL: func.func @_QPadjustable(
+! CHECK: cuf.alloc !fir.array<?xf32>, %{{.*}} : index {{{.*}}data_attr = #cuf.cuda<unified>
+! CHECK: cuf.free %{{.*}} {data_attr = #cuf.cuda<unified>}
+! MANAGED-LABEL: func.func @_QPadjustable(
+! MANAGED: cuf.alloc !fir.array<?xf32>, %{{.*}} : index {{{.*}}data_attr = #cuf.cuda<managed>
+subroutine adjustable
+  use m_adj
+  real :: a(0:(nx+1)/2)
+  a(0) = 0.0
+end subroutine
+
+! Fixed-size automatic arrays must remain ordinary stack allocations.
+! CHECK-LABEL: func.func @_QPfixed(
+! CHECK-NOT: cuf.alloc
+! CHECK: fir.alloca !fir.array<128xf32>
+! CHECK-NOT: cuf.free
+! MANAGED-LABEL: func.func @_QPfixed(
+! MANAGED-NOT: cuf.alloc
+! MANAGED: fir.alloca !fir.array<128xf32>
+subroutine fixed
+  real :: a(128)
+  a(1) = 1.0
+end subroutine
+
+! Dummy adjustable arrays are caller-allocated; do not retag them.
+! CHECK-LABEL: func.func @_QPdummy_adj(
+! CHECK-NOT: cuf.alloc
+! MANAGED-LABEL: func.func @_QPdummy_adj(
+! MANAGED-NOT: cuf.alloc
+subroutine dummy_adj(a, n)
+  integer :: n
+  real :: a(n)
+  a(1) = 1.0
+end subroutine

``````````

</details>


https://github.com/llvm/llvm-project/pull/212965


More information about the flang-commits mailing list