[llvm-branch-commits] [clang] [HLSL] Implicit resource binding for cbuffers (PR #139022)
Helena Kotas via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon May 12 11:49:51 PDT 2025
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/139022
>From 8194951b52e024b78c7f148d65ce6c23b3fcf424 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 7 May 2025 21:05:39 -0700
Subject: [PATCH 1/6] [HLSL] Implicit binding for cbuffers
Constant buffers defined using the `cbuffer` keyword do not have a constructor. Instead, the call to initialize the `cbuffer` resource handle based on its binding is generated in codegen. This change adds initialization of `cbuffers` that have implicit binding.
---
clang/include/clang/Basic/Attr.td | 11 ++++
clang/lib/CodeGen/CGHLSLRuntime.cpp | 48 ++++++++-------
clang/lib/Sema/SemaHLSL.cpp | 21 ++++++-
.../AST/HLSL/ast-dump-comment-cbuffer.hlsl | 1 +
clang/test/AST/HLSL/packoffset.hlsl | 1 +
clang/test/AST/HLSL/pch_hlsl_buffer.hlsl | 2 +
.../GlobalConstructorFunction.hlsl | 4 ++
clang/test/CodeGenHLSL/cbuffer.hlsl | 58 ++++++++++++++++++-
8 files changed, 122 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index df7bba094fce6..d655acc2a1b8c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -4778,6 +4778,7 @@ def HLSLResourceBinding: InheritableAttr {
RegisterType RegType;
std::optional<unsigned> SlotNumber;
unsigned SpaceNumber;
+ std::optional<unsigned> ImplicitBindingOrderID;
public:
void setBinding(RegisterType RT, std::optional<unsigned> SlotNum, unsigned SpaceNum) {
@@ -4799,6 +4800,16 @@ def HLSLResourceBinding: InheritableAttr {
unsigned getSpaceNumber() const {
return SpaceNumber;
}
+ void setImplicitBindingOrderID(uint32_t Value) {
+ ImplicitBindingOrderID = Value;
+ }
+ bool hasImplicitBindingOrderID() const {
+ return ImplicitBindingOrderID.has_value();
+ }
+ uint32_t getImplicitBindingOrderID() const {
+ assert(hasImplicitBindingOrderID() && "attribute does not have implicit binding order id");
+ return ImplicitBindingOrderID.value();
+ }
}];
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f6608faaa7309..327b43383d8d4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
@@ -42,8 +43,8 @@ using namespace llvm;
using llvm::hlsl::CBufferRowSizeInBytes;
static void initializeBufferFromBinding(CodeGenModule &CGM,
- llvm::GlobalVariable *GV, unsigned Slot,
- unsigned Space);
+ llvm::GlobalVariable *GV,
+ HLSLResourceBindingAttr *RBA);
namespace {
@@ -257,13 +258,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
// Initialize cbuffer from binding (implicit or explicit)
- const HLSLResourceBindingAttr *RBA =
- BufDecl->getAttr<HLSLResourceBindingAttr>();
- // FIXME: handle implicit binding if no binding attribute is found
- // (llvm/llvm-project#110722)
- if (RBA && !RBA->isImplicit())
- initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(),
- RBA->getSpaceNumber());
+ HLSLResourceBindingAttr *RBA = BufDecl->getAttr<HLSLResourceBindingAttr>();
+ assert(RBA &&
+ "cbuffer/tbuffer should always have resource binding attribute");
+ initializeBufferFromBinding(CGM, BufGV, RBA);
}
llvm::TargetExtType *
@@ -539,19 +537,27 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
}
static void initializeBufferFromBinding(CodeGenModule &CGM,
- llvm::GlobalVariable *GV, unsigned Slot,
- unsigned Space) {
+ llvm::GlobalVariable *GV,
+ HLSLResourceBindingAttr *RBA) {
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext());
- llvm::Value *Args[] = {
- llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
- llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
- llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
- llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
- llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
- };
- initializeBuffer(CGM, GV,
- CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
- Args);
+ auto *False = llvm::ConstantInt::get(Int1Ty, false);
+ auto *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
+ auto *One = llvm::ConstantInt::get(CGM.IntTy, 1);
+ auto *Space =
+ llvm::ConstantInt::get(CGM.IntTy, RBA ? RBA->getSpaceNumber() : 0);
+
+ if (!RBA->isImplicit()) {
+ auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
+ Intrinsic::ID Intr =
+ CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
+ initializeBuffer(CGM, GV, Intr, {Space, RegSlot, One, Zero, False});
+ } else {
+ auto *OrderID =
+ llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
+ Intrinsic::ID Intr =
+ CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
+ initializeBuffer(CGM, GV, Intr, {OrderID, Space, One, Zero, False});
+ }
}
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c0669a8d60470..1bee554eec219 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -536,6 +536,18 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
BufDecl->addLayoutStruct(LS);
}
+void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
+ uint32_t ImplicitBindingOrderID) {
+ RegisterType RT =
+ BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
+ auto *Attr =
+ HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
+ std::optional<unsigned> RegSlot;
+ Attr->setBinding(RT, RegSlot, 0);
+ Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
+ BufDecl->addAttr(Attr);
+}
+
// Handle end of cbuffer/tbuffer declaration
void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
@@ -547,8 +559,13 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
createHostLayoutStructForBuffer(SemaRef, BufDecl);
if (std::none_of(Dcl->attr_begin(), Dcl->attr_end(),
- [](Attr *A) { return isa<HLSLResourceBindingAttr>(A); }))
+ [](Attr *A) { return isa<HLSLResourceBindingAttr>(A); })) {
SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
+ // add implicit HLSLResourceBindingAttr for the buffer
+ // (used mostly as a way to tranfer ImplicitBindingOrderID to codegen)
+ addImplicitBindingAttrToBuffer(SemaRef, BufDecl,
+ getNextImplicitBindingOrderID());
+ }
SemaRef.PopDeclContext();
}
@@ -1972,6 +1989,8 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
DefaultCBufferDecls);
+ addImplicitBindingAttrToBuffer(SemaRef, DefaultCBuffer,
+ getNextImplicitBindingOrderID());
SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer);
diff --git a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
index 4cca9cc742c07..0cc72fd370633 100644
--- a/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
+++ b/clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
@@ -21,6 +21,7 @@ cbuffer A {
// AST: HLSLBufferDecl {{.*}} line:11:9 cbuffer A
// AST-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// AST-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
// AST-NEXT: FullComment
// AST-NEXT: ParagraphComment
// AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."
diff --git a/clang/test/AST/HLSL/packoffset.hlsl b/clang/test/AST/HLSL/packoffset.hlsl
index 4fe8aed5cb31a..dc86000a87ee3 100644
--- a/clang/test/AST/HLSL/packoffset.hlsl
+++ b/clang/test/AST/HLSL/packoffset.hlsl
@@ -5,6 +5,7 @@
cbuffer A
{
// CHECK-NEXT:-HLSLResourceClassAttr {{.*}} Implicit CBuffer
+ // CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
// CHECK-NEXT: VarDecl {{.*}} A1 'hlsl_constant float4'
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
float4 A1 : packoffset(c);
diff --git a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
index 9c73f587b7210..7fb06f8d3524a 100644
--- a/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
+++ b/clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
@@ -16,12 +16,14 @@ float foo() {
// Make sure cbuffer/tbuffer works for PCH.
// CHECK: HLSLBufferDecl {{.*}} line:{{[0-9]+}}:9 imported <undeserialized declarations> cbuffer A
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
+// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
// CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'hlsl_constant float'
// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> struct __cblayout_A definition
// CHECK: FieldDecl {{.*}} imported a 'float'
// CHECK: HLSLBufferDecl {{.*}} line:{{[0-9]+}}:9 imported <undeserialized declarations> tbuffer B
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
+// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
// CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'hlsl_constant float'
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> struct __cblayout_B definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'
diff --git a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
index c0eb1b138ed04..b36682e065b3a 100644
--- a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
+++ b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
@@ -27,6 +27,7 @@ void main(unsigned GI : SV_GroupIndex) {}
// Verify function constructors are emitted
// NOINLINE-NEXT: call void @_Z13call_me_firstv()
// NOINLINE-NEXT: call void @_Z12then_call_mev()
+// NOINLINE-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorFunction.hlsl()
// NOINLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
// NOINLINE-NEXT: call void @_Z4mainj(i32 %0)
// NOINLINE-NEXT: call void @_Z12call_me_lastv(
@@ -36,6 +37,9 @@ void main(unsigned GI : SV_GroupIndex) {}
// INLINE-NEXT: alloca
// INLINE-NEXT: store i32 12
// INLINE-NEXT: store i32 13
+// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0))
+// INLINE-NEXT-SAME: @"llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_$Globalss_4_0tt"(i32 0, i32 0, i32 1, i32 0, i1 false)
+// INLINE-NEXT: store target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0)) %[[HANDLE]], ptr @"$Globals.cb", align 4
// INLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
// INLINE-NEXT: store i32 %
// INLINE-NEXT: store i32 0
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 405f5ef218973..63da457dc4531 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -268,16 +268,64 @@ cbuffer CB_C {
// CHECK: define internal void @_init_buffer_CBScalars.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
+// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBScalarss_56_0_8_16_24_32_36_40_48tt(i32 5, i32 1, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48)) %CBScalars.cb_h, ptr @CBScalars.cb, align 4
+// CHECK: define internal void @_init_buffer_CBVectors.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBVectorss_136_0_16_40_48_80_96_112tt(i32 0, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112)) %CBVectors.cb_h, ptr @CBVectors.cb, align 4
+
// CHECK: define internal void @_init_buffer_CBArrays.cb()
// CHECK-NEXT: entry:
-// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
+// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
// CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBArrayss_708_0_48_112_176_224_608_624_656tt(i32 0, i32 2, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656)) %CBArrays.cb_h, ptr @CBArrays.cb, align 4
+// CHECK: define internal void @_init_buffer_CBTypedefArray.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBTypedefArrays_128_0_64tt(i32 1, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CBStructs.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBStructss_246_0_16_32_64_144_238_240tt(i32 2, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240)) %CBStructs.cb_h, ptr @CBStructs.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CBClasses.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBClassess_260_0_16_32_112tt(i32 3, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112)) %CBClasses.cb_h, ptr @CBClasses.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CBMix.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CBMix.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBMixs_170_0_24_32_120_128_136_144_152_160_168tt(i32 4, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBMix, 170, 0, 24, 32, 120, 128, 136, 144, 152, 160, 168)) %CBMix.cb_h, ptr @CBMix.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CB_A.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB_A.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_As_188_0_32_76_80_120_128_144_160_182tt(i32 5, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_A, 188, 0, 32, 76, 80, 120, 128, 144, 160, 182)) %CB_A.cb_h, ptr @CB_A.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CB_B.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Bs_94_0_88tt(i32 6, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88)) %CB_B.cb_h, ptr @CB_B.cb, align 4
+
+// CHECK: define internal void @_init_buffer_CB_C.cb()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392))
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CB_Cs_400_0_16_112_128_392tt(i32 7, i32 0, i32 1, i32 0, i1 false)
+// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392)) %CB_C.cb_h, ptr @CB_C.cb, align 4
+
RWBuffer<float> Buf;
[numthreads(4,1,1)]
@@ -288,7 +336,13 @@ void main() {
// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
// CHECK-NEXT: entry:
// CHECK-NEXT: call void @_init_buffer_CBScalars.cb()
+// CHECK-NEXT: call void @_init_buffer_CBVectors.cb()
// CHECK-NEXT: call void @_init_buffer_CBArrays.cb()
+// CHECK-NEXT: call void @_init_buffer_CBTypedefArray.cb()
+// CHECK-NEXT: call void @_init_buffer_CBStructs.cb()
+// CHECK-NEXT: call void @_init_buffer_CBClasses.cb()
+// CHECK-NEXT: call void @_init_buffer_CBMix.cb()
+// CHECK-NEXT: call void @_init_buffer_CB_A.cb()
// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBTYPEDEFARRAY:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBCLASSES:[0-9]+]],
// CHECK-SAME: ![[CBMIX:[0-9]+]], ![[CB_A:[0-9]+]], ![[CB_B:[0-9]+]], ![[CB_C:[0-9]+]]}
>From bcf27e98aba08285c2367fd4e999cd58e9c13950 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 7 May 2025 21:21:03 -0700
Subject: [PATCH 2/6] Handle space-only implicit binding
---
clang/lib/Sema/SemaHLSL.cpp | 17 ++++++++++-------
clang/test/CodeGenHLSL/cbuffer.hlsl | 4 ++--
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 1bee554eec219..4de5f674cd5c7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -536,7 +536,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
BufDecl->addLayoutStruct(LS);
}
-void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
+static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
uint32_t ImplicitBindingOrderID) {
RegisterType RT =
BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
@@ -558,13 +558,16 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
// create buffer layout struct
createHostLayoutStructForBuffer(SemaRef, BufDecl);
- if (std::none_of(Dcl->attr_begin(), Dcl->attr_end(),
- [](Attr *A) { return isa<HLSLResourceBindingAttr>(A); })) {
+ HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>();
+ if (!RBA || RBA->isImplicit()) {
SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
- // add implicit HLSLResourceBindingAttr for the buffer
- // (used mostly as a way to tranfer ImplicitBindingOrderID to codegen)
- addImplicitBindingAttrToBuffer(SemaRef, BufDecl,
- getNextImplicitBindingOrderID());
+ // Use HLSLResourceBindingAttr as a way to transfer implicit binding
+ // order_ID to codegen. If it does not exist, create an implicit one.
+ uint32_t OrderID = getNextImplicitBindingOrderID();
+ if (RBA)
+ RBA->setImplicitBindingOrderID(OrderID);
+ else
+ addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID);
}
SemaRef.PopDeclContext();
diff --git a/clang/test/CodeGenHLSL/cbuffer.hlsl b/clang/test/CodeGenHLSL/cbuffer.hlsl
index 63da457dc4531..3fb76d57341cf 100644
--- a/clang/test/CodeGenHLSL/cbuffer.hlsl
+++ b/clang/test/CodeGenHLSL/cbuffer.hlsl
@@ -102,7 +102,7 @@ typedef uint32_t4 uint32_t8[2];
typedef uint4 T1;
typedef T1 T2[2]; // check a double typedef
-cbuffer CBTypedefArray {
+cbuffer CBTypedefArray : register(space2) {
uint32_t8 t1[2];
T2 t2[2];
}
@@ -287,7 +287,7 @@ cbuffer CB_C {
// CHECK: define internal void @_init_buffer_CBTypedefArray.cb()
// CHECK-NEXT: entry:
// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64))
-// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBTypedefArrays_128_0_64tt(i32 1, i32 0, i32 1, i32 0, i1 false)
+// CHECK-SAME: @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_CBTypedefArrays_128_0_64tt(i32 1, i32 2, i32 1, i32 0, i1 false)
// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4
// CHECK: define internal void @_init_buffer_CBStructs.cb()
>From 1f997d843a064769e2520d35ee6e00295a77010a Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 8 May 2025 10:35:14 -0700
Subject: [PATCH 3/6] clang-format
---
clang/lib/Sema/SemaHLSL.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 4de5f674cd5c7..e1e55641ca858 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -537,7 +537,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
}
static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
- uint32_t ImplicitBindingOrderID) {
+ uint32_t ImplicitBindingOrderID) {
RegisterType RT =
BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
auto *Attr =
>From 03da2d1955069590f81b554dd560099fcba2a41d Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 9 May 2025 11:27:45 -0700
Subject: [PATCH 4/6] update comment
---
clang/lib/Sema/SemaHLSL.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index a587ba89e348f..74139be0c8f9d 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -561,8 +561,8 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>();
if (!RBA || RBA->isImplicit()) {
SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
- // Use HLSLResourceBindingAttr as a way to transfer implicit binding
- // order_ID to codegen. If it does not exist, create an implicit one.
+ // Use HLSLResourceBindingAttr to transfer implicit binding order_ID
+ // to codegen. If it does not exist, create an implicit attribute.
uint32_t OrderID = getNextImplicitBindingOrderID();
if (RBA)
RBA->setImplicitBindingOrderID(OrderID);
>From f3d96052ae42ddd790a8f7f0b31ad8daae111128 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Fri, 9 May 2025 13:58:57 -0700
Subject: [PATCH 5/6] fix merge
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +-
clang/lib/Sema/SemaHLSL.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 327b43383d8d4..bb75b7d74847c 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -546,7 +546,7 @@ static void initializeBufferFromBinding(CodeGenModule &CGM,
auto *Space =
llvm::ConstantInt::get(CGM.IntTy, RBA ? RBA->getSpaceNumber() : 0);
- if (!RBA->isImplicit()) {
+ if (RBA->hasRegisterSlot()) {
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
Intrinsic::ID Intr =
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 74139be0c8f9d..5a23271d049fa 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -559,7 +559,7 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
createHostLayoutStructForBuffer(SemaRef, BufDecl);
HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>();
- if (!RBA || RBA->isImplicit()) {
+ if (!RBA || !RBA->hasRegisterSlot()) {
SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
// Use HLSLResourceBindingAttr to transfer implicit binding order_ID
// to codegen. If it does not exist, create an implicit attribute.
>From d4a3bcd58eb6d6f8799f1ac2f65c378628c1b9a9 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 12 May 2025 11:47:16 -0700
Subject: [PATCH 6/6] rename vars
---
clang/lib/CodeGen/CGHLSLRuntime.cpp | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index bb75b7d74847c..15159e36900c4 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -540,9 +540,9 @@ static void initializeBufferFromBinding(CodeGenModule &CGM,
llvm::GlobalVariable *GV,
HLSLResourceBindingAttr *RBA) {
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext());
- auto *False = llvm::ConstantInt::get(Int1Ty, false);
- auto *Zero = llvm::ConstantInt::get(CGM.IntTy, 0);
- auto *One = llvm::ConstantInt::get(CGM.IntTy, 1);
+ auto *NonUniform = llvm::ConstantInt::get(Int1Ty, false);
+ auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
+ auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
auto *Space =
llvm::ConstantInt::get(CGM.IntTy, RBA ? RBA->getSpaceNumber() : 0);
@@ -550,13 +550,15 @@ static void initializeBufferFromBinding(CodeGenModule &CGM,
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
Intrinsic::ID Intr =
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
- initializeBuffer(CGM, GV, Intr, {Space, RegSlot, One, Zero, False});
+ initializeBuffer(CGM, GV, Intr,
+ {Space, RegSlot, RangeSize, Index, NonUniform});
} else {
auto *OrderID =
llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
Intrinsic::ID Intr =
CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
- initializeBuffer(CGM, GV, Intr, {OrderID, Space, One, Zero, False});
+ initializeBuffer(CGM, GV, Intr,
+ {OrderID, Space, RangeSize, Index, NonUniform});
}
}
More information about the llvm-branch-commits
mailing list