// RUN: fir-opt --split-input-file --cuf-device-global %s | FileCheck %s // RUN: fir-opt --split-input-file --cuf-device-global="cuda-unified=true" %s | FileCheck %s --check-prefix=UNIFIED module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMmtestsEn(dense<[3, 4, 5, 6, 7]> : tensor<5xi32>) {data_attr = #cuf.cuda} : !fir.array<5xi32> gpu.module @cuda_device_mod { } } // CHECK: gpu.module @cuda_device_mo // CHECK-NEXT: fir.global @_QMmtestsEn(dense<[3, 4, 5, 6, 7]> : tensor<5xi32>) {data_attr = #cuf.cuda} : !fir.array<5xi32> // ----- module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMm1ECb(dense<[90, 100, 110]> : tensor<3xi32>) constant : !fir.array<3xi32> fir.global @_QMm2ECc(dense<[100, 200, 300]> : tensor<3xi32>) constant : !fir.array<3xi32> } // CHECK: fir.global @_QMm1ECb // CHECK: fir.global @_QMm2ECc // CHECK: gpu.module @cuda_device_mod // CHECK-DAG: fir.global @_QMm2ECc // CHECK-DAG: fir.global @_QMm1ECb // ----- module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMmEddarrays {data_attr = #cuf.cuda} : !fir.box>>,phi_i:!fir.box>>,phi0_r:!fir.box>>,phi0_i:!fir.box>>,buf_r:!fir.box>>,buf_i:!fir.box>>}>>>> { %c0 = arith.constant 0 : index %0 = fir.zero_bits !fir.heap>>,phi_i:!fir.box>>,phi0_r:!fir.box>>,phi0_i:!fir.box>>,buf_r:!fir.box>>,buf_i:!fir.box>>}>>> %1 = fir.shape %c0 : (index) -> !fir.shape<1> %2 = fir.embox %0(%1) {allocator_idx = 3 : i32} : (!fir.heap>>,phi_i:!fir.box>>,phi0_r:!fir.box>>,phi0_i:!fir.box>>,buf_r:!fir.box>>,buf_i:!fir.box>>}>>>, !fir.shape<1>) -> !fir.box>>,phi_i:!fir.box>>,phi0_r:!fir.box>>,phi0_i:!fir.box>>,buf_r:!fir.box>>,buf_i:!fir.box>>}>>>> fir.has_value %2 : !fir.box>>,phi_i:!fir.box>>,phi0_r:!fir.box>>,phi0_i:!fir.box>>,buf_r:!fir.box>>,buf_i:!fir.box>>}>>>> } fir.global linkonce_odr @_QMmE.dt.devicearrays constant target : !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> { %0 = fir.undefined !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> fir.has_value %0 : !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,__padding0:!fir.array<4xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> } } // CHECK-NAG: fir.global @_QMmEddarrays // CHECK-NAG: fir.global linkonce_odr @_QMmE.dt.devicearrays // CHECK: gpu.module @cuda_device_mod // CHECK-NAG: fir.global @_QMmEddarrays // CHECK-NAG: fir.global linkonce_odr @_QMmE.dt.devicearrays // ----- module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { func.func @_QMmod1Ptest1() attributes {cuf.proc_attr = #cuf.cuda_proc} { %34 = fir.alloca !fir.type<_QMvector_typesTv2real2{x:f16,y:f16}> {bindc_name = "cv", uniq_name = "_QMmod1Ftest1Ecv"} return } fir.global linkonce_odr @_QMvector_typesE.dt.v2real2 constant : !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,memoryspace:i8,__padding0:!fir.array<3xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> { %0 = fir.undefined !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,memoryspace:i8,__padding0:!fir.array<3xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> fir.has_value %0 : !fir.type<_QM__fortran_type_infoTderivedtype{binding:!fir.box,name:!fir.box>>}>>>>,name:!fir.box>>,sizeinbytes:i64,uninstantiated:!fir.box>>,kindparameter:!fir.box>>,lenparameterkind:!fir.box>>,component:!fir.box>>,genre:i8,category:i8,kind:i8,rank:i8,memoryspace:i8,__padding0:!fir.array<3xi8>,offset:i64,characterlen:!fir.type<_QM__fortran_type_infoTvalue{genre:i8,__padding0:!fir.array<7xi8>,value:i64}>,derived:!fir.box>>,lenvalue:!fir.box,value:i64}>>>>,bounds:!fir.box,value:i64}>>>>,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>>>>,procptr:!fir.box>>,offset:i64,initialization:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,special:!fir.box,proc:!fir.type<_QM__fortran_builtinsT__builtin_c_funptr{__address:i64}>}>>>>,specialbitset:i32,hasparent:i8,noinitializationneeded:i8,nodestructionneeded:i8,nofinalizationneeded:i8,nodefinedassignment:i8,__padding0:!fir.array<3xi8>}> } } // CHECK-LABEL: func.func @_QMmod1Ptest1() // CHECK: fir.global linkonce_odr @_QMvector_typesE.dt.v2real2 // CHECK-LABEL: gpu.module @cuda_device_mod // CHECK: fir.global linkonce_odr @_QMvector_typesE.dt.v2real2 // ----- // Test that when a global already exists in the gpu.module, the pass // continues cloning the remaining candidates instead of stopping. module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMmEa(dense<[1, 2, 3]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32> fir.global @_QMmEb(dense<[10, 20, 30]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32> fir.global @_QMmEc(dense<[100, 200, 300]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32> gpu.module @cuda_device_mod { fir.global @_QMmEa(dense<[1, 2, 3]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32> } } // CHECK: gpu.module @cuda_device_mod // CHECK-DAG: fir.global @_QMmEa // CHECK-DAG: fir.global @_QMmEb // CHECK-DAG: fir.global @_QMmEc // ----- // Under -gpu=mem:unified (cuda-unified=true), plain host module-scope // variables referenced from device code are mirrored as no-body external // declarations in the GPU module. PTX lowers them as `.extern .global ...`. // CUFAddConstructor + the runtime then map the device-side extern to the // host pointer via __cudaRegisterHostVar. module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMmtestsEm(dense<[1, 2, 3, 4, 5]> : tensor<5xi32>) : !fir.array<5xi32> func.func @_QMmtestsPg1() attributes {cuf.proc_attr = #cuf.cuda_proc} { %0 = fir.address_of(@_QMmtestsEm) : !fir.ref> return } } // Host-side definition is preserved. // UNIFIED: fir.global @_QMmtestsEm(dense<[1, 2, 3, 4, 5]> : tensor<5xi32>) : !fir.array<5xi32> // GPU-module clone is an external declaration (no init body, no `dense<...>`). // UNIFIED: gpu.module @cuda_device_mod // UNIFIED: fir.global @_QMmtestsEm : !fir.array<5xi32> // UNIFIED-NOT: fir.global @_QMmtestsEm{{.*}}dense // ----- // Globals with an explicit CUF data attribute (device, managed, constant) // keep their existing definition-clone path even with cuda-unified=true. module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module} { fir.global @_QMmtestsEdev(dense<[1, 2, 3]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32> func.func @_QMmtestsPg1() attributes {cuf.proc_attr = #cuf.cuda_proc} { %0 = fir.address_of(@_QMmtestsEdev) : !fir.ref> return } } // UNIFIED: gpu.module @cuda_device_mod // UNIFIED: fir.global @_QMmtestsEdev(dense<[1, 2, 3]> : tensor<3xi32>) {data_attr = #cuf.cuda} : !fir.array<3xi32>