[flang][cuda] Use cuf.register_variable_static instead of CUFRegisterExternalVariable (#211886)
This gives more flexibility to the backend to select a different registration mechanism
This commit is contained in:
parent
f61e1fac80
commit
9d7095fb78
7 changed files with 19 additions and 35 deletions
|
|
@ -48,14 +48,6 @@ void RTDEF(CUFRegisterVariable)(
|
|||
__cudaRegisterVar(module, varSym, varName, varName, 0, size, 0, 0);
|
||||
}
|
||||
|
||||
void RTDEF(CUFRegisterExternalVariable)(
|
||||
void **module, char *varSym, const char *varName, int64_t size) {
|
||||
// Tell the CUDA driver to bind the device-side global <varName> to the
|
||||
// host-resident storage at <varSym>. Kernel accesses to <varName> then go
|
||||
// through the host address; HMM/ATS handles migration.
|
||||
__cudaRegisterHostVar(module, varName, varSym, size);
|
||||
}
|
||||
|
||||
void RTDEF(CUFRegisterManagedVariable)(
|
||||
void **module, void **varSym, char *varName, int64_t size) {
|
||||
__cudaRegisterManagedVar(module, varSym, varName, varName, 0, size, 0, 0);
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ def CUFAddConstructor : Pass<"cuf-add-constructor", "mlir::ModuleOp"> {
|
|||
Option<"cudaUnified", "cuda-unified", "bool", /*default=*/"false",
|
||||
"Treat host module globals as unified memory (-gpu=mem:unified): "
|
||||
"register every plain host module global that is mirrored in the "
|
||||
"GPU module via CUFRegisterExternalVariable, so the CUDA driver "
|
||||
"GPU module via cuf.register_variable_static, so the CUDA driver "
|
||||
"maps the device-side symbol to the host pointer at module-load "
|
||||
"time and HMM/ATS handles migration.">
|
||||
];
|
||||
|
|
|
|||
|
|
@ -28,13 +28,6 @@ void RTDECL(CUFRegisterFunction)(
|
|||
void RTDECL(CUFRegisterVariable)(
|
||||
void **module, char *varSym, const char *varName, int64_t size);
|
||||
|
||||
/// Register a module-scope variable as host-resident under -gpu=mem:unified,
|
||||
/// so that the device-side symbol of the same name is mapped to the host
|
||||
/// pointer at module-load time. Wraps __cudaRegisterHostVar. Kernel accesses
|
||||
/// to the variable then reach the host storage directly via HMM/ATS.
|
||||
void RTDECL(CUFRegisterExternalVariable)(
|
||||
void **module, char *varSym, const char *varName, int64_t size);
|
||||
|
||||
/// Register a managed variable.
|
||||
void RTDECL(CUFRegisterManagedVariable)(
|
||||
void **module, void **varSym, char *varName, int64_t size);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ static fir::GlobalOp createManagedPointerGlobal(fir::FirOpBuilder &builder,
|
|||
/// Return true if \p hostGlobal is a host module-scope global that has been
|
||||
/// mirrored in the GPU module as an external (no-body) declaration by the
|
||||
/// CUFDeviceGlobal pass under -gpu=mem:unified. Such globals must be
|
||||
/// registered with the CUDA driver via CUFRegisterExternalVariable so the
|
||||
/// registered with the CUDA driver via cuf.register_variable_static so the
|
||||
/// device-side `.extern` symbol resolves to the host pointer at module-load
|
||||
/// time and HMM/ATS handles migration.
|
||||
static bool isCudaUnifiedExternalGlobal(fir::GlobalOp hostGlobal,
|
||||
|
|
@ -173,8 +173,7 @@ static uint64_t getGlobalSizeInBytes(mlir::Location loc,
|
|||
/// Emit a call to a CUF registration runtime function with the canonical
|
||||
/// (module, addr, name, size) signature, where addr is the address of \p
|
||||
/// addrGlobal taken via fir.address_of and name/size describe \p nameGlobal.
|
||||
/// Used both for CUFRegisterVariable / CUFRegisterManagedVariable / and
|
||||
/// CUFRegisterExternalVariable.
|
||||
/// Used both for CUFRegisterVariable / CUFRegisterManagedVariable.
|
||||
static void
|
||||
emitCUFRegistrationCall(fir::FirOpBuilder &builder, mlir::Location loc,
|
||||
mlir::Type idxTy, const mlir::DataLayout &dl,
|
||||
|
|
@ -410,12 +409,13 @@ struct CUFAddConstructor
|
|||
for (fir::GlobalOp globalOp : mod.getOps<fir::GlobalOp>()) {
|
||||
if (!isCudaUnifiedExternalGlobal(globalOp, gpuSymTable))
|
||||
continue;
|
||||
auto func = fir::runtime::getRuntimeFunc<mkRTKey(
|
||||
CUFRegisterExternalVariable)>(loc, builder);
|
||||
emitCUFRegistrationCall(builder, loc, idxTy, *dl, kindMap,
|
||||
typeConverter, registeredMod, func,
|
||||
/*addrGlobal=*/globalOp,
|
||||
/*nameGlobal=*/globalOp);
|
||||
uint64_t szBytes = getGlobalSizeInBytes(loc, *dl, kindMap,
|
||||
typeConverter, globalOp);
|
||||
cuf::RegisterVariableStaticOp::create(
|
||||
builder, loc,
|
||||
mlir::SymbolRefAttr::get(ctx, globalOp.getSymName()),
|
||||
builder.getStringAttr(globalOp.getSymName()),
|
||||
builder.getI64IntegerAttr(szBytes));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ public:
|
|||
// External linkage (see convertLinkage in CodeGen.cpp), so an
|
||||
// initializer-less global emits as `.extern .global ...` in PTX.
|
||||
// The host-side definition stays. CUFAddConstructor will emit
|
||||
// CUFRegisterExternalVariable (= __cudaRegisterHostVar) so the CUDA
|
||||
// cuf.register_variable_static so the CUDA
|
||||
// runtime maps the device extern to the host pointer at module-load
|
||||
// time, and HMM/ATS handles migration.
|
||||
if (cudaUnified && !globalOp.getConstant() &&
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<
|
|||
// Under -gpu=mem:unified, a non-allocatable host module global referenced from
|
||||
// device code (mirrored as an external-linkage clone in the GPU module by the
|
||||
// CUFDeviceGlobal pass) must be registered with
|
||||
// _FortranACUFRegisterExternalVariable so the device-side `.extern` symbol
|
||||
// cuf.register_variable_static so the device-side `.extern` symbol
|
||||
// resolves to the host pointer at module-load time.
|
||||
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i1 = dense<8> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, f80 = dense<128> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, f128 = dense<128> : vector<2xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, "dlti.stack_alignment" = 128 : i64, "dlti.endianness" = "little">, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
|
||||
|
|
@ -229,14 +229,13 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i8 = dense<8> : vector<2xi64>, i
|
|||
|
||||
// UNIFIED: llvm.func internal @__cudaFortranConstructor()
|
||||
// UNIFIED: cuf.register_module @cuda_device_mod -> !llvm.ptr
|
||||
// UNIFIED: fir.address_of(@_QMmtestsEm) : !fir.ref<!fir.array<5xi32>>
|
||||
// UNIFIED: fir.call @_FortranACUFRegisterExternalVariable
|
||||
// UNIFIED: cuf.register_variable_static @_QMmtestsEm
|
||||
// UNIFIED-NOT: fir.call @_FortranACUFInitModule
|
||||
|
||||
// -----
|
||||
|
||||
// Under -gpu=mem:unified, an allocatable host module global also gets
|
||||
// registered via _FortranACUFRegisterExternalVariable; the registered symbol
|
||||
// registered via cuf.register_variable_static; the registered symbol
|
||||
// is the descriptor (fir.box<fir.heap<...>>). The host runtime allocates the
|
||||
// data buffer in HMM/ATS-accessible memory.
|
||||
|
||||
|
|
@ -257,12 +256,12 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i8 = dense<8> : vector<2xi64>, i
|
|||
|
||||
// UNIFIED: llvm.func internal @__cudaFortranConstructor()
|
||||
// UNIFIED: cuf.register_module @cuda_device_mod -> !llvm.ptr
|
||||
// UNIFIED: fir.address_of(@_QMmtestsEma) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
|
||||
// UNIFIED: fir.call @_FortranACUFRegisterExternalVariable
|
||||
// UNIFIED: cuf.register_variable_static @_QMmtestsEma
|
||||
// UNIFIED-NOT: fir.call @_FortranACUFInitModule
|
||||
|
||||
// -----
|
||||
|
||||
module attributes {dlti.dl_spec = #dlti.dl_spec<i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i1 = dense<8> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, f80 = dense<128> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, f128 = dense<128> : vector<2xi64>, !llvm.ptr<270> = dense<32> : vector<4xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, "dlti.stack_alignment" = 128 : i64, "dlti.endianness" = "little">, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu"} {
|
||||
func.func @_QPsub1() {
|
||||
%0 = cuf.alloc !fir.box<!fir.heap<!fir.array<?xf32>>> {bindc_name = "a", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub1Ea"} -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
|
||||
%4:2 = hlfir.declare %0 {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub1Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>)
|
||||
|
|
@ -274,6 +273,7 @@ func.func @_QPsub1() {
|
|||
cuf.free %4#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {data_attr = #cuf.cuda<device>}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: llvm.func internal @__cudaFortranConstructor()
|
||||
// CHECK: llvm.call @_FortranACUFRegisterAllocator()
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// 1. is mirrored into the GPU module by CUFDeviceGlobal as a no-body
|
||||
// external declaration (so PTX gets `.extern .global ...`); and
|
||||
// 2. is registered with the CUDA driver via
|
||||
// _FortranACUFRegisterExternalVariable (= __cudaRegisterHostVar) from
|
||||
// cuf.register_variable_static from
|
||||
// __cudaFortranConstructor, so the device-side symbol is mapped to
|
||||
// the host-resident storage at module-load time and HMM/ATS handles
|
||||
// migration.
|
||||
|
|
@ -44,6 +44,5 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<i8 = dense<8> : vector<2xi64>, i
|
|||
// Constructor registers the host pointer.
|
||||
// CHECK: llvm.func internal @__cudaFortranConstructor()
|
||||
// CHECK: cuf.register_module @cuda_device_mod -> !llvm.ptr
|
||||
// CHECK: fir.address_of(@_QMmtestsEm) : !fir.ref<!fir.array<5xi32>>
|
||||
// CHECK: fir.call @_FortranACUFRegisterExternalVariable
|
||||
// CHECK: cuf.register_variable_static @_QMmtestsEm
|
||||
// CHECK-NOT: fir.call @_FortranACUFInitModule
|
||||
|
|
|
|||
Loading…
Reference in a new issue