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

Reply via email to