Skip to content

Commit 8b18fe8

Browse files
committed
Add support for [[vk::binding]] attribute on resource arrays
1 parent b3138c2 commit 8b18fe8

File tree

4 files changed

+81
-38
lines changed

4 files changed

+81
-38
lines changed

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ class SemaHLSL : public SemaBase {
237237
bool initGlobalResourceArrayDecl(VarDecl *VD);
238238
void createResourceRecordCtorArgs(const Type *ResourceTy, StringRef VarName,
239239
HLSLResourceBindingAttr *RBA,
240+
HLSLVkBindingAttr *VkBinding,
240241
uint32_t ArrayIndex,
241242
llvm::SmallVector<Expr *> &Args);
242243
};

clang/lib/CodeGen/CGHLSLRuntime.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,29 @@ static void createResourceCtorArgs(CodeGenModule &CGM, CXXConstructorDecl *CD,
164164
llvm::Value *ThisPtr, llvm::Value *Range,
165165
llvm::Value *Index, StringRef Name,
166166
HLSLResourceBindingAttr *RBA,
167+
HLSLVkBindingAttr *VkBinding,
167168
CallArgList &Args) {
169+
assert((VkBinding || RBA) && "at least one a binding attribute expected");
170+
171+
std::optional<uint32_t> RegisterSlot;
172+
uint32_t SpaceNo = 0;
173+
if (VkBinding) {
174+
RegisterSlot = VkBinding->getBinding();
175+
SpaceNo = VkBinding->getSet();
176+
} else if (RBA) {
177+
if (RBA->hasRegisterSlot())
178+
RegisterSlot = RBA->getSlotNumber();
179+
SpaceNo = RBA->getSpaceNumber();
180+
}
181+
168182
ASTContext &AST = CD->getASTContext();
169183
Value *NameStr = buildNameForResource(Name, CGM);
170-
Value *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
184+
Value *Space = llvm::ConstantInt::get(CGM.IntTy, SpaceNo);
171185

172186
Args.add(RValue::get(ThisPtr), CD->getThisType());
173-
if (RBA->hasRegisterSlot()) {
187+
if (RegisterSlot.has_value()) {
174188
// explicit binding
175-
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
189+
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RegisterSlot.value());
176190
Args.add(RValue::get(RegSlot), AST.UnsignedIntTy);
177191
Args.add(RValue::get(Space), AST.UnsignedIntTy);
178192
Args.add(RValue::get(Range), AST.IntTy);
@@ -696,13 +710,6 @@ static void initializeBuffer(CodeGenModule &CGM, llvm::GlobalVariable *GV,
696710
CGM.AddCXXGlobalInit(InitResFunc);
697711
}
698712

699-
static Value *buildNameForResource(llvm::StringRef BaseName,
700-
CodeGenModule &CGM) {
701-
std::string Str(BaseName);
702-
std::string GlobalName(Str + ".str");
703-
return CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
704-
}
705-
706713
void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
707714
llvm::GlobalVariable *GV,
708715
HLSLVkBindingAttr *VkBinding) {
@@ -730,17 +737,13 @@ void CGHLSLRuntime::initializeBufferFromBinding(const HLSLBufferDecl *BufDecl,
730737
auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
731738
auto *RangeSize = llvm::ConstantInt::get(CGM.IntTy, 1);
732739
auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
733-
Value *Name = nullptr;
740+
Value *Name = buildNameForResource(BufDecl->getName(), CGM);
734741

735742
llvm::Intrinsic::ID IntrinsicID =
736743
RBA->hasRegisterSlot()
737744
? CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic()
738745
: CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
739746

740-
std::string Str(BufDecl->getName());
741-
std::string GlobalName(Str + ".str");
742-
Name = CGM.GetAddrOfConstantCString(Str, GlobalName.c_str()).getPointer();
743-
744747
// buffer with explicit binding
745748
if (RBA->hasRegisterSlot()) {
746749
auto *RegSlot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
@@ -854,15 +857,16 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
854857
}
855858

856859
// find binding info for the resource array
857-
// (for implicit binding it should have been by SemaHLSL)
860+
// (for implicit binding an HLSLResourceBindingAttr should have been added by SemaHLSL)
858861
QualType ResourceTy = ArraySubsExpr->getType();
862+
HLSLVkBindingAttr *VkBinding = ArrayDecl->getAttr<HLSLVkBindingAttr>();
859863
HLSLResourceBindingAttr *RBA = ArrayDecl->getAttr<HLSLResourceBindingAttr>();
860-
assert(RBA && "resource array is missing HLSLResourceBindingAttr attribute");
864+
assert((VkBinding || RBA) && "resource array must have a binding attribute");
861865

862866
// lookup the resource class constructor based on the resource type and
863867
// binding
864868
CXXConstructorDecl *CD = findResourceConstructorDecl(
865-
ArrayDecl->getASTContext(), ResourceTy, RBA->hasRegisterSlot());
869+
ArrayDecl->getASTContext(), ResourceTy, VkBinding || RBA->hasRegisterSlot());
866870

867871
// create a temporary variable for the resource class instance (we need to
868872
// return an LValue)
@@ -885,7 +889,7 @@ std::optional<LValue> CGHLSLRuntime::emitResourceArraySubscriptExpr(
885889
// assemble the constructor parameters
886890
CallArgList Args;
887891
createResourceCtorArgs(CGM, CD, ThisPtr, Range, Index, ArrayDecl->getName(),
888-
RBA, Args);
892+
RBA, VkBinding, Args);
889893

890894
// call the constructor
891895
CGF.EmitCXXConstructorCall(CD, Ctor_Complete, false, false, ThisAddress, Args,

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3661,15 +3661,17 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) {
36613661
// If the resource array does not have an explicit binding attribute,
36623662
// create an implicit one. It will be used to transfer implicit binding
36633663
// order_ID to codegen.
3664-
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3665-
if (!RBA || !RBA->hasRegisterSlot()) {
3666-
uint32_t OrderID = getNextImplicitBindingOrderID();
3667-
if (RBA)
3668-
RBA->setImplicitBindingOrderID(OrderID);
3669-
else
3670-
addImplicitBindingAttrToDecl(
3671-
SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)),
3672-
OrderID);
3664+
if (!VD->hasAttr<HLSLVkBindingAttr>()) {
3665+
HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
3666+
if (!RBA || !RBA->hasRegisterSlot()) {
3667+
uint32_t OrderID = getNextImplicitBindingOrderID();
3668+
if (RBA)
3669+
RBA->setImplicitBindingOrderID(OrderID);
3670+
else
3671+
addImplicitBindingAttrToDecl(
3672+
SemaRef, VD, getRegisterType(getResourceArrayHandleType(VD)),
3673+
OrderID);
3674+
}
36733675
}
36743676
}
36753677

@@ -3745,9 +3747,12 @@ void SemaHLSL::createResourceRecordCtorArgs(const Type *ResourceTy,
37453747
Args.append({RegSlot, Space, RangeSize, Index, Name});
37463748
} else {
37473749
// resource with implicit binding
3750+
uint32_t OrderID = (RBA && RBA->hasImplicitBindingOrderID())
3751+
? RBA->getImplicitBindingOrderID()
3752+
: getNextImplicitBindingOrderID();
37483753
IntegerLiteral *OrderId = IntegerLiteral::Create(
3749-
AST, llvm::APInt(UIntTySize, getNextImplicitBindingOrderID()),
3750-
AST.UnsignedIntTy, SourceLocation());
3754+
AST, llvm::APInt(UIntTySize, OrderID), AST.UnsignedIntTy,
3755+
SourceLocation());
37513756
Args.append({Space, RangeSize, Index, OrderId, Name});
37523757
}
37533758
}
Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,59 @@
11
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-compute -finclude-default-header \
2-
// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
2+
// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,DXIL
33
// RUN: %clang_cc1 -finclude-default-header -triple spirv-unknown-vulkan-compute \
4-
// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
4+
// RUN: -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -check-prefixes=CHECK,SPIRV
55

66
// CHECK: @[[BufA:.*]] = private unnamed_addr constant [2 x i8] c"A\00", align 1
77
// CHECK: @[[BufB:.*]] = private unnamed_addr constant [2 x i8] c"B\00", align 1
8+
// CHECK: @[[BufC:.*]] = private unnamed_addr constant [2 x i8] c"C\00", align 1
9+
// CHECK: @[[BufD:.*]] = private unnamed_addr constant [2 x i8] c"D\00", align 1
810

11+
// different explicit binding for DXIL and SPIR-V
12+
[[vk::binding(12, 2)]]
913
RWBuffer<float> A[4] : register(u10, space1);
10-
RWBuffer<int> B[5]; // implicit binding -> u0, space0
14+
15+
[[vk::binding(13)]] // SPIR-V explicit binding 13, set 0
16+
RWBuffer<int> B[5]; // DXIL implicit binding in space0
17+
18+
// same explicit binding for both DXIL and SPIR-V
19+
// (SPIR-V takes the binding from register annotation if there is no vk::binding attribute))
20+
RWBuffer<int> C[3] : register(u2);
21+
22+
// implicit binding for both DXIL and SPIR-V in space/set 0
23+
RWBuffer<double> D[10];
24+
1125
RWStructuredBuffer<float> Out;
1226

1327
[numthreads(4,1,1)]
1428
void main() {
1529
// CHECK: define internal{{.*}} void @_Z4mainv()
1630
// CHECK: %[[Tmp0:.*]] = alloca %"class.hlsl::RWBuffer
1731
// CHECK: %[[Tmp1:.*]] = alloca %"class.hlsl::RWBuffer
32+
// CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWBuffer
33+
// CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
34+
35+
// Make sure A[2] is translated to a RWBuffer<float> constructor call with range 4 and index 2
36+
// and DXIL explicit binding (u10, space1)
37+
// and SPIR-V explicit binding (binding 12, set 2)
38+
// DXIL: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
39+
// SPV: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
1840

19-
// Make sure that A[2] is translated to a RWBuffer<float> constructor call for explicit binding (u10, space1) with range 4 and index 2
20-
// CHECK: call void @_ZN4hlsl8RWBufferIfEC1EjjijPKc(ptr {{.*}} %[[Tmp0]], i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
41+
// Make sure B[3] is translated to a RWBuffer<int> constructor call with range 5 and index 3
42+
// and DXIL for implicit binding in space0, order id 0
43+
// and SPIR-V explicit binding (binding 13, set 0)
44+
// DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 0, i32 noundef 5, i32 noundef 3, i32 noundef 0, ptr noundef @[[BufB]])
45+
// SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 13, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]])
2146

22-
// Make sure that A[3] is translated to a RWBuffer<int> constructor call for implicit binding (u0, space0) with range 5 and index 3
23-
// CHECK: call void @_ZN4hlsl8RWBufferIiEC1EjijjPKc(ptr {{.*}} %[[Tmp1]], i32 noundef 0, i32 noundef 5, i32 noundef 3, i32 noundef 0, ptr noundef @[[BufB]])
47+
// Make sure C[1] is translated to a RWBuffer<int> constructor call with range 3 and index 1
48+
// and DXIL explicit binding (u2, space0)
49+
// and SPIR-V explicit binding (binding 2, set 0)
50+
// DXIL: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
51+
// SPV: call void @_ZN4hlsl8RWBufferIiEC1EjjijPKc(ptr {{.*}} %[[Tmp2]], i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
2452

25-
Out[0] = A[2][0] + (float)B[3][0];
53+
// Make sure D[7] is translated to a RWBuffer<doublet> constructor call with range 10 and index 7
54+
// and DXIL for implicit binding in space0, order id 1
55+
// and SPIR-V explicit binding (binding 13, set 0), order id 0
56+
// DXIL: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 1, ptr noundef @[[BufD]])
57+
// SPV: call void @_ZN4hlsl8RWBufferIdEC1EjijjPKc(ptr {{.*}} %[[Tmp3]], i32 noundef 0, i32 noundef 10, i32 noundef 7, i32 noundef 0, ptr noundef @[[BufD]])
58+
Out[0] = A[2][0] + (float)B[3][0] + (float)C[1][0] + (float)D[7][0];
2659
}

0 commit comments

Comments
 (0)