https://github.com/Siya-05 updated https://github.com/llvm/llvm-project/pull/225146
>From 83e8ec141a3e5e2fda507d73ad33fce1b5fed023 Mon Sep 17 00:00:00 2001 From: Sivapriya <[email protected]> Date: Mon, 21 Sep 2026 17:06:17 +0000 Subject: [PATCH 1/2] [CIR][CUDA] Add host-side surface registration support --- .../clang/CIR/Dialect/IR/CIRCUDAAttrs.td | 3 +- clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp | 34 +++++++---- clang/lib/CIR/Dialect/IR/CIRAttrs.cpp | 10 +++- .../Dialect/Transforms/LoweringPrepare.cpp | 58 +++++++++++++------ clang/test/CIR/CodeGenCUDA/surface.cu | 49 ++++++++++++++++ 5 files changed, 121 insertions(+), 33 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td index d993e1b2b11ebb..c6f8afd8d4b306 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td @@ -89,7 +89,8 @@ def CIR_CUDAVarRegistrationInfoAttr : CIR_Attr<"CUDAVarRegistrationInfo", "cu.va // handleVarRegistration via hasAttr<HIPManagedAttr>(). "bool":$isExtern, "bool":$isConstant, - "bool":$isManaged + "bool":$isManaged, + "int32_t":$surfaceType ); let hasCustomAssemblyFormat = 1; diff --git a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp index ab4baf336d379a..ac81ac3261a541 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp @@ -93,7 +93,8 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { builder.getContext(), getDeviceSideName(cast<NamedDecl>(vd)), cir::CUDADeviceVarKind::Variable, isExtern, isConstant, - vd->hasAttr<HIPManagedAttr>())); + vd->hasAttr<HIPManagedAttr>(), + /*surfaceType=*/0)); deviceVars.push_back({ var, vd, @@ -101,8 +102,8 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { }); } - void registerDeviceSurf(const VarDecl *vd, cir::GlobalOp &var, - bool isExtern) { + void registerDeviceSurf(const VarDecl *vd, cir::GlobalOp &var, bool isExtern, + int32_t surfaceType) { auto &builder = cgm.getBuilder(); var->setAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic(), @@ -111,7 +112,7 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { getDeviceSideName(cast<NamedDecl>(vd)), cir::CUDADeviceVarKind::Surface, isExtern, /*isConstant=*/false, - /*isManaged=*/false)); + /*isManaged=*/false, surfaceType)); deviceVars.push_back({ var, @@ -129,7 +130,8 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { getDeviceSideName(cast<NamedDecl>(vd)), cir::CUDADeviceVarKind::Texture, isExtern, /*isConstant=*/false, - /*isManaged=*/false)); + /*isManaged=*/false, + /*surfaceType=*/0)); deviceVars.push_back({ var, @@ -430,14 +432,11 @@ void CIRGenNVCUDARuntime::internalizeDeviceSideVar( // counterparts. It's not clear yet whether it's nvcc's bug or // a feature, but we've got to do the same for compatibility. if (d->hasAttr<CUDADeviceAttr>() || d->hasAttr<CUDAConstantAttr>() || - d->hasAttr<CUDASharedAttr>()) { + d->hasAttr<CUDASharedAttr>() || + d->getType()->isCUDADeviceBuiltinSurfaceType() || + d->getType()->isCUDADeviceBuiltinTextureType()) { linkage = cir::GlobalLinkageKind::InternalLinkage; } - - if (d->getType()->isCUDADeviceBuiltinSurfaceType() || - d->getType()->isCUDADeviceBuiltinTextureType()) - cgm.errorNYI(d->getSourceRange(), - "internalizeDeviceSideVar: CUDA Surface/Texture support"); } std::string CIRGenNVCUDARuntime::getDeviceSideName(const NamedDecl *nd) { @@ -498,8 +497,19 @@ void CIRGenNVCUDARuntime::handleVarRegistration(const VarDecl *vd, } else if (vd->getType()->isCUDADeviceBuiltinSurfaceType()) { // Builtin surfaces and their template arguments are also registered // with CUDA runtime. + const auto *td = cast<ClassTemplateSpecializationDecl>( + vd->getType()->castAsCXXRecordDecl()); + const TemplateArgumentList &args = td->getTemplateArgs(); + + assert(args.size() == 2 && + "Unexpected number of template arguments of CUDA device " + "builtin surface type."); + + auto surfaceType = args[1].getAsIntegral(); + if (!vd->hasExternalStorage()) - registerDeviceSurf(vd, var, !vd->hasDefinition()); + registerDeviceSurf(vd, var, !vd->hasDefinition(), + surfaceType.getSExtValue()); } else if (vd->getType()->isCUDADeviceBuiltinTextureType()) { // Builtin textures and their template arguments are also registered diff --git a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp index 05408c8b2f2e99..049797e7ab5c9f 100644 --- a/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRAttrs.cpp @@ -519,6 +519,8 @@ void CUDAVarRegistrationInfoAttr::print(AsmPrinter &p) const { p << ", constant"; if (getIsManaged()) p << ", managed"; + if (getKind() == CUDADeviceVarKind::Surface) + p << ", surface_type = " << getSurfaceType(); p << ">"; } @@ -553,6 +555,7 @@ Attribute CUDAVarRegistrationInfoAttr::parse(AsmParser &parser, Type odsType) { bool isExtern = false; bool isConstant = false; bool isManaged = false; + int32_t surfaceType = 0; while (parser.parseOptionalGreater().failed()) { if (parser.parseComma()) @@ -568,14 +571,17 @@ Attribute CUDAVarRegistrationInfoAttr::parse(AsmParser &parser, Type odsType) { isConstant = true; else if (flag == "managed") isManaged = true; - else { + else if (flag == "surface_type") { + if (parser.parseEqual() || parser.parseInteger(surfaceType)) + return {}; + } else { parser.emitError(parser.getCurrentLocation(), "unknown flag: ") << flag; return {}; } } return get(parser.getContext(), deviceSideName, *kind, isExtern, isConstant, - isManaged); + isManaged, surfaceType); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index a155bd4661ce3a..b6c22ed0b2f14e 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -2992,6 +2992,16 @@ void LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder, FuncType::get({voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy, sizeTy, intTy, intTy}, voidTy)); + // void __cudaRegisterSurface(void **fatbinHandle, + // const struct surfaceReference *hostVar, + // const void **deviceAddress, + // const char *deviceName, + // int type, int ext); + FuncOp cudaRegisterSurface = buildRuntimeFunction( + globalBuilder, addUnderscoredPrefix(cudaPrefix, "RegisterSurface"), loc, + FuncType::get( + {voidPtrPtrTy, voidPtrTy, voidPtrTy, voidPtrTy, intTy, intTy}, + voidTy)); auto makeConstantString = [&](llvm::StringRef str) -> GlobalOp { auto strType = ArrayType::get(&getContext(), charTy, 1 + str.size()); @@ -3008,15 +3018,6 @@ void LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder, mlir::Value fatbinHandle = *regGlobalFunc.args_begin(); for (auto &[global, regAttr] : cudaDeviceVars) { - switch (regAttr.getKind()) { - case cir::CUDADeviceVarKind::Variable: - break; - case cir::CUDADeviceVarKind::Surface: - llvm_unreachable("Surface registration NYI"); - case cir::CUDADeviceVarKind::Texture: - llvm_unreachable("Texture registration NYI"); - } - if (regAttr.getIsManaged()) llvm_unreachable("Managed variable registration NYI"); @@ -3028,15 +3029,36 @@ void LoweringPreparePass::buildCUDARegisterVars(cir::CIRBaseBuilderTy &builder, auto isExtern = ConstantOp::create( builder, loc, IntAttr::get(intTy, regAttr.getIsExtern() ? 1 : 0)); - llvm::TypeSize size = dataLayout.getTypeAllocSize(global.getSymType()); - auto varSize = ConstantOp::create( - builder, loc, IntAttr::get(sizeTy, size.getFixedValue())); - auto isConstant = ConstantOp::create( - builder, loc, IntAttr::get(intTy, regAttr.getIsConstant() ? 1 : 0)); - auto normalized = ConstantOp::create(builder, loc, IntAttr::get(intTy, 0)); - builder.createCallOp(loc, cudaRegisterVar, - {fatbinHandle, hostVar, deviceName, deviceName, - isExtern, varSize, isConstant, normalized}); + + switch (regAttr.getKind()) { + case cir::CUDADeviceVarKind::Variable: { + llvm::TypeSize size = dataLayout.getTypeAllocSize(global.getSymType()); + auto varSize = ConstantOp::create( + builder, loc, IntAttr::get(sizeTy, size.getFixedValue())); + auto isConstant = ConstantOp::create( + builder, loc, IntAttr::get(intTy, regAttr.getIsConstant() ? 1 : 0)); + auto normalized = + ConstantOp::create(builder, loc, IntAttr::get(intTy, 0)); + + builder.createCallOp(loc, cudaRegisterVar, + {fatbinHandle, hostVar, deviceName, deviceName, + isExtern, varSize, isConstant, normalized}); + break; + } + + case cir::CUDADeviceVarKind::Surface: { + auto surfaceType = ConstantOp::create( + builder, loc, IntAttr::get(intTy, regAttr.getSurfaceType())); + + builder.createCallOp(loc, cudaRegisterSurface, + {fatbinHandle, hostVar, deviceName, deviceName, + surfaceType, isExtern}); + break; + } + + case cir::CUDADeviceVarKind::Texture: + llvm_unreachable("Texture registration NYI"); + } } } diff --git a/clang/test/CIR/CodeGenCUDA/surface.cu b/clang/test/CIR/CodeGenCUDA/surface.cu index 67d7257c07c6e5..619b34ffde48dc 100644 --- a/clang/test/CIR/CodeGenCUDA/surface.cu +++ b/clang/test/CIR/CodeGenCUDA/surface.cu @@ -1,9 +1,21 @@ // REQUIRES: x86-registered-target // REQUIRES: nvptx-registered-target + // RUN: %clang_cc1 -fclangir -std=c++11 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-cir -o - %s | FileCheck --check-prefix=CIR-DEVICE %s // RUN: %clang_cc1 -fclangir -std=c++11 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - %s | FileCheck --check-prefix=LLVM-DEVICE %s // RUN: %clang_cc1 -std=c++11 -fcuda-is-device -triple nvptx64-nvidia-cuda -emit-llvm -o - %s | FileCheck --check-prefix=OGCG-DEVICE %s +// RUN: echo -n "GPU binary would be here." > %t +// RUN: %clang_cc1 -fclangir -std=c++11 -triple x86_64-unknown-linux-gnu \ +// RUN: -target-sdk-version=12.3 -fcuda-include-gpubinary %t \ +// RUN: -emit-cir -o - %s | FileCheck --check-prefix=CIR-HOST %s +// RUN: %clang_cc1 -fclangir -std=c++11 -triple x86_64-unknown-linux-gnu \ +// RUN: -target-sdk-version=12.3 -fcuda-include-gpubinary %t \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=LLVM-HOST %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu \ +// RUN: -target-sdk-version=12.3 -fcuda-include-gpubinary %t \ +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=OGCG-HOST %s + struct surfaceReference { int desc; }; @@ -18,8 +30,45 @@ struct __attribute__((device_builtin_surface_type)) surface<void, dim> surface<void, 2> surf; +//===----------------------------------------------------------------------===// +// Device-side checks +//===----------------------------------------------------------------------===// + // CIR-DEVICE: cir.global external target_address_space(1) @surf = #cir.undef : !cir.cuda_surface // CIR now matches OG CodeGen and emits undef for CUDA shadow variables. // LLVM-DEVICE: @surf ={{.*}} addrspace(1) externally_initialized global i64 undef // OGCG-DEVICE: @surf ={{.*}} addrspace(1) externally_initialized global i64 undef + +//===----------------------------------------------------------------------===// +// Host-side checks +//===----------------------------------------------------------------------===// + +// Check the CUDA surface registration runtime declaration. +// CIR-HOST: cir.func private @__cudaRegisterSurface(!cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>, !cir.ptr<!void>, !cir.ptr<!void>, !s32i, !s32i) + +// Check that __cuda_register_globals registers the surface using the host +// shadow, device-side name, surface type, and extern flag. +// CIR-HOST-LABEL: cir.func internal private @__cuda_register_globals +// CIR-HOST-SAME: (%[[FATBIN:.*]]: !cir.ptr<!cir.ptr<!void>> +// CIR-HOST: %[[NAME_RAW:.*]] = cir.get_global @".strsurf" +// CIR-HOST-NEXT: %[[NAME:.*]] = cir.cast bitcast %[[NAME_RAW]] +// CIR-HOST-NEXT: %[[HOST_RAW:.*]] = cir.get_global @surf +// CIR-HOST-NEXT: %[[HOST:.*]] = cir.cast bitcast %[[HOST_RAW]] +// CIR-HOST-NEXT: %[[EXTERN:.*]] = cir.const #cir.int<0> : !s32i +// CIR-HOST-NEXT: %[[SURFACE_TYPE:.*]] = cir.const #cir.int<2> : !s32i +// CIR-HOST-NEXT: cir.call @__cudaRegisterSurface(%[[FATBIN]], %[[HOST]], %[[NAME]], %[[NAME]], %[[SURFACE_TYPE]], %[[EXTERN]]) + +// Check that the host-side shadow carries the surface registration metadata, +// including the surface type extracted from surface<void, 2>. +// CIR-HOST: cir.global{{.*}} @surf = {{.*}}cu.var_registration = #cir.cu.var_registration<surf, Surface, surface_type = 2> + +// Check CIR-lowered LLVM registration. +// LLVM-HOST-LABEL: define internal void @__cuda_register_globals +// LLVM-HOST-SAME: (ptr %[[FATBIN:.*]]) +// LLVM-HOST: call void @__cudaRegisterSurface(ptr %[[FATBIN]], ptr @surf, ptr @[[NAME:.*]], ptr @[[NAME]], i32 2, i32 0) + +// Check parity with original CodeGen. +// OGCG-HOST-LABEL: define internal void @__cuda_register_globals +// OGCG-HOST-SAME: (ptr %[[FATBIN:.*]]) +// OGCG-HOST: call void @__cudaRegisterSurface(ptr %[[FATBIN]], ptr @surf, ptr @[[NAME:.*]], ptr @[[NAME]], i32 2, i32 0) >From 2cae85ca4e93450a5f4bd30c22b8a150780481de Mon Sep 17 00:00:00 2001 From: Sivapriya <[email protected]> Date: Wed, 23 Sep 2026 11:46:53 +0000 Subject: [PATCH 2/2] [CIR][CUDA] Address review comments --- clang/test/CIR/CodeGenCUDA/surface.cu | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/clang/test/CIR/CodeGenCUDA/surface.cu b/clang/test/CIR/CodeGenCUDA/surface.cu index 619b34ffde48dc..413e19cabbd80c 100644 --- a/clang/test/CIR/CodeGenCUDA/surface.cu +++ b/clang/test/CIR/CodeGenCUDA/surface.cu @@ -14,15 +14,19 @@ // RUN: -emit-llvm -o - %s | FileCheck --check-prefix=LLVM-HOST %s // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux-gnu \ // RUN: -target-sdk-version=12.3 -fcuda-include-gpubinary %t \ -// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=OGCG-HOST %s +// RUN: -emit-llvm -o - %s | FileCheck --check-prefix=LLVM-HOST %s struct surfaceReference { int desc; }; -template <typename T, int dim = 1> -struct __attribute__((device_builtin_surface_type)) surface - : public surfaceReference {}; +template <class T, int dim = 1> +struct __attribute__((device_builtin_surface_type)) surface; + +template <class T, int dim> +struct __attribute__((device_builtin_surface_type)) surface { + typedef surfaceReference type; +}; template <int dim> struct __attribute__((device_builtin_surface_type)) surface<void, dim> @@ -63,12 +67,7 @@ surface<void, 2> surf; // including the surface type extracted from surface<void, 2>. // CIR-HOST: cir.global{{.*}} @surf = {{.*}}cu.var_registration = #cir.cu.var_registration<surf, Surface, surface_type = 2> -// Check CIR-lowered LLVM registration. +// Check both CIR-lowered LLVM and original CodeGen registration. // LLVM-HOST-LABEL: define internal void @__cuda_register_globals // LLVM-HOST-SAME: (ptr %[[FATBIN:.*]]) -// LLVM-HOST: call void @__cudaRegisterSurface(ptr %[[FATBIN]], ptr @surf, ptr @[[NAME:.*]], ptr @[[NAME]], i32 2, i32 0) - -// Check parity with original CodeGen. -// OGCG-HOST-LABEL: define internal void @__cuda_register_globals -// OGCG-HOST-SAME: (ptr %[[FATBIN:.*]]) -// OGCG-HOST: call void @__cudaRegisterSurface(ptr %[[FATBIN]], ptr @surf, ptr @[[NAME:.*]], ptr @[[NAME]], i32 2, i32 0) +// LLVM-HOST: call void @__cudaRegisterSurface(ptr %[[FATBIN]], ptr @surf, ptr @[[NAME:.*]], ptr @[[NAME]], i32 2, i32 0) \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
