Skip to content

Commit 77613aa

Browse files
authored
[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`.
1 parent 13cd700 commit 77613aa

File tree

3 files changed

+175
-2
lines changed

3 files changed

+175
-2
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9913,6 +9913,13 @@ void ResolveNamesVisitor::FinishSpecificationPart(
99139913
SetBindNameOn(symbol);
99149914
}
99159915
}
9916+
// -gpu=mem:managed: implicitly treat allocatable arrays as managed.
9917+
// This is done after all explicit CUDA attributes have been processed.
9918+
if (context().languageFeatures().IsEnabled(
9919+
common::LanguageFeature::CudaManaged))
9920+
if (auto *object{symbol.detailsIf<ObjectEntityDetails>()})
9921+
if (IsAllocatable(symbol) && !object->cudaDataAttr())
9922+
object->set_cudaDataAttr(common::CUDADataAttr::Managed);
99169923
}
99179924
currScope().InstantiateDerivedTypes();
99189925
for (const auto &decl : decls) {
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
! RUN: bbc -emit-hlfir -fcuda -gpu=mem:managed %s -o - | FileCheck %s
2+
3+
! Test -gpu=managed flag: allocatable arrays without explicit CUDA attributes
4+
! should be implicitly treated as managed.
5+
6+
! -----------------------------------------------------------------------------
7+
! Test 1: Basic allocatable without explicit attribute becomes managed
8+
! -----------------------------------------------------------------------------
9+
subroutine test_implicit_managed()
10+
real, allocatable :: a(:)
11+
allocate(a(100))
12+
a = 1.0
13+
deallocate(a)
14+
end subroutine
15+
16+
! CHECK-LABEL: func.func @_QPtest_implicit_managed()
17+
! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_implicit_managedEa"}
18+
! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
19+
! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_implicit_managedEa"}
20+
! CHECK: cuf.allocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
21+
! CHECK: cuf.deallocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
22+
! CHECK: cuf.free %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<managed>}
23+
24+
! -----------------------------------------------------------------------------
25+
! Test 2: Explicit device attribute is preserved (not overridden to managed)
26+
! -----------------------------------------------------------------------------
27+
subroutine test_explicit_device()
28+
real, allocatable, device :: d(:)
29+
allocate(d(100))
30+
deallocate(d)
31+
end subroutine
32+
33+
! CHECK-LABEL: func.func @_QPtest_explicit_device()
34+
! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "d", data_attr = #cuf.cuda<device>, uniq_name = "_QFtest_explicit_deviceEd"}
35+
! CHECK: fir.embox {{.*}} {allocator_idx = 2 : i32}
36+
! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_deviceEd"}
37+
! CHECK: cuf.allocate %[[BOX_DECL]]#0 : {{.*}} {data_attr = #cuf.cuda<device>}
38+
39+
! -----------------------------------------------------------------------------
40+
! Test 3: Explicit pinned attribute is preserved
41+
! -----------------------------------------------------------------------------
42+
subroutine test_explicit_pinned()
43+
real, allocatable, pinned :: p(:)
44+
allocate(p(100))
45+
deallocate(p)
46+
end subroutine
47+
48+
! CHECK-LABEL: func.func @_QPtest_explicit_pinned()
49+
! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "p", data_attr = #cuf.cuda<pinned>, uniq_name = "_QFtest_explicit_pinnedEp"}
50+
! CHECK: fir.embox {{.*}} {allocator_idx = 1 : i32}
51+
! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<pinned>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_pinnedEp"}
52+
53+
! -----------------------------------------------------------------------------
54+
! Test 4: Explicit managed attribute is preserved (redundant but valid)
55+
! -----------------------------------------------------------------------------
56+
subroutine test_explicit_managed()
57+
real, allocatable, managed :: m(:)
58+
allocate(m(100))
59+
deallocate(m)
60+
end subroutine
61+
62+
! CHECK-LABEL: func.func @_QPtest_explicit_managed()
63+
! CHECK: %[[BOX:.*]] = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "m", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_explicit_managedEm"}
64+
! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
65+
! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_explicit_managedEm"}
66+
67+
! -----------------------------------------------------------------------------
68+
! Test 5: Pointer variables are NOT affected by -gpu=managed
69+
! -----------------------------------------------------------------------------
70+
subroutine test_pointer_not_managed()
71+
real, pointer :: ptr(:)
72+
allocate(ptr(100))
73+
ptr = 1.0
74+
deallocate(ptr)
75+
end subroutine
76+
77+
! CHECK-LABEL: func.func @_QPtest_pointer_not_managed()
78+
! CHECK: %[[BOX:.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xf32>>> {bindc_name = "ptr", uniq_name = "_QFtest_pointer_not_managedEptr"}
79+
! CHECK-NOT: data_attr = #cuf.cuda<managed>
80+
! CHECK: %[[BOX_DECL:.*]]:2 = hlfir.declare %[[BOX]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFtest_pointer_not_managedEptr"}
81+
! CHECK: fir.call @_FortranAPointerAllocate
82+
83+
! -----------------------------------------------------------------------------
84+
! Test 6: Multiple allocatables - mix of implicit and explicit
85+
! -----------------------------------------------------------------------------
86+
subroutine test_mixed_allocatables()
87+
real, allocatable :: a(:) ! Should become managed
88+
real, allocatable, device :: d(:) ! Should stay device
89+
real, allocatable, pinned :: p(:) ! Should stay pinned
90+
real, allocatable, managed :: m(:) ! Should stay managed (explicit)
91+
92+
allocate(a(10), d(10), p(10), m(10))
93+
deallocate(a, d, p, m)
94+
end subroutine
95+
96+
! CHECK-LABEL: func.func @_QPtest_mixed_allocatables()
97+
! CHECK: cuf.alloc {{.*}} {bindc_name = "a", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_mixed_allocatablesEa"}
98+
! CHECK: cuf.alloc {{.*}} {bindc_name = "d", data_attr = #cuf.cuda<device>, uniq_name = "_QFtest_mixed_allocatablesEd"}
99+
! CHECK: cuf.alloc {{.*}} {bindc_name = "m", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_mixed_allocatablesEm"}
100+
! CHECK: cuf.alloc {{.*}} {bindc_name = "p", data_attr = #cuf.cuda<pinned>, uniq_name = "_QFtest_mixed_allocatablesEp"}
101+
102+
! -----------------------------------------------------------------------------
103+
! Test 7: Multi-dimensional allocatable array
104+
! -----------------------------------------------------------------------------
105+
subroutine test_multidim()
106+
real, allocatable :: arr(:,:,:)
107+
allocate(arr(10,20,30))
108+
arr = 0.0
109+
deallocate(arr)
110+
end subroutine
111+
112+
! CHECK-LABEL: func.func @_QPtest_multidim()
113+
! CHECK: cuf.alloc {{.*}} {bindc_name = "arr", data_attr = #cuf.cuda<managed>, uniq_name = "_QFtest_multidimEarr"}
114+
! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
115+
116+
! -----------------------------------------------------------------------------
117+
! Test 8: Explicit unified attribute is preserved (not overridden to managed)
118+
! -----------------------------------------------------------------------------
119+
subroutine test_explicit_unified()
120+
real, allocatable, unified :: u(:)
121+
allocate(u(100))
122+
deallocate(u)
123+
end subroutine
124+
125+
! CHECK-LABEL: func.func @_QPtest_explicit_unified()
126+
! CHECK: cuf.alloc {{.*}} {bindc_name = "u", data_attr = #cuf.cuda<unified>, uniq_name = "_QFtest_explicit_unifiedEu"}
127+
! CHECK: hlfir.declare {{.*}} {data_attr = #cuf.cuda<unified>, fortran_attrs = #fir.var_attrs<allocatable>
128+
129+
! -----------------------------------------------------------------------------
130+
! Test 9: Dummy arguments - allocatable dummy without explicit attribute
131+
! -----------------------------------------------------------------------------
132+
subroutine test_dummy_allocatable(arr)
133+
real, allocatable, intent(inout) :: arr(:)
134+
if (.not. allocated(arr)) allocate(arr(100))
135+
arr = 1.0
136+
end subroutine
137+
138+
! CHECK-LABEL: func.func @_QPtest_dummy_allocatable(
139+
! CHECK-SAME: %{{.*}}: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {cuf.data_attr = #cuf.cuda<managed>, fir.bindc_name = "arr"})
140+
! CHECK: hlfir.declare {{.*}} {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<allocatable, intent_inout>
141+
142+
! -----------------------------------------------------------------------------
143+
! Test 10: Module variables - allocatable module variable becomes managed
144+
! -----------------------------------------------------------------------------
145+
module mod_globals
146+
real, allocatable :: global_arr(:)
147+
real, allocatable, device :: global_device(:)
148+
end module
149+
150+
! CHECK: fir.global @_QMmod_globalsEglobal_arr {data_attr = #cuf.cuda<managed>} : !fir.box<!fir.heap<!fir.array<?xf32>>>
151+
! CHECK: fir.embox {{.*}} {allocator_idx = 3 : i32}
152+
153+
! CHECK: fir.global @_QMmod_globalsEglobal_device {data_attr = #cuf.cuda<device>} : !fir.box<!fir.heap<!fir.array<?xf32>>>
154+
! CHECK: fir.embox {{.*}} {allocator_idx = 2 : i32}
155+
156+
subroutine test_module_var()
157+
use mod_globals
158+
allocate(global_arr(50))
159+
allocate(global_device(50))
160+
deallocate(global_arr)
161+
deallocate(global_device)
162+
end subroutine
163+
164+
! CHECK-LABEL: func.func @_QPtest_module_var()
165+
! CHECK: cuf.allocate {{.*}} {data_attr = #cuf.cuda<managed>, hasDoubleDescriptor}
166+
! CHECK: cuf.allocate {{.*}} {data_attr = #cuf.cuda<device>, hasDoubleDescriptor}

flang/tools/bbc/bbc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,9 +638,9 @@ int main(int argc, char **argv) {
638638
Fortran::common::LanguageFeature::CudaWarpMatchFunction, false);
639639
}
640640

641-
if (enableGPUMode == "managed") {
641+
if (enableGPUMode == "managed" || enableGPUMode == "mem:managed") {
642642
options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);
643-
} else if (enableGPUMode == "unified") {
643+
} else if (enableGPUMode == "unified" || enableGPUMode == "mem:unified") {
644644
options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);
645645
}
646646

0 commit comments

Comments
 (0)