[flang-commits] [flang] 77613aa - [flang][CUDA] Apply implicit managed attribute when `-gpu=mem:managed` is used. (#175648)
via flang-commits
flang-commits at lists.llvm.org
Mon Jan 12 18:07:34 PST 2026
Author: Zhen Wang
Date: 2026-01-13T02:07:29Z
New Revision: 77613aa7ead051471a32c679ffc2e6ce60751a2f
URL: https://github.com/llvm/llvm-project/commit/77613aa7ead051471a32c679ffc2e6ce60751a2f
DIFF: https://github.com/llvm/llvm-project/commit/77613aa7ead051471a32c679ffc2e6ce60751a2f.diff
LOG: [flang][CUDA] Apply implicit managed attribute when `-gpu=mem:managed` is used. (#175648)
When `-gpu=mem:managed` is used, allocatable arrays without explicit
CUDA data attributes are implicitly treated as managed. The
`-gpu=mem:managed` flag to enable this feature is currently only
supported in `bbc`.
Added:
flang/test/Lower/CUDA/cuda-gpu-managed.cuf
Modified:
flang/lib/Semantics/resolve-names.cpp
flang/tools/bbc/bbc.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 47ca433e0f7aa..d2a3331710dba 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9913,6 +9913,13 @@ void ResolveNamesVisitor::FinishSpecificationPart(
SetBindNameOn(symbol);
}
}
+ // -gpu=mem:managed: implicitly treat allocatable arrays as managed.
+ // This is done after all explicit CUDA attributes have been processed.
+ if (context().languageFeatures().IsEnabled(
+ common::LanguageFeature::CudaManaged))
+ if (auto *object{symbol.detailsIf<ObjectEntityDetails>()})
+ if (IsAllocatable(symbol) && !object->cudaDataAttr())
+ object->set_cudaDataAttr(common::CUDADataAttr::Managed);
}
currScope().InstantiateDerivedTypes();
for (const auto &decl : decls) {
diff --git a/flang/test/Lower/CUDA/cuda-gpu-managed.cuf b/flang/test/Lower/CUDA/cuda-gpu-managed.cuf
new file mode 100644
index 0000000000000..b015b470b921b
--- /dev/null
+++ b/flang/test/Lower/CUDA/cuda-gpu-managed.cuf
@@ -0,0 +1,166 @@
+! RUN: bbc -emit-hlfir -fcuda -gpu=mem:managed %s -o - | FileCheck %s
+
+! Test -gpu=managed flag: allocatable arrays without explicit CUDA attributes
+! should be implicitly treated as managed.
+
+! -----------------------------------------------------------------------------
+! Test 1: Basic allocatable without explicit attribute becomes managed
+! -----------------------------------------------------------------------------
+subroutine test_implicit_managed()
+ real, allocatable :: a(:)
+ allocate(a(100))
+ a = 1.0
+ deallocate(a)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_implicit_managed()
+! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_implicit_managedEa"}
+! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
+! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_implicit_managedEa"}
+! CHECK: cuf.allocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
+! CHECK: cuf.deallocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
+! CHECK: cuf.free %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
+
+! -----------------------------------------------------------------------------
+! Test 2: Explicit device attribute is preserved (not overridden to managed)
+! -----------------------------------------------------------------------------
+subroutine test_explicit_device()
+ real, allocatable, device :: d(:)
+ allocate(d(100))
+ deallocate(d)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_explicit_device()
+! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "d", data_attr = #cuf.cuda<device>, uniq_name = "_QFtest_explicit_deviceEd"}
+! CHECK: fir.embox {{.*}} {allocator_idx = 2 : i32}
+! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_deviceEd"}
+! CHECK: cuf.allocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<device>}
+
+! -----------------------------------------------------------------------------
+! Test 3: Explicit pinned attribute is preserved
+! -----------------------------------------------------------------------------
+subroutine test_explicit_pinned()
+ real, allocatable, pinned :: p(:)
+ allocate(p(100))
+ deallocate(p)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_explicit_pinned()
+! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "p", data_attr = #cuf.cuda<pinned>, uniq_name = "_QFtest_explicit_pinnedEp"}
+! CHECK: fir.embox {{.*}} {allocator_idx = 1 : i32}
+! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<pinned>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_pinnedEp"}
+
+! -----------------------------------------------------------------------------
+! Test 4: Explicit managed attribute is preserved (redundant but valid)
+! -----------------------------------------------------------------------------
+subroutine test_explicit_managed()
+ real, allocatable, managed :: m(:)
+ allocate(m(100))
+ deallocate(m)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_explicit_managed()
+! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "m", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_explicit_managedEm"}
+! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
+! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_managedEm"}
+
+! -----------------------------------------------------------------------------
+! Test 5: Pointer variables are NOT affected by -gpu=managed
+! -----------------------------------------------------------------------------
+subroutine test_pointer_not_managed()
+ real, pointer :: ptr(:)
+ allocate(ptr(100))
+ ptr = 1.0
+ deallocate(ptr)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_pointer_not_managed()
+! CHECK: %[[BOX:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {bindc_name = "ptr", uniq_name = "_QFtest_pointer_not_managedEptr"}
+! CHECK-NOT: data_attr = #cuf.cuda<managed>
+! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtest_pointer_not_managedEptr"}
+! CHECK: fir.call @_FortranAPointerAllocate
+
+! -----------------------------------------------------------------------------
+! Test 6: Multiple allocatables - mix of implicit and explicit
+! -----------------------------------------------------------------------------
+subroutine test_mixed_allocatables()
+ real, allocatable :: a(:) ! Should become managed
+ real, allocatable, device :: d(:) ! Should stay device
+ real, allocatable, pinned :: p(:) ! Should stay pinned
+ real, allocatable, managed :: m(:) ! Should stay managed (explicit)
+
+ allocate(a(10), d(10), p(10), m(10))
+ deallocate(a, d, p, m)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_mixed_allocatables()
+! CHECK: cuf.alloc {{.*}} {bindc_name = "a", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_mixed_allocatablesEa"}
+! CHECK: cuf.alloc {{.*}} {bindc_name = "d", data_attr = #cuf.cuda<device>, uniq_name = "_QFtest_mixed_allocatablesEd"}
+! CHECK: cuf.alloc {{.*}} {bindc_name = "m", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_mixed_allocatablesEm"}
+! CHECK: cuf.alloc {{.*}} {bindc_name = "p", data_attr = #cuf.cuda<pinned>, uniq_name = "_QFtest_mixed_allocatablesEp"}
+
+! -----------------------------------------------------------------------------
+! Test 7: Multi-dimensional allocatable array
+! -----------------------------------------------------------------------------
+subroutine test_multidim()
+ real, allocatable :: arr(:,:,:)
+ allocate(arr(10,20,30))
+ arr = 0.0
+ deallocate(arr)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_multidim()
+! CHECK: cuf.alloc {{.*}} {bindc_name = "arr", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_multidimEarr"}
+! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
+
+! -----------------------------------------------------------------------------
+! Test 8: Explicit unified attribute is preserved (not overridden to managed)
+! -----------------------------------------------------------------------------
+subroutine test_explicit_unified()
+ real, allocatable, unified :: u(:)
+ allocate(u(100))
+ deallocate(u)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_explicit_unified()
+! CHECK: cuf.alloc {{.*}} {bindc_name = "u", data_attr = #cuf.cuda<unified>, uniq_name = "_QFtest_explicit_unifiedEu"}
+! CHECK: hlfir.declare {{.*}} {data_attr = #cuf.cuda<unified>, fortran_attrs = #fir.var_attrs<allocatable>
+
+! -----------------------------------------------------------------------------
+! Test 9: Dummy arguments - allocatable dummy without explicit attribute
+! -----------------------------------------------------------------------------
+subroutine test_dummy_allocatable(arr)
+ real, allocatable, intent(inout) :: arr(:)
+ if (.not. allocated(arr)) allocate(arr(100))
+ arr = 1.0
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_dummy_allocatable(
+! CHECK-SAME: %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {cuf.data_attr = #cuf.cuda<managed>, fir.bindc_name = "arr"})
+! CHECK: hlfir.declare {{.*}} {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable, intent_inout>
+
+! -----------------------------------------------------------------------------
+! Test 10: Module variables - allocatable module variable becomes managed
+! -----------------------------------------------------------------------------
+module mod_globals
+ real, allocatable :: global_arr(:)
+ real, allocatable, device :: global_device(:)
+end module
+
+! CHECK: fir.global @_QMmod_globalsEglobal_arr {data_attr = #cuf.cuda<managed>} : !fir.box<!fir.heap<!fir.array<?xf32>>>
+! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
+
+! CHECK: fir.global @_QMmod_globalsEglobal_device {data_attr = #cuf.cuda<device>} : !fir.box<!fir.heap<!fir.array<?xf32>>>
+! CHECK: fir.embox {{.*}} {allocator_idx = 2 : i32}
+
+subroutine test_module_var()
+ use mod_globals
+ allocate(global_arr(50))
+ allocate(global_device(50))
+ deallocate(global_arr)
+ deallocate(global_device)
+end subroutine
+
+! CHECK-LABEL: func.func @_QPtest_module_var()
+! CHECK: cuf.allocate {{.*}} {data_attr = #cuf.cuda<managed>, hasDoubleDescriptor}
+! CHECK: cuf.allocate {{.*}} {data_attr = #cuf.cuda<device>, hasDoubleDescriptor}
diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp
index 607ac5c82cec4..aefb4369fc761 100644
--- a/flang/tools/bbc/bbc.cpp
+++ b/flang/tools/bbc/bbc.cpp
@@ -638,9 +638,9 @@ int main(int argc, char **argv) {
Fortran::common::LanguageFeature::CudaWarpMatchFunction, false);
}
- if (enableGPUMode == "managed") {
+ if (enableGPUMode == "managed" || enableGPUMode == "mem:managed") {
options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);
- } else if (enableGPUMode == "unified") {
+ } else if (enableGPUMode == "unified" || enableGPUMode == "mem:unified") {
options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);
}
More information about the flang-commits
mailing list