Skip to content

Commit 5110e68

Browse files
committed
[SPIRV] Support Peeled Array Layouts for HLSL CBuffers
This commit adds support for 'peeled arrays' in HLSL constant buffers. HLSL CBuffers may have padding between array elements but not after the last element. This is represented in LLVM IR as {[N-1 x {T, pad}], T}. Changes include: - Recognition of the peeled array pattern. - Logic to reconstitute these into SPIR-V compatible arrays. - Support for spirv.Padding type in GlobalRegistry and Builtins. - Updates to SPIRVCBufferAccess to correctly calculate member offsets in these padded structures. Depends on #169076
1 parent 99e9b17 commit 5110e68

File tree

10 files changed

+250
-3
lines changed

10 files changed

+250
-3
lines changed

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,8 @@ SPIRVType *lowerBuiltinType(const Type *OpaqueType,
33733373
TargetType = getInlineSpirvType(BuiltinType, MIRBuilder, GR);
33743374
} else if (Name == "spirv.VulkanBuffer") {
33753375
TargetType = getVulkanBufferType(BuiltinType, MIRBuilder, GR);
3376+
} else if (Name == "spirv.Padding") {
3377+
TargetType = GR->getOrCreatePaddingType(MIRBuilder);
33763378
} else if (Name == "spirv.Layout") {
33773379
TargetType = getLayoutType(BuiltinType, MIRBuilder, GR);
33783380
} else {

llvm/lib/Target/SPIRV/SPIRVCBufferAccess.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,20 @@ static bool replaceCBufferAccesses(Module &M) {
7979
// The handle definition should dominate all uses of the cbuffer members.
8080
// We'll insert our getpointer calls right after it.
8181
IRBuilder<> Builder(HandleDef->getNextNode());
82+
auto *HandleTy = cast<TargetExtType>(Mapping.Handle->getValueType());
83+
auto *LayoutTy = cast<StructType>(HandleTy->getTypeParameter(0));
84+
const StructLayout *SL = M.getDataLayout().getStructLayout(LayoutTy);
8285

83-
for (uint32_t Index = 0; Index < Mapping.Members.size(); ++Index) {
84-
GlobalVariable *MemberGV = Mapping.Members[Index].GV;
86+
for (const hlsl::CBufferMember &Member : Mapping.Members) {
87+
GlobalVariable *MemberGV = Member.GV;
8588
if (MemberGV->use_empty()) {
8689
continue;
8790
}
8891

92+
uint32_t IndexInStruct = SL->getElementContainingOffset(Member.Offset);
93+
8994
// Create the getpointer intrinsic call.
90-
Value *IndexVal = Builder.getInt32(Index);
95+
Value *IndexVal = Builder.getInt32(IndexInStruct);
9196
Type *PtrType = MemberGV->getType();
9297
Value *GetPointerCall = Builder.CreateIntrinsic(
9398
PtrType, Intrinsic::spv_resource_getpointer, {HandleDef, IndexVal});

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,7 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
841841
uint32_t Index = cast<ConstantInt>(II->getOperand(1))->getZExtValue();
842842
Ty = cast<StructType>(Ty)->getElementType(Index);
843843
}
844+
Ty = reconstitutePeeledArrayType(Ty);
844845
} else {
845846
llvm_unreachable("Unknown handle type for spv_resource_getpointer.");
846847
}

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,17 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeStruct(
889889
const StructType *Ty, MachineIRBuilder &MIRBuilder,
890890
SPIRV::AccessQualifier::AccessQualifier AccQual,
891891
StructOffsetDecorator Decorator, bool EmitIR) {
892+
Type *OriginalElementType = nullptr;
893+
uint64_t TotalSize = 0;
894+
if (matchPeeledArrayPattern(Ty, OriginalElementType, TotalSize)) {
895+
SPIRVType *ElementSPIRVType = findSPIRVType(
896+
OriginalElementType, MIRBuilder, AccQual,
897+
/* ExplicitLayoutRequired= */ Decorator != nullptr, EmitIR);
898+
return getOpTypeArray(TotalSize, ElementSPIRVType, MIRBuilder,
899+
/*ExplicitLayoutRequired=*/Decorator != nullptr,
900+
EmitIR);
901+
}
902+
892903
const SPIRVSubtarget &ST =
893904
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
894905
SmallVector<Register, 4> FieldTypes;
@@ -1405,6 +1416,18 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateVulkanBufferType(
14051416
return R;
14061417
}
14071418

1419+
SPIRVType *
1420+
SPIRVGlobalRegistry::getOrCreatePaddingType(MachineIRBuilder &MIRBuilder) {
1421+
auto Key = SPIRV::irhandle_padding();
1422+
if (const MachineInstr *MI = findMI(Key, &MIRBuilder.getMF()))
1423+
return MI;
1424+
auto *T = Type::getInt8Ty(MIRBuilder.getContext());
1425+
SPIRVType *R = getOrCreateSPIRVIntegerType(8, MIRBuilder);
1426+
finishCreatingSPIRVType(T, R);
1427+
add(Key, R);
1428+
return R;
1429+
}
1430+
14081431
SPIRVType *SPIRVGlobalRegistry::getOrCreateLayoutType(
14091432
MachineIRBuilder &MIRBuilder, const TargetExtType *T, bool EmitIr) {
14101433
auto Key = SPIRV::handle(T);

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ class SPIRVGlobalRegistry : public SPIRVIRMapping {
611611
SPIRV::StorageClass::StorageClass SC,
612612
bool IsWritable, bool EmitIr = false);
613613

614+
SPIRVType *getOrCreatePaddingType(MachineIRBuilder &MIRBuilder);
615+
614616
SPIRVType *getOrCreateLayoutType(MachineIRBuilder &MIRBuilder,
615617
const TargetExtType *T, bool EmitIr = false);
616618

llvm/lib/Target/SPIRV/SPIRVIRMapping.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ enum SpecialTypeKind {
6464
STK_Value,
6565
STK_MachineInstr,
6666
STK_VkBuffer,
67+
STK_Padding,
6768
STK_ExplictLayoutType,
6869
STK_Last = -1
6970
};
@@ -149,6 +150,10 @@ inline IRHandle irhandle_vkbuffer(const Type *ElementType,
149150
SpecialTypeKind::STK_VkBuffer);
150151
}
151152

153+
inline IRHandle irhandle_padding() {
154+
return std::make_tuple(nullptr, 0, SpecialTypeKind::STK_Padding);
155+
}
156+
152157
inline IRHandle irhandle_explict_layout_type(const Type *Ty) {
153158
const Type *WrpTy = unifyPtrType(Ty);
154159
return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_ExplictLayoutType);

llvm/lib/Target/SPIRV/SPIRVUtils.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,71 @@ getFirstValidInstructionInsertPoint(MachineBasicBlock &BB) {
10421042
: VarPos;
10431043
}
10441044

1045+
bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
1046+
uint64_t &TotalSize) {
1047+
// An array of N padded structs is represented as {[N-1 x <{T, pad}>], T}.
1048+
if (!Ty->isStructTy() || Ty->getStructNumElements() != 2)
1049+
return false;
1050+
1051+
Type *FirstElement = Ty->getStructElementType(0);
1052+
Type *SecondElement = Ty->getStructElementType(1);
1053+
1054+
if (!FirstElement->isArrayTy())
1055+
return false;
1056+
1057+
Type *ArrayElementType = FirstElement->getArrayElementType();
1058+
if (!ArrayElementType->isStructTy() ||
1059+
ArrayElementType->getStructNumElements() != 2)
1060+
return false;
1061+
1062+
Type *T_in_struct = ArrayElementType->getStructElementType(0);
1063+
if (T_in_struct != SecondElement)
1064+
return false;
1065+
1066+
const uint64_t ArraySize = FirstElement->getArrayNumElements();
1067+
TotalSize = ArraySize + 1;
1068+
OriginalElementType = ArrayElementType;
1069+
return true;
1070+
}
1071+
1072+
Type *reconstitutePeeledArrayType(Type *Ty) {
1073+
if (!Ty->isStructTy())
1074+
return Ty;
1075+
1076+
auto *STy = cast<StructType>(Ty);
1077+
Type *OriginalElementType = nullptr;
1078+
uint64_t TotalSize = 0;
1079+
if (matchPeeledArrayPattern(STy, OriginalElementType, TotalSize)) {
1080+
Type *ResultTy = ArrayType::get(
1081+
reconstitutePeeledArrayType(OriginalElementType), TotalSize);
1082+
return ResultTy;
1083+
}
1084+
1085+
SmallVector<Type *, 4> NewElementTypes;
1086+
bool Changed = false;
1087+
for (Type *ElementTy : STy->elements()) {
1088+
Type *NewElementTy = reconstitutePeeledArrayType(ElementTy);
1089+
if (NewElementTy != ElementTy)
1090+
Changed = true;
1091+
NewElementTypes.push_back(NewElementTy);
1092+
}
1093+
1094+
if (Changed) {
1095+
Type *ResultTy;
1096+
if (STy->isLiteral())
1097+
ResultTy =
1098+
StructType::get(STy->getContext(), NewElementTypes, STy->isPacked());
1099+
else {
1100+
auto *NewTy = StructType::create(STy->getContext(), STy->getName());
1101+
NewTy->setBody(NewElementTypes, STy->isPacked());
1102+
ResultTy = NewTy;
1103+
}
1104+
return ResultTy;
1105+
}
1106+
1107+
return Ty;
1108+
}
1109+
10451110
std::optional<SPIRV::LinkageType::LinkageType>
10461111
getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
10471112
if (GV.hasLocalLinkage() || GV.hasHiddenVisibility())

llvm/lib/Target/SPIRV/SPIRVUtils.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,21 @@ Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx);
321321
// Returns true if the function was changed.
322322
bool sortBlocks(Function &F);
323323

324+
// Check for peeled array structs and recursively reconstitute them. In HLSL
325+
// CBuffers, arrays may have padding between the elements, but not after the
326+
// last element. To represent this in LLVM IR an array [N x T] will be
327+
// represented as {[N-1 x {T, spirv.Padding}], T}. The function
328+
// matchPeeledArrayPattern recognizes this pattern retrieving the type {T,
329+
// spirv.Padding}, and the size N.
330+
bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
331+
uint64_t &TotalSize);
332+
333+
// This function will turn the type {[N-1 x {T, spirv.Padding}], T} back into
334+
// [N x {T, spirv.Padding}]. So it can be translated into SPIR-V. The offset
335+
// decorations will be such that there will be no padding after the array when
336+
// relevant.
337+
Type *reconstitutePeeledArrayType(Type *Ty);
338+
324339
inline bool hasInitializer(const GlobalVariable *GV) {
325340
return GV->hasInitializer() && !isa<UndefValue>(GV->getInitializer());
326341
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
; RUN: llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
5+
; CHECK: %[[STRUCT:[0-9]+]] = OpTypeStruct %[[FLOAT]]
6+
; CHECK: %[[I8:[0-9]+]] = OpTypeInt 8 0
7+
; CHECK: %[[STRUCT_PAD:[0-9]+]] = OpTypeStruct %[[STRUCT]] %[[I8]]
8+
; CHECK: %[[UINT:[0-9]+]] = OpTypeInt 32 0
9+
; CHECK: %[[CONST_4:[0-9]+]] = OpConstant %[[UINT]] 4
10+
; CHECK: %[[ARRAY:[0-9]+]] = OpTypeArray %[[STRUCT_PAD]] %[[CONST_4]]
11+
; CHECK: %[[CBLAYOUT:[0-9]+]] = OpTypeStruct %[[ARRAY]] %[[FLOAT]]
12+
; CHECK: %[[WRAPPER:[0-9]+]] = OpTypeStruct %[[CBLAYOUT]]
13+
; CHECK: %[[PTR_WRAPPER:[0-9]+]] = OpTypePointer Uniform %[[WRAPPER]]
14+
; CHECK: %[[ZERO:[0-9]+]] = OpConstant %[[UINT]] 0
15+
; CHECK: %[[MYCBUFFER:[0-9]+]] = OpVariable %[[PTR_WRAPPER]] Uniform
16+
17+
%__cblayout_MyCBuffer = type <{ <{ [3 x <{ %OrigType, target("spirv.Padding", 12) }>], %OrigType }>, float }>
18+
%OrigType = type <{ float }>
19+
20+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
21+
@myArray = external hidden local_unnamed_addr addrspace(12) global <{ [3 x <{ %OrigType, target("spirv.Padding", 12) }>], %OrigType }>, align 1
22+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
23+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
24+
25+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
26+
27+
define void @main() #1 {
28+
entry:
29+
; CHECK: %[[BUFFER_HANDLE:[0-9]+]] = OpCopyObject %[[PTR_WRAPPER]] %[[MYCBUFFER]]
30+
; CHECK: %[[ACCESS_ARRAY:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[BUFFER_HANDLE]] %[[ZERO]] %[[ZERO]]
31+
%MyCBuffer.cb_h.i.i = tail call target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @MyCBuffer.str)
32+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
33+
34+
%0 = tail call target("spirv.Image", float, 5, 2, 0, 0, 2, 1) @llvm.spv.resource.handlefromimplicitbinding.tspirv.Image_f32_5_2_0_0_2_1t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str)
35+
%1 = tail call i32 @llvm.spv.thread.id.i32(i32 0)
36+
%rem.i = and i32 %1, 3
37+
38+
; CHECK: %[[IDX_CONV:[0-9]+]] = OpUConvert {{.*}}
39+
%idxprom.i = zext nneg i32 %rem.i to i64
40+
41+
; CHECK: %[[PTR_ELEM:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[ACCESS_ARRAY]] %[[IDX_CONV]]
42+
%cbufferidx.i = getelementptr <{ %OrigType, target("spirv.Padding", 12) }>, ptr addrspace(12) @myArray, i64 %idxprom.i
43+
44+
; CHECK: %[[PTR_FIELD:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[PTR_ELEM]] %[[ZERO]] %[[ZERO]]
45+
; CHECK: %[[VAL_FLOAT:[0-9]+]] = OpLoad %[[FLOAT]] %[[PTR_FIELD]] Aligned 4
46+
%2 = load float, ptr addrspace(12) %cbufferidx.i, align 4
47+
48+
%vecinit4.i = insertelement <4 x float> <float poison, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00>, float %2, i64 0
49+
%3 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_f32_5_2_0_0_2_1t(target("spirv.Image", float, 5, 2, 0, 0, 2, 1) %0, i32 0)
50+
store <4 x float> %vecinit4.i, ptr addrspace(11) %3, align 16
51+
; CHECK: OpImageWrite {{%[0-9]+}} {{%[0-9]+}} {{%[0-9]+}}
52+
ret void
53+
}
54+
55+
declare i32 @llvm.spv.thread.id.i32(i32)
56+
57+
declare target("spirv.Image", float, 5, 2, 0, 0, 2, 1) @llvm.spv.resource.handlefromimplicitbinding.tspirv.Image_f32_5_2_0_0_2_1t(i32, i32, i32, i32, ptr)
58+
59+
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_f32_5_2_0_0_2_1t(target("spirv.Image", float, 5, 2, 0, 0, 2, 1), i32)
60+
61+
attributes #1 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
62+
63+
!hlsl.cbs = !{!0}
64+
65+
!0 = distinct !{ptr @MyCBuffer.cb, ptr addrspace(12) @myArray, null}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
; RUN: llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
3+
4+
; CHECK: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
5+
; CHECK: %[[VEC3:[0-9]+]] = OpTypeVector %[[FLOAT]] 3
6+
; CHECK: %[[I8:[0-9]+]] = OpTypeInt 8 0
7+
; CHECK: %[[STRUCT_PAD:[0-9]+]] = OpTypeStruct %[[VEC3]] %[[I8]]
8+
; CHECK: %[[UINT:[0-9]+]] = OpTypeInt 32 0
9+
; CHECK: %[[CONST_3:[0-9]+]] = OpConstant %[[UINT]] 3
10+
; CHECK: %[[ARRAY:[0-9]+]] = OpTypeArray %[[STRUCT_PAD]] %[[CONST_3]]
11+
; CHECK: %[[CBLAYOUT:[0-9]+]] = OpTypeStruct %[[ARRAY]]
12+
; CHECK: %[[WRAPPER:[0-9]+]] = OpTypeStruct %[[CBLAYOUT]]
13+
; CHECK: %[[PTR_WRAPPER:[0-9]+]] = OpTypePointer Uniform %[[WRAPPER]]
14+
; CHECK: %[[ZERO:[0-9]+]] = OpConstant %[[UINT]] 0
15+
; CHECK: %[[MYCBUFFER:[0-9]+]] = OpVariable %[[PTR_WRAPPER]] Uniform
16+
17+
%__cblayout_MyCBuffer = type <{ <{ [2 x <{ <3 x float>, target("spirv.Padding", 4) }>], <3 x float> }> }>
18+
19+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
20+
@myArray = external hidden local_unnamed_addr addrspace(12) global <{ [2 x <{ <3 x float>, target("spirv.Padding", 4) }>], <3 x float> }>, align 16
21+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
22+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
23+
24+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
25+
26+
define void @main() #1 {
27+
entry:
28+
; CHECK: %[[BUFFER_HANDLE:[0-9]+]] = OpCopyObject %[[PTR_WRAPPER]] %[[MYCBUFFER]]
29+
; CHECK: %[[ACCESS_ARRAY:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[BUFFER_HANDLE]] %[[ZERO]] %[[ZERO]]
30+
%MyCBuffer.cb_h.i.i = tail call target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @MyCBuffer.str)
31+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
32+
33+
%0 = tail call target("spirv.VulkanBuffer", [0 x <3 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v3f32_12_1t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
34+
%1 = tail call i32 @llvm.spv.thread.id.i32(i32 0)
35+
36+
; CHECK: %[[IDX:[0-9]+]] = OpUMod %[[UINT]] {{%[0-9]+}} %[[CONST_3]]
37+
%rem.i = urem i32 %1, 3
38+
39+
; CHECK: %[[IDX_CONV:[0-9]+]] = OpUConvert {{.*}} %[[IDX]]
40+
%idxprom.i = zext nneg i32 %rem.i to i64
41+
42+
; CHECK: %[[PTR_ELEM:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[ACCESS_ARRAY]] %[[IDX_CONV]]
43+
%cbufferidx.i = getelementptr <{ <3 x float>, target("spirv.Padding", 4) }>, ptr addrspace(12) @myArray, i64 %idxprom.i
44+
45+
; CHECK: %[[PTR_FIELD:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[PTR_ELEM]] {{.*}}
46+
; CHECK: %[[VAL_VEC3:[0-9]+]] = OpLoad %[[VEC3]] %[[PTR_FIELD]] Aligned 16
47+
%2 = load <3 x float>, ptr addrspace(12) %cbufferidx.i, align 16
48+
49+
%3 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v3f32_12_1t(target("spirv.VulkanBuffer", [0 x <3 x float>], 12, 1) %0, i32 %1)
50+
store <3 x float> %2, ptr addrspace(11) %3, align 16
51+
ret void
52+
}
53+
54+
declare i32 @llvm.spv.thread.id.i32(i32)
55+
56+
declare target("spirv.VulkanBuffer", [0 x <3 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v3f32_12_1t(i32, i32, i32, i32, ptr)
57+
58+
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v3f32_12_1t(target("spirv.VulkanBuffer", [0 x <3 x float>], 12, 1), i32)
59+
60+
attributes #1 = { "hlsl.numthreads"="8,1,1" "hlsl.shader"="compute" }
61+
62+
!hlsl.cbs = !{!0}
63+
64+
!0 = !{ptr @MyCBuffer.cb, ptr addrspace(12) @myArray}

0 commit comments

Comments
 (0)