Skip to content

Commit 6e983e3

Browse files
authored
[SPIRV] Support Peeled Array Layouts for HLSL CBuffers (#169078)
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 0c2701f commit 6e983e3

File tree

10 files changed

+289
-3
lines changed

10 files changed

+289
-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
@@ -920,6 +920,17 @@ SPIRVType *SPIRVGlobalRegistry::getOpTypeStruct(
920920
const StructType *Ty, MachineIRBuilder &MIRBuilder,
921921
SPIRV::AccessQualifier::AccessQualifier AccQual,
922922
StructOffsetDecorator Decorator, bool EmitIR) {
923+
Type *OriginalElementType = nullptr;
924+
uint64_t TotalSize = 0;
925+
if (matchPeeledArrayPattern(Ty, OriginalElementType, TotalSize)) {
926+
SPIRVType *ElementSPIRVType = findSPIRVType(
927+
OriginalElementType, MIRBuilder, AccQual,
928+
/* ExplicitLayoutRequired= */ Decorator != nullptr, EmitIR);
929+
return getOpTypeArray(TotalSize, ElementSPIRVType, MIRBuilder,
930+
/*ExplicitLayoutRequired=*/Decorator != nullptr,
931+
EmitIR);
932+
}
933+
923934
const SPIRVSubtarget &ST =
924935
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
925936
SmallVector<Register, 4> FieldTypes;
@@ -1444,6 +1455,18 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateVulkanBufferType(
14441455
return R;
14451456
}
14461457

1458+
SPIRVType *
1459+
SPIRVGlobalRegistry::getOrCreatePaddingType(MachineIRBuilder &MIRBuilder) {
1460+
auto Key = SPIRV::irhandle_padding();
1461+
if (const MachineInstr *MI = findMI(Key, &MIRBuilder.getMF()))
1462+
return MI;
1463+
auto *T = Type::getInt8Ty(MIRBuilder.getContext());
1464+
SPIRVType *R = getOrCreateSPIRVIntegerType(8, MIRBuilder);
1465+
finishCreatingSPIRVType(T, R);
1466+
add(Key, R);
1467+
return R;
1468+
}
1469+
14471470
SPIRVType *SPIRVGlobalRegistry::getOrCreateLayoutType(
14481471
MachineIRBuilder &MIRBuilder, const TargetExtType *T, bool EmitIr) {
14491472
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: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,75 @@ 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->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+
auto *Padding_in_struct =
1067+
dyn_cast<TargetExtType>(ArrayElementType->getStructElementType(1));
1068+
if (!Padding_in_struct || Padding_in_struct->getName() != "spirv.Padding")
1069+
return false;
1070+
1071+
const uint64_t ArraySize = FirstElement->getArrayNumElements();
1072+
TotalSize = ArraySize + 1;
1073+
OriginalElementType = ArrayElementType;
1074+
return true;
1075+
}
1076+
1077+
Type *reconstitutePeeledArrayType(Type *Ty) {
1078+
if (!Ty->isStructTy())
1079+
return Ty;
1080+
1081+
auto *STy = cast<StructType>(Ty);
1082+
Type *OriginalElementType = nullptr;
1083+
uint64_t TotalSize = 0;
1084+
if (matchPeeledArrayPattern(STy, OriginalElementType, TotalSize)) {
1085+
Type *ResultTy = ArrayType::get(
1086+
reconstitutePeeledArrayType(OriginalElementType), TotalSize);
1087+
return ResultTy;
1088+
}
1089+
1090+
SmallVector<Type *, 4> NewElementTypes;
1091+
bool Changed = false;
1092+
for (Type *ElementTy : STy->elements()) {
1093+
Type *NewElementTy = reconstitutePeeledArrayType(ElementTy);
1094+
if (NewElementTy != ElementTy)
1095+
Changed = true;
1096+
NewElementTypes.push_back(NewElementTy);
1097+
}
1098+
1099+
if (!Changed)
1100+
return Ty;
1101+
1102+
Type *ResultTy;
1103+
if (STy->isLiteral())
1104+
ResultTy =
1105+
StructType::get(STy->getContext(), NewElementTypes, STy->isPacked());
1106+
else {
1107+
auto *NewTy = StructType::create(STy->getContext(), STy->getName());
1108+
NewTy->setBody(NewElementTypes, STy->isPacked());
1109+
ResultTy = NewTy;
1110+
}
1111+
return ResultTy;
1112+
}
1113+
10451114
std::optional<SPIRV::LinkageType::LinkageType>
10461115
getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) {
10471116
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: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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-DAG: OpDecorate %[[ARRAY:[0-9]+]] ArrayStride 16
5+
; CHECK-DAG: OpMemberDecorate %[[CBLAYOUT:[0-9]+]] 0 Offset 0
6+
; CHECK-DAG: OpMemberDecorate %[[CBLAYOUT]] 1 Offset 52
7+
; CHECK-DAG: OpMemberDecorate %[[WRAPPER:[0-9]+]] 0 Offset 0
8+
; CHECK-DAG: OpDecorate %[[WRAPPER]] Block
9+
; CHECK-DAG: OpMemberDecorate %[[STRUCT:[0-9]+]] 0 Offset 0
10+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_PAD:[0-9]+]] 0 Offset 0
11+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_PAD]] 1 Offset 4
12+
13+
; CHECK-DAG: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
14+
; CHECK-DAG: %[[STRUCT]] = OpTypeStruct %[[FLOAT]]
15+
; CHECK-DAG: %[[I8:[0-9]+]] = OpTypeInt 8 0
16+
; CHECK-DAG: %[[STRUCT_PAD]] = OpTypeStruct %[[STRUCT]] %[[I8]]
17+
; CHECK-DAG: %[[UINT:[0-9]+]] = OpTypeInt 32 0
18+
; CHECK-DAG: %[[CONST_4:[0-9]+]] = OpConstant %[[UINT]] 4
19+
; CHECK-DAG: %[[ARRAY]] = OpTypeArray %[[STRUCT_PAD]] %[[CONST_4]]
20+
; CHECK-DAG: %[[CBLAYOUT]] = OpTypeStruct %[[ARRAY]] %[[FLOAT]]
21+
; CHECK-DAG: %[[WRAPPER]] = OpTypeStruct %[[CBLAYOUT]]
22+
; CHECK-DAG: %[[PTR_WRAPPER:[0-9]+]] = OpTypePointer Uniform %[[WRAPPER]]
23+
; CHECK-DAG: %[[ZERO:[0-9]+]] = OpConstant %[[UINT]] 0
24+
; CHECK-DAG: %[[MYCBUFFER:[0-9]+]] = OpVariable %[[PTR_WRAPPER]] Uniform
25+
26+
; CHECK-DAG: %[[I64:[0-9]+]] = OpTypeInt 64 0
27+
; CHECK-DAG: %[[STRUCT2:[0-9]+]] = OpTypeStruct %[[I64]] %[[UINT]]
28+
; CHECK-DAG: %[[CONST_3:[0-9]+]] = OpConstant %[[UINT]] 3
29+
; CHECK-DAG: %[[ARRAY2:[0-9]+]] = OpTypeArray %[[STRUCT2]] %[[CONST_3]]
30+
; CHECK-DAG: %[[CBLAYOUT2:[0-9]+]] = OpTypeStruct %[[ARRAY2]] %[[I64]]
31+
; CHECK-DAG: %[[PTR_PRIVATE:[0-9]+]] = OpTypePointer Private %[[CBLAYOUT2]]
32+
; CHECK-DAG: %[[MYPRIVATEVAR:[0-9]+]] = OpVariable %[[PTR_PRIVATE]] Private
33+
34+
%__cblayout_MyCBuffer = type <{ <{ [3 x <{ %OrigType, target("spirv.Padding", 12) }>], %OrigType }>, float }>
35+
%OrigType = type <{ float }>
36+
37+
%__cblayout_MyCBuffer2 = type <{ [ 3 x <{ i64, i32 }> ], i64 }>
38+
39+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
40+
@myPrivateVar = internal addrspace(10) global %__cblayout_MyCBuffer2 poison
41+
42+
@myArray = external hidden local_unnamed_addr addrspace(12) global <{ [3 x <{ %OrigType, target("spirv.Padding", 12) }>], %OrigType }>, align 1
43+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
44+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
45+
46+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
47+
48+
define void @main() #1 {
49+
entry:
50+
; CHECK: %[[BUFFER_HANDLE:[0-9]+]] = OpCopyObject %[[PTR_WRAPPER]] %[[MYCBUFFER]]
51+
; CHECK: %[[ACCESS_ARRAY:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[BUFFER_HANDLE]] %[[ZERO]] %[[ZERO]]
52+
%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)
53+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
54+
55+
%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)
56+
%1 = tail call i32 @llvm.spv.thread.id.i32(i32 0)
57+
%rem.i = and i32 %1, 3
58+
59+
; CHECK: %[[IDX_CONV:[0-9]+]] = OpUConvert {{.*}}
60+
%idxprom.i = zext nneg i32 %rem.i to i64
61+
62+
; CHECK: %[[PTR_ELEM:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[ACCESS_ARRAY]] %[[IDX_CONV]]
63+
%cbufferidx.i = getelementptr <{ %OrigType, target("spirv.Padding", 12) }>, ptr addrspace(12) @myArray, i64 %idxprom.i
64+
65+
; CHECK: %[[PTR_FIELD:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[PTR_ELEM]] %[[ZERO]] %[[ZERO]]
66+
; CHECK: %[[VAL_FLOAT:[0-9]+]] = OpLoad %[[FLOAT]] %[[PTR_FIELD]] Aligned 4
67+
%2 = load float, ptr addrspace(12) %cbufferidx.i, align 4
68+
69+
%val = load i64, ptr addrspace(10) getelementptr (%__cblayout_MyCBuffer2, ptr addrspace(10) @myPrivateVar, i32 0, i32 1), align 8
70+
%val.float = sitofp i64 %val to float
71+
72+
%vecinit4.i = insertelement <4 x float> <float poison, float 0.000000e+00, float 0.000000e+00, float 0.000000e+00>, float %2, i64 0
73+
%vecinit4.i.2 = insertelement <4 x float> %vecinit4.i, float %val.float, i64 1
74+
%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)
75+
store <4 x float> %vecinit4.i.2, ptr addrspace(11) %3, align 16
76+
; CHECK: OpImageWrite {{%[0-9]+}} {{%[0-9]+}} {{%[0-9]+}}
77+
ret void
78+
}
79+
80+
declare i32 @llvm.spv.thread.id.i32(i32)
81+
82+
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)
83+
84+
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)
85+
86+
attributes #1 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
87+
88+
!hlsl.cbs = !{!0}
89+
90+
!0 = distinct !{ptr @MyCBuffer.cb, ptr addrspace(12) @myArray, null}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
5+
; CHECK-DAG: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
6+
; CHECK-DAG: %[[VEC3:[0-9]+]] = OpTypeVector %[[FLOAT]] 3
7+
; CHECK-DAG: %[[I8:[0-9]+]] = OpTypeInt 8 0
8+
; CHECK-DAG: %[[STRUCT_PAD:[0-9]+]] = OpTypeStruct %[[VEC3]] %[[I8]]
9+
; CHECK-DAG: %[[UINT:[0-9]+]] = OpTypeInt 32 0
10+
; CHECK-DAG: %[[CONST_3:[0-9]+]] = OpConstant %[[UINT]] 3
11+
; CHECK-DAG: %[[ARRAY:[0-9]+]] = OpTypeArray %[[STRUCT_PAD]] %[[CONST_3]]
12+
; CHECK-DAG: %[[CBLAYOUT:[0-9]+]] = OpTypeStruct %[[ARRAY]]
13+
; CHECK-DAG: OpMemberDecorate %[[CBLAYOUT]] 0 Offset 0
14+
; CHECK-DAG: %[[WRAPPER:[0-9]+]] = OpTypeStruct %[[CBLAYOUT]]
15+
; CHECK-DAG: %[[PTR_WRAPPER:[0-9]+]] = OpTypePointer Uniform %[[WRAPPER]]
16+
; CHECK-DAG: %[[ZERO:[0-9]+]] = OpConstant %[[UINT]] 0
17+
; CHECK-DAG: %[[MYCBUFFER:[0-9]+]] = OpVariable %[[PTR_WRAPPER]] Uniform
18+
19+
20+
; TODO(168401): This array stride and offset of element 1 are incorrect. This
21+
; is an issue with how 3 element vectors are handled.
22+
; CHECK-DAG: OpDecorate %[[ARRAY]] ArrayStride 20
23+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_PAD]] 0 Offset 0
24+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_PAD]] 1 Offset 16
25+
; CHECK-DAG: OpMemberDecorate %[[WRAPPER]] 0 Offset 0
26+
; CHECK-DAG: OpDecorate %[[WRAPPER]] Block
27+
%__cblayout_MyCBuffer = type <{ <{ [2 x <{ <3 x float>, target("spirv.Padding", 4) }>], <3 x float> }> }>
28+
29+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
30+
@myArray = external hidden local_unnamed_addr addrspace(12) global <{ [2 x <{ <3 x float>, target("spirv.Padding", 4) }>], <3 x float> }>, align 16
31+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
32+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
33+
34+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
35+
36+
define void @main() #1 {
37+
entry:
38+
; CHECK: %[[BUFFER_HANDLE:[0-9]+]] = OpCopyObject %[[PTR_WRAPPER]] %[[MYCBUFFER]]
39+
; CHECK: %[[ACCESS_ARRAY:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[BUFFER_HANDLE]] %[[ZERO]] %[[ZERO]]
40+
%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)
41+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
42+
43+
%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)
44+
%1 = tail call i32 @llvm.spv.thread.id.i32(i32 0)
45+
46+
; CHECK: %[[IDX:[0-9]+]] = OpUMod %[[UINT]] {{%[0-9]+}} %[[CONST_3]]
47+
%rem.i = urem i32 %1, 3
48+
49+
; CHECK: %[[IDX_CONV:[0-9]+]] = OpUConvert {{.*}} %[[IDX]]
50+
%idxprom.i = zext nneg i32 %rem.i to i64
51+
52+
; CHECK: %[[PTR_ELEM:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[ACCESS_ARRAY]] %[[IDX_CONV]]
53+
%cbufferidx.i = getelementptr <{ <3 x float>, target("spirv.Padding", 4) }>, ptr addrspace(12) @myArray, i64 %idxprom.i
54+
55+
; CHECK: %[[PTR_FIELD:[0-9]+]] = OpAccessChain {{%[0-9]+}} %[[PTR_ELEM]] {{.*}}
56+
; CHECK: %[[VAL_VEC3:[0-9]+]] = OpLoad %[[VEC3]] %[[PTR_FIELD]] Aligned 16
57+
%2 = load <3 x float>, ptr addrspace(12) %cbufferidx.i, align 16
58+
59+
%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)
60+
store <3 x float> %2, ptr addrspace(11) %3, align 16
61+
ret void
62+
}
63+
64+
declare i32 @llvm.spv.thread.id.i32(i32)
65+
66+
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)
67+
68+
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)
69+
70+
attributes #1 = { "hlsl.numthreads"="8,1,1" "hlsl.shader"="compute" }
71+
72+
!hlsl.cbs = !{!0}
73+
74+
!0 = !{ptr @MyCBuffer.cb, ptr addrspace(12) @myArray}

0 commit comments

Comments
 (0)