Author: Orphic Dreamer Date: 2026-07-08T03:59:54Z New Revision: 5a924bf3962c7f0c84e2de46172cd1d01ae3a67d
URL: https://github.com/llvm/llvm-project/commit/5a924bf3962c7f0c84e2de46172cd1d01ae3a67d DIFF: https://github.com/llvm/llvm-project/commit/5a924bf3962c7f0c84e2de46172cd1d01ae3a67d.diff LOG: [CIR][CUDA] Support built-in CUDA surface type (#196079) Related: #179278 This patch adds initial support for CUDA built-in surface types in CIR for device-side compilation. CUDA surface references are lowered to the NVPTX device-handle representation (`i64`), matching existing Clang CodeGen behavior. Changes * Add `getCUDADeviceBuiltinSurfaceDeviceType()` target hook to `TargetCIRGenInfo` * Implement NVPTX surface lowering in `NVPTXTargetCIRGenInfo` * Handle CUDA built-in surface types in `CIRGenTypes::convertType` * Add CIR CUDA test coverage for device-side surface lowering Notes * This patch only implements device-side surface type lowering support * Texture types remain unsupported * TBAA handling for surface/texture types is left for follow-up work --------- Co-authored-by: mencotton <[email protected]> Co-authored-by: David Rivera <[email protected]> Co-authored-by: Andy Kaylor <[email protected]> Added: clang/lib/CIR/CodeGen/Targets/NVPTX.cpp clang/test/CIR/CodeGenCUDA/surface.cu Modified: clang/include/clang/CIR/MissingFeatures.h clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp clang/lib/CIR/CodeGen/CIRGenTypes.cpp clang/lib/CIR/CodeGen/CMakeLists.txt clang/lib/CIR/CodeGen/TargetInfo.cpp clang/lib/CIR/CodeGen/TargetInfo.h Removed: ################################################################################ diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 9a1546fe14e65..467313fc1e041 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -215,6 +215,7 @@ struct MissingFeatures { static bool ctorConstLvalueToRvalueConversion() { return false; } static bool ctorMemcpyizer() { return false; } static bool cudaSupport() { return false; } + static bool cudaTextureType() { return false; } static bool hipModuleCtor() { return false; } static bool dataLayoutTypeAllocSize() { return false; } static bool dataLayoutPtrHandlingBasedOnLangAS() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp index 65a3c2a7468e9..9aa6bffbd4db7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCUDANV.cpp @@ -100,6 +100,25 @@ class CIRGenNVCUDARuntime : public CIRGenCUDARuntime { cir::CUDADeviceVarKind::Variable, }); } + + void registerDeviceSurf(const VarDecl *vd, cir::GlobalOp &var, + bool isExtern) { + auto &builder = cgm.getBuilder(); + + var->setAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic(), + cir::CUDAVarRegistrationInfoAttr::get( + builder.getContext(), + getDeviceSideName(cast<NamedDecl>(vd)), + cir::CUDADeviceVarKind::Surface, isExtern, + /*isConstant=*/false, + /*isManaged=*/false)); + + deviceVars.push_back({ + var, + vd, + cir::CUDADeviceVarKind::Surface, + }); + } }; } // namespace @@ -458,12 +477,15 @@ void CIRGenNVCUDARuntime::handleVarRegistration(const VarDecl *vd, registerDeviceVar(vd, var, !vd->hasDefinition(), vd->hasAttr<CUDAConstantAttr>()); } - } else if (vd->getType()->isCUDADeviceBuiltinSurfaceType() || - vd->getType()->isCUDADeviceBuiltinTextureType()) { - // Builtin surfaces and textures and their template arguments are - // also registered with CUDA runtime. + } else if (vd->getType()->isCUDADeviceBuiltinSurfaceType()) { + // Builtin surfaces and their template arguments are also registered + // with CUDA runtime. + if (!vd->hasExternalStorage()) + registerDeviceSurf(vd, var, !vd->hasDefinition()); + + } else if (vd->getType()->isCUDADeviceBuiltinTextureType()) { cgm.errorNYI(vd->getSourceRange(), - "handleVarRegistration: Surface and Texture registration"); + "handleVarRegistration: Texture registration"); } } diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp index 298c44d849782..9ff4626bc3c25 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp @@ -10,6 +10,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/MissingFeatures.h" #include <cassert> @@ -304,6 +305,16 @@ mlir::Type CIRGenTypes::convertType(QualType type) { type = astContext.getCanonicalType(type); const Type *ty = type.getTypePtr(); + if (astContext.getLangOpts().CUDAIsDevice) { + if (type->isCUDADeviceBuiltinSurfaceType()) { + if (mlir::Type ty = + cgm.getTargetCIRGenInfo().getCUDADeviceBuiltinSurfaceDeviceType()) + return ty; + } else if (type->isCUDADeviceBuiltinTextureType()) { + assert(!cir::MissingFeatures::cudaTextureType()); + } + } + // Process record types before the type cache lookup. if (const auto *recordType = dyn_cast<RecordType>(type)) return convertRecordDeclType(recordType->getDecl()->getDefinitionOrSelf()); diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt index 79d0a49570b3e..8e4fd906b6eca 100644 --- a/clang/lib/CIR/CodeGen/CMakeLists.txt +++ b/clang/lib/CIR/CodeGen/CMakeLists.txt @@ -55,6 +55,7 @@ add_clang_library(clangCIR CIRGenVTables.cpp TargetInfo.cpp Targets/AMDGPU.cpp + Targets/NVPTX.cpp Targets/SPIRV.cpp DEPENDS diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 71ccb6e24a8aa..ba7eeb29dd252 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -122,70 +122,11 @@ class X8664TargetCIRGenInfo : public TargetCIRGenInfo { }; } // namespace -namespace { - -class NVPTXABIInfo : public ABIInfo { -public: - NVPTXABIInfo(CIRGenTypes &cgt) : ABIInfo(cgt) {} -}; - -class NVPTXTargetCIRGenInfo : public TargetCIRGenInfo { -public: - NVPTXTargetCIRGenInfo(CIRGenTypes &cgt) - : TargetCIRGenInfo(std::make_unique<NVPTXABIInfo>(cgt)) {} - - void setTargetAttributes(const clang::Decl *decl, mlir::Operation *global, - CIRGenModule &cgm) const override { - auto globalValue = mlir::dyn_cast<cir::CIRGlobalValueInterface>(global); - if (globalValue && globalValue.isDeclaration()) - return; - - const auto *vd = dyn_cast_or_null<VarDecl>(decl); - if (vd) { - if (cgm.getLangOpts().CUDA) { - if (vd->getType()->isCUDADeviceBuiltinSurfaceType() || - vd->getType()->isCUDADeviceBuiltinTextureType()) - assert(!cir::MissingFeatures::emitNVVMMetadata()); - return; - } - } - - const auto *fd = dyn_cast_or_null<FunctionDecl>(decl); - if (!fd) - return; - - auto func = mlir::cast<cir::FuncOp>(global); - - // Perform special handling in OpenCL/CUDA mode. - if (cgm.getLangOpts().OpenCL || cgm.getLangOpts().CUDA) { - // Use function attributes to check for kernel functions. By default, all - // functions are device functions. - if (fd->hasAttr<DeviceKernelAttr>() || fd->hasAttr<CUDAGlobalAttr>()) { - // OpenCL/CUDA kernel functions get kernel metadata. Kernel functions - // are also not subject to inlining. - func.setInlineKind(cir::InlineKind::NoInline); - if (fd->hasAttr<CUDAGlobalAttr>()) { - func.setCallingConv(cir::CallingConv::PTXKernel); - assert(!cir::MissingFeatures::opFuncParameterAttributes()); - } - if (fd->hasAttr<CUDALaunchBoundsAttr>()) - assert(!cir::MissingFeatures::handleCUDALaunchBoundsAttr()); - } - } - } -}; -} // namespace - std::unique_ptr<TargetCIRGenInfo> clang::CIRGen::createAMDGPUTargetCIRGenInfo(CIRGenTypes &cgt) { return std::make_unique<AMDGPUTargetCIRGenInfo>(cgt); } -std::unique_ptr<TargetCIRGenInfo> -clang::CIRGen::createNVPTXTargetCIRGenInfo(CIRGenTypes &cgt) { - return std::make_unique<NVPTXTargetCIRGenInfo>(cgt); -} - std::unique_ptr<TargetCIRGenInfo> clang::CIRGen::createX8664TargetCIRGenInfo(CIRGenTypes &cgt) { return std::make_unique<X8664TargetCIRGenInfo>(cgt); diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index 5c5659056d696..308d472234f99 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -66,6 +66,10 @@ class TargetCIRGenInfo { cir::LangAddressSpace::Default); } + virtual mlir::Type getCUDADeviceBuiltinSurfaceDeviceType() const { + return nullptr; + } + /// Determine whether a call to an unprototyped functions under /// the given calling convention should use the variadic /// convention or the non-variadic convention. diff --git a/clang/lib/CIR/CodeGen/Targets/NVPTX.cpp b/clang/lib/CIR/CodeGen/Targets/NVPTX.cpp new file mode 100644 index 0000000000000..83904d1f16855 --- /dev/null +++ b/clang/lib/CIR/CodeGen/Targets/NVPTX.cpp @@ -0,0 +1,87 @@ +//===---- NVPTX.cpp - NVPTX-specific CIR CodeGen --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This provides NVPTX-specific CIR CodeGen logic. +// +//===----------------------------------------------------------------------===// + +#include "../ABIInfo.h" +#include "../CIRGenModule.h" +#include "../TargetInfo.h" + +#include "clang/CIR/Dialect/IR/CIRTypes.h" + +using namespace clang; +using namespace clang::CIRGen; + +namespace { + +class NVPTXABIInfo : public ABIInfo { +public: + NVPTXABIInfo(CIRGenTypes &cgt) : ABIInfo(cgt) {} +}; + +class NVPTXTargetCIRGenInfo : public TargetCIRGenInfo { +public: + NVPTXTargetCIRGenInfo(CIRGenTypes &cgt) + : TargetCIRGenInfo(std::make_unique<NVPTXABIInfo>(cgt)) {} + + void setTargetAttributes(const clang::Decl *decl, mlir::Operation *global, + CIRGenModule &cgm) const override { + auto globalValue = mlir::dyn_cast<cir::CIRGlobalValueInterface>(global); + if (globalValue && globalValue.isDeclaration()) + return; + + const auto *vd = dyn_cast_or_null<VarDecl>(decl); + if (vd) { + if (cgm.getLangOpts().CUDA) { + if (vd->getType()->isCUDADeviceBuiltinSurfaceType() || + vd->getType()->isCUDADeviceBuiltinTextureType()) + assert(!cir::MissingFeatures::emitNVVMMetadata()); + return; + } + } + + const auto *fd = dyn_cast_or_null<FunctionDecl>(decl); + if (!fd) + return; + + auto func = mlir::cast<cir::FuncOp>(global); + + // Perform special handling in OpenCL/CUDA mode. + if (cgm.getLangOpts().OpenCL || cgm.getLangOpts().CUDA) { + // Use function attributes to check for kernel functions. By default, all + // functions are device functions. + if (fd->hasAttr<DeviceKernelAttr>() || fd->hasAttr<CUDAGlobalAttr>()) { + // OpenCL/CUDA kernel functions get kernel metadata. Kernel functions + // are also not subject to inlining. + func.setInlineKind(cir::InlineKind::NoInline); + if (fd->hasAttr<CUDAGlobalAttr>()) { + func.setCallingConv(cir::CallingConv::PTXKernel); + assert(!cir::MissingFeatures::opFuncParameterAttributes()); + } + if (fd->hasAttr<CUDALaunchBoundsAttr>()) + assert(!cir::MissingFeatures::handleCUDALaunchBoundsAttr()); + } + } + } + + mlir::Type getCUDADeviceBuiltinSurfaceDeviceType() const override { + // On the device side, surface reference is represented as an object handle + // in 64-bit integer. + return cir::IntType::get(&getABIInfo().cgt.getMLIRContext(), 64, + /*isSigned=*/true); + } +}; + +} // namespace + +std::unique_ptr<TargetCIRGenInfo> +clang::CIRGen::createNVPTXTargetCIRGenInfo(CIRGenTypes &cgt) { + return std::make_unique<NVPTXTargetCIRGenInfo>(cgt); +} diff --git a/clang/test/CIR/CodeGenCUDA/surface.cu b/clang/test/CIR/CodeGenCUDA/surface.cu new file mode 100644 index 0000000000000..6ec9b53ad6473 --- /dev/null +++ b/clang/test/CIR/CodeGenCUDA/surface.cu @@ -0,0 +1,25 @@ +// 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 + +struct surfaceReference { + int desc; +}; + +template <typename T, int dim = 1> +struct __attribute__((device_builtin_surface_type)) surface + : public surfaceReference {}; + +template <int dim> +struct __attribute__((device_builtin_surface_type)) surface<void, dim> + : public surfaceReference {}; + +surface<void, 2> surf; + +// CIR-DEVICE: cir.global external target_address_space(1) @surf = #cir.undef : !s64i + +// 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
