Skip to content

[HLSL] Implicit resource binding for cbuffers #139022

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
d5685ec
[HLSL] Implement DXILResourceBindingAnalysis
hekota Apr 24, 2025
d8a4a3f
Rename DXILResourceBindingsInfo to DXILResourceBindingInfo
hekota Apr 25, 2025
d79900c
Merge branch 'main' of https://github.com/llvm/llvm-project into reso…
hekota Apr 25, 2025
c718763
Add wrapper pass
hekota Apr 26, 2025
9a70f06
update signature
hekota Apr 28, 2025
bca1bf3
code review feedback - rename flags, remove unnecessary functions, do…
hekota Apr 30, 2025
f58e2d5
[HLSL] Implementation of DXILResourceImplicitBinding pass
hekota Apr 30, 2025
b65d3bc
fix bug & update tests
hekota May 1, 2025
075e27e
Merge branch 'main' of https://github.com/llvm/llvm-project into reso…
hekota May 2, 2025
2f0aba1
Remove extra new line
hekota May 5, 2025
79c2e7b
Merge branch 'main' of https://github.com/llvm/llvm-project into impl…
hekota May 6, 2025
e9747e5
Merge branch 'main' of https://github.com/llvm/llvm-project into reso…
hekota May 6, 2025
da838a9
Merge branch 'users/hekota/pr137258-resource-binding-analysis' of htt…
hekota May 6, 2025
dfce6ce
[HLSL] Add resource constructor with implicit binding for global reso…
hekota May 7, 2025
8194951
[HLSL] Implicit binding for cbuffers
hekota May 8, 2025
bcf27e9
Handle space-only implicit binding
hekota May 8, 2025
1f997d8
clang-format
hekota May 8, 2025
8a27708
code review feedback - use std::optional, renames
hekota May 9, 2025
bc93994
Merge branch 'main' of https://github.com/llvm/llvm-project into impl…
hekota May 9, 2025
8142713
Merge branch 'users/hekota/pr138043-implicit-binding-pass' of https:/…
hekota May 9, 2025
9eab67d
Merge branch 'users/hekota/pr138976-implicit-binding-constructor' of …
hekota May 9, 2025
4a3e4c5
revert changes to StructuredBuffers-methods-ps.hlsl
hekota May 9, 2025
03da2d1
update comment
hekota May 9, 2025
f3d9605
fix merge
hekota May 9, 2025
d4a3bcd
rename vars
hekota May 12, 2025
fb3d516
Merge branch 'main' of https://github.com/llvm/llvm-project into impl…
hekota May 13, 2025
2ff496b
code review feedback - update comment, rename param
hekota May 14, 2025
e4369aa
Merge branch 'main' of https://github.com/llvm/llvm-project into impl…
hekota May 14, 2025
cecd1e4
simplify constructor tests
hekota May 14, 2025
cef2c3e
rename vars
hekota May 14, 2025
d82236d
Merge branch 'users/hekota/pr138976-implicit-binding-constructor' int…
hekota May 14, 2025
84d710d
Merge branch 'main' into implicit-binding-cbuffers
hekota May 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -4789,6 +4789,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) {
Expand All @@ -4810,6 +4811,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();
}
}];
}

Expand Down
50 changes: 29 additions & 21 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {

Expand Down Expand Up @@ -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->hasRegisterSlot())
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 *
Expand Down Expand Up @@ -539,19 +537,29 @@ 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 *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);

if (RBA->hasRegisterSlot()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are unconditionally dereferencing RBA here just the line before you are using conditional operator to check if RBA is nullptr. One of these lines is in error.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened issue here: #145525

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @shafik for following up! I was planning to fix this before I left on vacation but didn't get to it.

auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
Intrinsic::ID Intr =
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
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, RangeSize, Index, NonUniform});
}
}

llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
Expand Down
26 changes: 24 additions & 2 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,18 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
BufDecl->addLayoutStruct(LS);
}

static 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);
Expand All @@ -547,9 +559,17 @@ 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->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.
uint32_t OrderID = getNextImplicitBindingOrderID();
if (RBA)
RBA->setImplicitBindingOrderID(OrderID);
else
addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID);
}

SemaRef.PopDeclContext();
}
Expand Down Expand Up @@ -1999,6 +2019,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);

Expand Down
1 change: 1 addition & 0 deletions clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
1 change: 1 addition & 0 deletions clang/test/AST/HLSL/packoffset.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions clang/test/AST/HLSL/pch_hlsl_buffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 4 additions & 0 deletions clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down
60 changes: 57 additions & 3 deletions clang/test/CodeGenHLSL/cbuffer.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
Expand Down Expand Up @@ -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 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()
// 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)]
Expand All @@ -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]+]]}
Expand Down