Skip to content

Commit f95f303

Browse files
authored
[HLSL] Implicit resource binding for cbuffers (llvm#139022)
Constant buffers defined with the `cbuffer` keyword do not have a constructor. Instead, the call to initialize the resource handle based on its binding is generated in codegen. This change adds initialization of `cbuffer` handles that have implicit binding. Closes llvm#139617
1 parent 664c937 commit f95f303

File tree

8 files changed

+129
-26
lines changed

8 files changed

+129
-26
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4790,6 +4790,7 @@ def HLSLResourceBinding: InheritableAttr {
47904790
RegisterType RegType;
47914791
std::optional<unsigned> SlotNumber;
47924792
unsigned SpaceNumber;
4793+
std::optional<unsigned> ImplicitBindingOrderID;
47934794

47944795
public:
47954796
void setBinding(RegisterType RT, std::optional<unsigned> SlotNum, unsigned SpaceNum) {
@@ -4811,6 +4812,16 @@ def HLSLResourceBinding: InheritableAttr {
48114812
unsigned getSpaceNumber() const {
48124813
return SpaceNumber;
48134814
}
4815+
void setImplicitBindingOrderID(uint32_t Value) {
4816+
ImplicitBindingOrderID = Value;
4817+
}
4818+
bool hasImplicitBindingOrderID() const {
4819+
return ImplicitBindingOrderID.has_value();
4820+
}
4821+
uint32_t getImplicitBindingOrderID() const {
4822+
assert(hasImplicitBindingOrderID() && "attribute does not have implicit binding order id");
4823+
return ImplicitBindingOrderID.value();
4824+
}
48144825
}];
48154826
}
48164827

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/AST/Type.h"
2424
#include "clang/Basic/TargetOptions.h"
2525
#include "llvm/ADT/SmallVector.h"
26+
#include "llvm/IR/Constants.h"
2627
#include "llvm/IR/DerivedTypes.h"
2728
#include "llvm/IR/GlobalVariable.h"
2829
#include "llvm/IR/LLVMContext.h"
@@ -42,8 +43,8 @@ using namespace llvm;
4243
using llvm::hlsl::CBufferRowSizeInBytes;
4344

4445
static void initializeBufferFromBinding(CodeGenModule &CGM,
45-
llvm::GlobalVariable *GV, unsigned Slot,
46-
unsigned Space);
46+
llvm::GlobalVariable *GV,
47+
HLSLResourceBindingAttr *RBA);
4748

4849
namespace {
4950

@@ -271,13 +272,10 @@ void CGHLSLRuntime::addBuffer(const HLSLBufferDecl *BufDecl) {
271272
emitBufferGlobalsAndMetadata(BufDecl, BufGV);
272273

273274
// Initialize cbuffer from binding (implicit or explicit)
274-
const HLSLResourceBindingAttr *RBA =
275-
BufDecl->getAttr<HLSLResourceBindingAttr>();
276-
// FIXME: handle implicit binding if no binding attribute is found
277-
// (llvm/llvm-project#110722)
278-
if (RBA && RBA->hasRegisterSlot())
279-
initializeBufferFromBinding(CGM, BufGV, RBA->getSlotNumber(),
280-
RBA->getSpaceNumber());
275+
HLSLResourceBindingAttr *RBA = BufDecl->getAttr<HLSLResourceBindingAttr>();
276+
assert(RBA &&
277+
"cbuffer/tbuffer should always have resource binding attribute");
278+
initializeBufferFromBinding(CGM, BufGV, RBA);
281279
}
282280

283281
llvm::TargetExtType *
@@ -560,19 +558,29 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
560558
}
561559

562560
static void initializeBufferFromBinding(CodeGenModule &CGM,
563-
llvm::GlobalVariable *GV, unsigned Slot,
564-
unsigned Space) {
561+
llvm::GlobalVariable *GV,
562+
HLSLResourceBindingAttr *RBA) {
565563
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGM.getLLVMContext());
566-
llvm::Value *Args[] = {
567-
llvm::ConstantInt::get(CGM.IntTy, Space), /* reg_space */
568-
llvm::ConstantInt::get(CGM.IntTy, Slot), /* lower_bound */
569-
llvm::ConstantInt::get(CGM.IntTy, 1), /* range_size */
570-
llvm::ConstantInt::get(CGM.IntTy, 0), /* index */
571-
llvm::ConstantInt::get(Int1Ty, false) /* non-uniform */
572-
};
573-
initializeBuffer(CGM, GV,
574-
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic(),
575-
Args);
564+
auto *NonUniform = llvm::ConstantInt::get(Int1Ty, false);
565+
auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
566+
auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
567+
auto *Space =
568+
llvm::ConstantInt::get(CGM.IntTy, RBA ? RBA->getSpaceNumber() : 0);
569+
570+
if (RBA->hasRegisterSlot()) {
571+
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
572+
Intrinsic::ID Intr =
573+
CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
574+
initializeBuffer(CGM, GV, Intr,
575+
{Space, RegSlot, RangeSize, Index, NonUniform});
576+
} else {
577+
auto *OrderID =
578+
llvm::ConstantInt::get(CGM.IntTy, RBA->getImplicitBindingOrderID());
579+
Intrinsic::ID Intr =
580+
CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
581+
initializeBuffer(CGM, GV, Intr,
582+
{OrderID, Space, RangeSize, Index, NonUniform});
583+
}
576584
}
577585

578586
llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,18 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
537537
BufDecl->addLayoutStruct(LS);
538538
}
539539

540+
static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
541+
uint32_t ImplicitBindingOrderID) {
542+
RegisterType RT =
543+
BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
544+
auto *Attr =
545+
HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
546+
std::optional<unsigned> RegSlot;
547+
Attr->setBinding(RT, RegSlot, 0);
548+
Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
549+
BufDecl->addAttr(Attr);
550+
}
551+
540552
// Handle end of cbuffer/tbuffer declaration
541553
void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
542554
auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
@@ -547,9 +559,17 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
547559
// create buffer layout struct
548560
createHostLayoutStructForBuffer(SemaRef, BufDecl);
549561

550-
if (std::none_of(Dcl->attr_begin(), Dcl->attr_end(),
551-
[](Attr *A) { return isa<HLSLResourceBindingAttr>(A); }))
562+
HLSLResourceBindingAttr *RBA = Dcl->getAttr<HLSLResourceBindingAttr>();
563+
if (!RBA || !RBA->hasRegisterSlot()) {
552564
SemaRef.Diag(Dcl->getLocation(), diag::warn_hlsl_implicit_binding);
565+
// Use HLSLResourceBindingAttr to transfer implicit binding order_ID
566+
// to codegen. If it does not exist, create an implicit attribute.
567+
uint32_t OrderID = getNextImplicitBindingOrderID();
568+
if (RBA)
569+
RBA->setImplicitBindingOrderID(OrderID);
570+
else
571+
addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID);
572+
}
553573

554574
SemaRef.PopDeclContext();
555575
}
@@ -2000,6 +2020,8 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
20002020
HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
20012021
SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
20022022
DefaultCBufferDecls);
2023+
addImplicitBindingAttrToBuffer(SemaRef, DefaultCBuffer,
2024+
getNextImplicitBindingOrderID());
20032025
SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
20042026
createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer);
20052027

clang/test/AST/HLSL/ast-dump-comment-cbuffer.hlsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cbuffer A {
2121

2222
// AST: HLSLBufferDecl {{.*}} line:11:9 cbuffer A
2323
// AST-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
24+
// AST-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
2425
// AST-NEXT: FullComment
2526
// AST-NEXT: ParagraphComment
2627
// AST-NEXT: TextComment {{.*}} Text=" CBuffer decl."

clang/test/AST/HLSL/packoffset.hlsl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
cbuffer A
66
{
77
// CHECK-NEXT:-HLSLResourceClassAttr {{.*}} Implicit CBuffer
8+
// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
89
// CHECK-NEXT: VarDecl {{.*}} A1 'hlsl_constant float4'
910
// CHECK-NEXT: HLSLPackOffsetAttr {{.*}} 0 0
1011
float4 A1 : packoffset(c);

clang/test/AST/HLSL/pch_hlsl_buffer.hlsl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ float foo() {
1616
// Make sure cbuffer/tbuffer works for PCH.
1717
// CHECK: HLSLBufferDecl {{.*}} line:{{[0-9]+}}:9 imported <undeserialized declarations> cbuffer A
1818
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
19+
// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
1920
// CHECK-NEXT: VarDecl 0x[[A:[0-9a-f]+]] {{.*}} imported used a 'hlsl_constant float'
2021
// CHECK-NEXT: CXXRecordDecl {{.*}} imported implicit <undeserialized declarations> struct __cblayout_A definition
2122
// CHECK: FieldDecl {{.*}} imported a 'float'
2223

2324
// CHECK: HLSLBufferDecl {{.*}} line:{{[0-9]+}}:9 imported <undeserialized declarations> tbuffer B
2425
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit SRV
26+
// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
2527
// CHECK-NEXT: VarDecl 0x[[B:[0-9a-f]+]] {{.*}} imported used b 'hlsl_constant float'
2628
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} imported implicit <undeserialized declarations> struct __cblayout_B definition
2729
// CHECK: FieldDecl 0x{{[0-9a-f]+}} {{.*}} imported b 'float'

clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void main(unsigned GI : SV_GroupIndex) {}
2727
// Verify function constructors are emitted
2828
// NOINLINE-NEXT: call void @_Z13call_me_firstv()
2929
// NOINLINE-NEXT: call void @_Z12then_call_mev()
30+
// NOINLINE-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorFunction.hlsl()
3031
// NOINLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
3132
// NOINLINE-NEXT: call void @_Z4mainj(i32 %0)
3233
// NOINLINE-NEXT: call void @_Z12call_me_lastv(
@@ -36,6 +37,9 @@ void main(unsigned GI : SV_GroupIndex) {}
3637
// INLINE-NEXT: alloca
3738
// INLINE-NEXT: store i32 12
3839
// INLINE-NEXT: store i32 13
40+
// INLINE-NEXT: %[[HANDLE:.*]] = call target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0))
41+
// 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)
42+
// INLINE-NEXT: store target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 4, 0)) %[[HANDLE]], ptr @"$Globals.cb", align 4
3943
// INLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
4044
// INLINE-NEXT: store i32 %
4145
// INLINE-NEXT: store i32 0

clang/test/CodeGenHLSL/cbuffer.hlsl

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ typedef uint32_t4 uint32_t8[2];
102102
typedef uint4 T1;
103103
typedef T1 T2[2]; // check a double typedef
104104

105-
cbuffer CBTypedefArray {
105+
cbuffer CBTypedefArray : register(space2) {
106106
uint32_t8 t1[2];
107107
T2 t2[2];
108108
}
@@ -268,16 +268,64 @@ cbuffer CB_C {
268268

269269
// CHECK: define internal void @_init_buffer_CBScalars.cb()
270270
// CHECK-NEXT: entry:
271-
// CHECK-NEXT: %[[HANDLE1:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
271+
// CHECK-NEXT: %CBScalars.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBScalars, 56, 0, 8, 16, 24, 32, 36, 40, 48))
272272
// 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)
273273
// 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
274274

275+
// CHECK: define internal void @_init_buffer_CBVectors.cb()
276+
// CHECK-NEXT: entry:
277+
// CHECK-NEXT: %CBVectors.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBVectors, 136, 0, 16, 40, 48, 80, 96, 112))
278+
// 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)
279+
// 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
280+
275281
// CHECK: define internal void @_init_buffer_CBArrays.cb()
276282
// CHECK-NEXT: entry:
277-
// CHECK-NEXT: %[[HANDLE2:.*]] = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
283+
// CHECK-NEXT: %CBArrays.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBArrays, 708, 0, 48, 112, 176, 224, 608, 624, 656))
278284
// 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)
279285
// 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
280286

287+
// CHECK: define internal void @_init_buffer_CBTypedefArray.cb()
288+
// CHECK-NEXT: entry:
289+
// CHECK-NEXT: %CBTypedefArray.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64))
290+
// 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)
291+
// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBTypedefArray, 128, 0, 64)) %CBTypedefArray.cb_h, ptr @CBTypedefArray.cb, align 4
292+
293+
// CHECK: define internal void @_init_buffer_CBStructs.cb()
294+
// CHECK-NEXT: entry:
295+
// CHECK-NEXT: %CBStructs.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBStructs, 246, 0, 16, 32, 64, 144, 238, 240))
296+
// 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)
297+
// 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
298+
299+
// CHECK: define internal void @_init_buffer_CBClasses.cb()
300+
// CHECK-NEXT: entry:
301+
// CHECK-NEXT: %CBClasses.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112))
302+
// 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)
303+
// CHECK-NEXT: store target("dx.CBuffer", target("dx.Layout", %__cblayout_CBClasses, 260, 0, 16, 32, 112)) %CBClasses.cb_h, ptr @CBClasses.cb, align 4
304+
305+
// CHECK: define internal void @_init_buffer_CBMix.cb()
306+
// CHECK-NEXT: entry:
307+
// 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))
308+
// 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)
309+
// 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
310+
311+
// CHECK: define internal void @_init_buffer_CB_A.cb()
312+
// CHECK-NEXT: entry:
313+
// 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))
314+
// 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)
315+
// 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
316+
317+
// CHECK: define internal void @_init_buffer_CB_B.cb()
318+
// CHECK-NEXT: entry:
319+
// CHECK-NEXT: %CB_B.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_B, 94, 0, 88))
320+
// 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)
321+
// 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
322+
323+
// CHECK: define internal void @_init_buffer_CB_C.cb()
324+
// CHECK-NEXT: entry:
325+
// CHECK-NEXT: %CB_C.cb_h = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB_C, 400, 0, 16, 112, 128, 392))
326+
// 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)
327+
// 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
328+
281329
RWBuffer<float> Buf;
282330

283331
[numthreads(4,1,1)]
@@ -288,7 +336,13 @@ void main() {
288336
// CHECK: define internal void @_GLOBAL__sub_I_cbuffer.hlsl()
289337
// CHECK-NEXT: entry:
290338
// CHECK-NEXT: call void @_init_buffer_CBScalars.cb()
339+
// CHECK-NEXT: call void @_init_buffer_CBVectors.cb()
291340
// CHECK-NEXT: call void @_init_buffer_CBArrays.cb()
341+
// CHECK-NEXT: call void @_init_buffer_CBTypedefArray.cb()
342+
// CHECK-NEXT: call void @_init_buffer_CBStructs.cb()
343+
// CHECK-NEXT: call void @_init_buffer_CBClasses.cb()
344+
// CHECK-NEXT: call void @_init_buffer_CBMix.cb()
345+
// CHECK-NEXT: call void @_init_buffer_CB_A.cb()
292346

293347
// CHECK: !hlsl.cbs = !{![[CBSCALARS:[0-9]+]], ![[CBVECTORS:[0-9]+]], ![[CBARRAYS:[0-9]+]], ![[CBTYPEDEFARRAY:[0-9]+]], ![[CBSTRUCTS:[0-9]+]], ![[CBCLASSES:[0-9]+]],
294348
// CHECK-SAME: ![[CBMIX:[0-9]+]], ![[CB_A:[0-9]+]], ![[CB_B:[0-9]+]], ![[CB_C:[0-9]+]]}

0 commit comments

Comments
 (0)