Skip to content

Commit 662636e

Browse files
authored
[HLSL] Add implicit binding attribute to resource arrays (#152452)
If a resource array does not have an explicit binding attribute, SemaHLSL will add an implicit one. The attribute will be used to transfer implicit binding order ID to the codegen, the same way as it is done for HLSLBufferDecls. This is necessary in order to generate correct initialization of resources in an array that does not have an explicit binding. Depends on #152450 Part 1 of #145424
1 parent cbc8f65 commit 662636e

File tree

3 files changed

+91
-12
lines changed

3 files changed

+91
-12
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4932,6 +4932,7 @@ def HLSLResourceBinding: InheritableAttr {
49324932
return SpaceNumber;
49334933
}
49344934
void setImplicitBindingOrderID(uint32_t Value) {
4935+
assert(!hasImplicitBindingOrderID() && "attribute already has implicit binding order id");
49354936
ImplicitBindingOrderID = Value;
49364937
}
49374938
bool hasImplicitBindingOrderID() const {

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ static RegisterType getRegisterType(ResourceClass RC) {
7171
llvm_unreachable("unexpected ResourceClass value");
7272
}
7373

74+
static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) {
75+
return getRegisterType(ResTy->getAttrs().ResourceClass);
76+
}
77+
7478
// Converts the first letter of string Slot to RegisterType.
7579
// Returns false if the letter does not correspond to a valid register type.
7680
static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
@@ -342,6 +346,16 @@ static bool isResourceRecordTypeOrArrayOf(VarDecl *VD) {
342346
return Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray();
343347
}
344348

349+
static const HLSLAttributedResourceType *
350+
getResourceArrayHandleType(VarDecl *VD) {
351+
assert(VD->getType()->isHLSLResourceRecordArray() &&
352+
"expected array of resource records");
353+
const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
354+
while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
355+
Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType();
356+
return HLSLAttributedResourceType::findHandleTypeOnResource(Ty);
357+
}
358+
345359
// Returns true if the type is a leaf element type that is not valid to be
346360
// included in HLSL Buffer, such as a resource class, empty struct, zero-sized
347361
// array, or a builtin intangible type. Returns false it is a valid leaf element
@@ -568,16 +582,13 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) {
568582
BufDecl->addLayoutStruct(LS);
569583
}
570584

571-
static void addImplicitBindingAttrToBuffer(Sema &S, HLSLBufferDecl *BufDecl,
572-
uint32_t ImplicitBindingOrderID) {
573-
RegisterType RT =
574-
BufDecl->isCBuffer() ? RegisterType::CBuffer : RegisterType::SRV;
585+
static void addImplicitBindingAttrToDecl(Sema &S, Decl *D, RegisterType RT,
586+
uint32_t ImplicitBindingOrderID) {
575587
auto *Attr =
576588
HLSLResourceBindingAttr::CreateImplicit(S.getASTContext(), "", "0", {});
577-
std::optional<unsigned> RegSlot;
578-
Attr->setBinding(RT, RegSlot, 0);
589+
Attr->setBinding(RT, std::nullopt, 0);
579590
Attr->setImplicitBindingOrderID(ImplicitBindingOrderID);
580-
BufDecl->addAttr(Attr);
591+
D->addAttr(Attr);
581592
}
582593

583594
// Handle end of cbuffer/tbuffer declaration
@@ -600,7 +611,10 @@ void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) {
600611
if (RBA)
601612
RBA->setImplicitBindingOrderID(OrderID);
602613
else
603-
addImplicitBindingAttrToBuffer(SemaRef, BufDecl, OrderID);
614+
addImplicitBindingAttrToDecl(SemaRef, BufDecl,
615+
BufDecl->isCBuffer() ? RegisterType::CBuffer
616+
: RegisterType::SRV,
617+
OrderID);
604618
}
605619

606620
SemaRef.PopDeclContext();
@@ -1906,7 +1920,7 @@ static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc,
19061920
if (const HLSLAttributedResourceType *AttrResType =
19071921
HLSLAttributedResourceType::findHandleTypeOnResource(
19081922
VD->getType().getTypePtr())) {
1909-
if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass))
1923+
if (RegType == getRegisterType(AttrResType))
19101924
return true;
19111925

19121926
S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
@@ -2439,8 +2453,8 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) {
24392453
HLSLBufferDecl *DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer(
24402454
SemaRef.getASTContext(), SemaRef.getCurLexicalContext(),
24412455
DefaultCBufferDecls);
2442-
addImplicitBindingAttrToBuffer(SemaRef, DefaultCBuffer,
2443-
getNextImplicitBindingOrderID());
2456+
addImplicitBindingAttrToDecl(SemaRef, DefaultCBuffer, RegisterType::CBuffer,
2457+
getNextImplicitBindingOrderID());
24442458
SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer);
24452459
createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer);
24462460

@@ -3640,6 +3654,24 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
36403654

36413655
// process explicit bindings
36423656
processExplicitBindingsOnDecl(VD);
3657+
3658+
if (VD->getType()->isHLSLResourceRecordArray()) {
3659+
// If the resource array does not have an explicit binding attribute,
3660+
// create an implicit one. It will be used to transfer implicit binding
3661+
// order_ID to codegen.
3662+
if (!VD->hasAttr<HLSLVkBindingAttr>()) {
3663+
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3664+
if (!RBA || !RBA->hasRegisterSlot()) {
3665+
uint32_t OrderID = getNextImplicitBindingOrderID();
3666+
if (RBA)
3667+
RBA->setImplicitBindingOrderID(OrderID);
3668+
else
3669+
addImplicitBindingAttrToDecl(
3670+
SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)),
3671+
OrderID);
3672+
}
3673+
}
3674+
}
36433675
}
36443676

36453677
deduceAddressSpace(VD);

clang/test/AST/HLSL/resource_binding_attr.hlsl

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -ast-dump -o - %s | FileCheck %s
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -ast-dump -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL
2+
// RUN: %clang_cc1 -triple spirv-unknown-vulkan-library -finclude-default-header -ast-dump -o - %s | FileCheck %s -check-prefixes=CHECK,SPV
23

34
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 4]]:9 cbuffer CB
45
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
@@ -34,6 +35,10 @@ RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
3435
// CHECK: HLSLResourceBindingAttr {{.*}} "" "space5"
3536
RWBuffer<float> UAV3 : register(space5);
3637

38+
// CHECK: VarDecl {{.*}} UAV_Array 'RWBuffer<float>[10]'
39+
// CHECK: HLSLResourceBindingAttr {{.*}} "u10" "space6"
40+
RWBuffer<float> UAV_Array[10] : register(u10, space6);
41+
3742
//
3843
// Default constants ($Globals) layout annotations
3944

@@ -56,3 +61,44 @@ struct S {
5661
// CHECK: VarDecl {{.*}} s 'hlsl_constant S'
5762
// CHECK: HLSLResourceBindingAttr {{.*}} "c10" "space0
5863
S s : register(c10);
64+
65+
//
66+
// Implicit binding
67+
68+
// Constant buffers should have implicit binding attribute added by SemaHLSL,
69+
// unless the target is SPIR-V and there is [[vk::binding]] attribute.
70+
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 3]]:9 cbuffer CB2
71+
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
72+
// CHECK-NEXT: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
73+
cbuffer CB2 {
74+
float4 c;
75+
}
76+
77+
// CHECK: HLSLBufferDecl {{.*}} line:[[# @LINE + 7]]:9 cbuffer CB3
78+
// CHECK-NEXT: HLSLResourceClassAttr {{.*}} Implicit CBuffer
79+
// DXIL: HLSLResourceBindingAttr {{.*}} Implicit
80+
// DXIL-NOT: HLSLVkBindingAttr
81+
// SPV: HLSLVkBindingAttr {{.*}} 1 0
82+
// SPV-NOT: HLSLResourceBindingAttr {{.*}} Implicit
83+
[[vk::binding(1)]]
84+
cbuffer CB3 {
85+
float2 d;
86+
}
87+
88+
// Resource arrays should have implicit binding attribute added by SemaHLSL,
89+
// unless the target is SPIR-V and there is [[vk::binding]] attribute.
90+
// CHECK: VarDecl {{.*}} SB 'StructuredBuffer<float>[10]'
91+
// CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0"
92+
StructuredBuffer<float> SB[10];
93+
94+
// CHECK: VarDecl {{.*}} SB2 'StructuredBuffer<float>[10]'
95+
// DXIL: HLSLResourceBindingAttr {{.*}} Implicit
96+
// DXIL-NOT: HLSLVkBindingAttr
97+
// SPV: HLSLVkBindingAttr {{.*}} 2 0
98+
// SPV-NOT: HLSLResourceBindingAttr {{.*}} Implicit
99+
[[vk::binding(2)]]
100+
StructuredBuffer<float> SB2[10];
101+
102+
// $Globals should have implicit binding attribute added by SemaHLSL
103+
// CHECK: HLSLBufferDecl {{.*}} implicit cbuffer $Globals
104+
// CHECK: HLSLResourceBindingAttr {{.*}} Implicit "" "0"

0 commit comments

Comments
 (0)