Skip to content

Commit 04bddda

Browse files
authored
[SPIRV] Improve Logical SPIR-V Pointer Access and GEP Legalization (llvm#169076)
This commit improves the handling of GetElementPtr (GEP) instructions for Logical SPIR-V. It includes: - Rewriting of GEPs that are not allowed in Logical SPIR-V (specifically, handling non-zero first indices by rebuilding access chains or adjusting types). - Better deduction of element types for pointer casting. - Updates to instruction selection to ensure GEPs are correctly lowered to OpAccessChain or OpInBoundsAccessChain only when valid (e.g. first index 0). - Support for standard HLSL cbuffer layouts in tests.
1 parent c0a7b15 commit 04bddda

File tree

6 files changed

+379
-38
lines changed

6 files changed

+379
-38
lines changed

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,16 +1569,57 @@ Instruction *SPIRVEmitIntrinsics::visitSwitchInst(SwitchInst &I) {
15691569
return BrI;
15701570
}
15711571

1572-
Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
1573-
if (I.getSourceElementType() == IntegerType::getInt8Ty(CurrF->getContext()) &&
1574-
TM->getSubtargetImpl()->isLogicalSPIRV()) {
1575-
Instruction *Result = buildLogicalAccessChainFromGEP(I);
1576-
if (Result)
1577-
return Result;
1572+
static bool isFirstIndexZero(const GetElementPtrInst *GEP) {
1573+
if (GEP->getNumIndices() == 0)
1574+
return false;
1575+
if (const auto *CI = dyn_cast<ConstantInt>(GEP->getOperand(1))) {
1576+
return CI->getZExtValue() == 0;
15781577
}
1578+
return false;
1579+
}
15791580

1581+
Instruction *SPIRVEmitIntrinsics::visitGetElementPtrInst(GetElementPtrInst &I) {
15801582
IRBuilder<> B(I.getParent());
15811583
B.SetInsertPoint(&I);
1584+
1585+
if (TM->getSubtargetImpl()->isLogicalSPIRV() && !isFirstIndexZero(&I)) {
1586+
// Logical SPIR-V cannot use the OpPtrAccessChain instruction. If the first
1587+
// index of the GEP is not 0, then we need to try to adjust it.
1588+
//
1589+
// If the GEP is doing byte addressing, try to rebuild the full access chain
1590+
// from the type of the pointer.
1591+
if (I.getSourceElementType() ==
1592+
IntegerType::getInt8Ty(CurrF->getContext())) {
1593+
return buildLogicalAccessChainFromGEP(I);
1594+
}
1595+
1596+
// Look for the array-to-pointer decay. If this is the pattern
1597+
// we can adjust the types, and prepend a 0 to the indices.
1598+
Value *PtrOp = I.getPointerOperand();
1599+
Type *SrcElemTy = I.getSourceElementType();
1600+
Type *DeducedPointeeTy = deduceElementType(PtrOp, true);
1601+
1602+
if (auto *ArrTy = dyn_cast<ArrayType>(DeducedPointeeTy)) {
1603+
if (ArrTy->getElementType() == SrcElemTy) {
1604+
SmallVector<Value *> NewIndices;
1605+
Type *FirstIdxType = I.getOperand(1)->getType();
1606+
NewIndices.push_back(ConstantInt::get(FirstIdxType, 0));
1607+
for (Value *Idx : I.indices())
1608+
NewIndices.push_back(Idx);
1609+
1610+
SmallVector<Type *, 2> Types = {I.getType(), I.getPointerOperandType()};
1611+
SmallVector<Value *, 4> Args;
1612+
Args.push_back(B.getInt1(I.isInBounds()));
1613+
Args.push_back(I.getPointerOperand());
1614+
Args.append(NewIndices.begin(), NewIndices.end());
1615+
1616+
auto *NewI = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
1617+
replaceAllUsesWithAndErase(B, &I, NewI);
1618+
return NewI;
1619+
}
1620+
}
1621+
}
1622+
15821623
SmallVector<Type *, 2> Types = {I.getType(), I.getOperand(0)->getType()};
15831624
SmallVector<Value *, 4> Args;
15841625
Args.push_back(B.getInt1(I.isInBounds()));
@@ -1772,16 +1813,12 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
17721813
Value *Pointer = GEPI->getPointerOperand();
17731814
Type *OpTy = nullptr;
17741815

1775-
// Knowing the accessed type is mandatory for logical SPIR-V. Sadly,
1776-
// the GEP source element type should not be used for this purpose, and
1777-
// the alternative type-scavenging method is not working.
1778-
// Physical SPIR-V can work around this, but not logical, hence still
1779-
// try to rely on the broken type scavenging for logical.
1780-
bool IsRewrittenGEP =
1781-
GEPI->getSourceElementType() == IntegerType::getInt8Ty(I->getContext());
1782-
if (IsRewrittenGEP && TM->getSubtargetImpl()->isLogicalSPIRV()) {
1783-
Value *Src = getPointerRoot(Pointer);
1784-
OpTy = GR->findDeducedElementType(Src);
1816+
// Logical SPIR-V is not allowed to use Op*PtrAccessChain instructions. If
1817+
// the first index is 0, then we can trivially lower to OpAccessChain. If
1818+
// not we need to try to rewrite the GEP. We avoid adding a pointer cast at
1819+
// this time, and will rewrite the GEP when visiting it.
1820+
if (TM->getSubtargetImpl()->isLogicalSPIRV() && !isFirstIndexZero(GEPI)) {
1821+
return;
17851822
}
17861823

17871824
// In all cases, fall back to the GEP type if type scavenging failed.

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,7 @@ static bool isConstReg(MachineRegisterInfo *MRI, MachineInstr *OpDef,
467467
switch (Opcode) {
468468
case TargetOpcode::G_CONSTANT:
469469
case TargetOpcode::G_FCONSTANT:
470+
case TargetOpcode::G_IMPLICIT_DEF:
470471
return true;
471472
case TargetOpcode::G_INTRINSIC:
472473
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
@@ -3088,6 +3089,11 @@ bool SPIRVInstructionSelector::selectGEP(Register ResVReg,
30883089
.addUse(GR.getSPIRVTypeID(ResType))
30893090
// Object to get a pointer to.
30903091
.addUse(I.getOperand(3).getReg());
3092+
assert(Opcode == SPIRV::OpPtrAccessChain ||
3093+
Opcode == SPIRV::OpInBoundsPtrAccessChain ||
3094+
(getImm(I.getOperand(4), MRI) && foldImm(I.getOperand(4), MRI) == 0) &&
3095+
"Cannot translate GEP to OpAccessChain. First index must be 0.");
3096+
30913097
// Adding indices.
30923098
const unsigned StartingIndex =
30933099
(Opcode == SPIRV::OpAccessChain || Opcode == SPIRV::OpInBoundsAccessChain)

llvm/lib/Target/SPIRV/SPIRVLegalizePointerCast.cpp

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,13 @@ class SPIRVLegalizePointerCast : public FunctionPass {
104104
Value *loadFirstValueFromAggregate(IRBuilder<> &B, Type *ElementType,
105105
Value *Source, LoadInst *BadLoad) {
106106
SmallVector<Type *, 2> Types = {BadLoad->getPointerOperandType(),
107-
BadLoad->getPointerOperandType()};
108-
SmallVector<Value *, 3> Args{/* isInBounds= */ B.getInt1(false), Source,
109-
B.getInt32(0), B.getInt32(0)};
107+
Source->getType()};
108+
SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(false), Source};
109+
110+
Type *AggregateType = GR->findDeducedElementType(Source);
111+
assert(AggregateType && "Could not deduce aggregate type");
112+
buildGEPIndexChain(B, ElementType, AggregateType, Args);
113+
110114
auto *GEP = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
111115
GR->buildAssignPtr(B, ElementType, GEP);
112116

@@ -201,34 +205,20 @@ class SPIRVLegalizePointerCast : public FunctionPass {
201205

202206
auto *SAT = dyn_cast<ArrayType>(FromTy);
203207
auto *SVT = dyn_cast<FixedVectorType>(FromTy);
204-
auto *SST = dyn_cast<StructType>(FromTy);
205208
auto *DVT = dyn_cast<FixedVectorType>(ToTy);
206209

207210
B.SetInsertPoint(LI);
208211

209-
// Destination is the element type of Source, and source is an array ->
210-
// Loading 1st element.
212+
// Destination is the element type of some member of FromTy. For example,
213+
// loading the 1st element of an array:
211214
// - float a = array[0];
212-
if (SAT && SAT->getElementType() == ToTy)
213-
Output = loadFirstValueFromAggregate(B, SAT->getElementType(),
214-
OriginalOperand, LI);
215-
// Destination is the element type of Source, and source is a vector ->
216-
// Vector to scalar.
217-
// - float a = vector.x;
218-
else if (!DVT && SVT && SVT->getElementType() == ToTy) {
219-
Output = loadFirstValueFromAggregate(B, SVT->getElementType(),
220-
OriginalOperand, LI);
221-
}
215+
if (isTypeFirstElementAggregate(ToTy, FromTy))
216+
Output = loadFirstValueFromAggregate(B, ToTy, OriginalOperand, LI);
222217
// Destination is a smaller vector than source or different vector type.
223218
// - float3 v3 = vector4;
224219
// - float4 v2 = int4;
225220
else if (SVT && DVT)
226221
Output = loadVectorFromVector(B, SVT, DVT, OriginalOperand);
227-
// Destination is the scalar type stored at the start of an aggregate.
228-
// - struct S { float m };
229-
// - float v = s.m;
230-
else if (SST && SST->getTypeAtIndex(0u) == ToTy)
231-
Output = loadFirstValueFromAggregate(B, ToTy, OriginalOperand, LI);
232222
else if (SAT && DVT && SAT->getElementType() == DVT->getElementType())
233223
Output = loadVectorFromArray(B, DVT, OriginalOperand);
234224
else
@@ -334,7 +324,7 @@ class SPIRVLegalizePointerCast : public FunctionPass {
334324
Value *storeToFirstValueAggregate(IRBuilder<> &B, Value *Src, Value *Dst,
335325
Type *DstPointeeType, Align Alignment) {
336326
SmallVector<Type *, 2> Types = {Dst->getType(), Dst->getType()};
337-
SmallVector<Value *, 3> Args{/* isInBounds= */ B.getInt1(true), Dst};
327+
SmallVector<Value *, 8> Args{/* isInBounds= */ B.getInt1(true), Dst};
338328
buildGEPIndexChain(B, Src->getType(), DstPointeeType, Args);
339329
auto *GEP = B.CreateIntrinsic(Intrinsic::spv_gep, {Types}, {Args});
340330
GR->buildAssignPtr(B, Src->getType(), GEP);
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
5+
; CHECK-DAG: %[[VEC4:[0-9]+]] = OpTypeVector %[[FLOAT]] 4
6+
; CHECK-DAG: %[[PTR_VEC4:[0-9]+]] = OpTypePointer Uniform %[[VEC4]]
7+
; CHECK-DAG: %[[INT:[0-9]+]] = OpTypeInt 32 0
8+
; CHECK-DAG: %[[PTR_INT:[0-9]+]] = OpTypePointer Uniform %[[INT]]
9+
; CHECK-DAG: %[[INT64:[0-9]+]] = OpTypeInt 64 0
10+
; CHECK-DAG: %[[CONST_4:[0-9]+]] = OpConstant %[[INT]] 4{{$}}
11+
12+
; CHECK-DAG: %[[ARRAY:[0-9]+]] = OpTypeArray %[[VEC4]] %[[CONST_4]]
13+
; CHECK-DAG: %[[PTR_ARRAY:[0-9]+]] = OpTypePointer Uniform %[[ARRAY]]
14+
15+
; CHECK-DAG: %[[STRUCT_INNER:[0-9]+]] = OpTypeStruct %[[ARRAY]] %[[INT]]
16+
; CHECK-DAG: %[[STRUCT_CBUFFER:[0-9]+]] = OpTypeStruct %[[STRUCT_INNER]]
17+
; CHECK-DAG: %[[PTR_CBUFFER:[0-9]+]] = OpTypePointer Uniform %[[STRUCT_CBUFFER]]
18+
19+
; CHECK-DAG: OpDecorate %[[ARRAY]] ArrayStride 16
20+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_INNER]] 0 Offset 0
21+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_INNER]] 1 Offset 64
22+
; CHECK-DAG: OpMemberDecorate %[[STRUCT_CBUFFER]] 0 Offset 0
23+
; CHECK-DAG: OpDecorate %[[STRUCT_CBUFFER]] Block
24+
25+
; CHECK-DAG: %[[ZERO:[0-9]+]] = OpConstant %[[INT]] 0{{$}}
26+
; CHECK-DAG: %[[ONE:[0-9]+]] = OpConstant %[[INT]] 1{{$}}
27+
28+
; CHECK: %[[CBUFFER:[0-9]+]] = OpVariable %[[PTR_CBUFFER]] Uniform
29+
30+
%__cblayout_MyCBuffer = type <{ [4 x <4 x float>], i32 }>
31+
32+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
33+
@colors = external hidden local_unnamed_addr addrspace(12) global [4 x <4 x float>], align 16
34+
@index = external hidden local_unnamed_addr addrspace(12) global i32, align 4
35+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
36+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
37+
38+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
39+
40+
define void @main() #1 {
41+
entry:
42+
; Get pointers to the two elements of the cbuffer
43+
; CHECK: %[[COPY:[0-9]+]] = OpCopyObject %[[PTR_CBUFFER]] %[[CBUFFER]]
44+
; CHECK: %[[PTR_ARRAY_ACCESS:[0-9]+]] = OpAccessChain %[[PTR_ARRAY]] %[[COPY]] %[[ZERO]] %[[ZERO]]
45+
; CHECK: %[[PTR_INT_ACCESS:[0-9]+]] = OpAccessChain %[[PTR_INT]] %[[COPY]] %[[ZERO]] %[[ONE]]
46+
%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)
47+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
48+
49+
%0 = tail call target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4f32_12_1t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
50+
51+
; CHECK: %[[VAL_INT:[0-9]+]] = OpLoad %[[INT]] %[[PTR_INT_ACCESS]] Aligned 4
52+
%1 = load i32, ptr addrspace(12) @index, align 4
53+
54+
; CHECK: %[[VAL_INT64:[0-9]+]] = OpSConvert %[[INT64]] %[[VAL_INT]]
55+
%idxprom.i = sext i32 %1 to i64
56+
57+
; CHECK: %[[PTR_ELEM:[0-9]+]] = OpInBoundsAccessChain %[[PTR_VEC4]] %[[PTR_ARRAY_ACCESS]] %[[VAL_INT64]]
58+
%arrayidx.i = getelementptr inbounds <4 x float>, ptr addrspace(12) @colors, i64 %idxprom.i
59+
60+
; CHECK: %[[VAL_ELEM:[0-9]+]] = OpLoad %[[VEC4]] %[[PTR_ELEM]] Aligned 16
61+
%2 = load <4 x float>, ptr addrspace(12) %arrayidx.i, align 16
62+
63+
; CHECK: OpStore {{%[0-9]+}} %[[VAL_ELEM]] Aligned 16
64+
%3 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4f32_12_1t(target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) %0, i32 0)
65+
store <4 x float> %2, ptr addrspace(11) %3, align 16
66+
ret void
67+
}
68+
69+
declare target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4f32_12_1t(i32, i32, i32, i32, ptr)
70+
71+
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4f32_12_1t(target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1), i32)
72+
73+
attributes #1 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
74+
75+
!hlsl.cbs = !{!0}
76+
77+
!0 = !{ptr @MyCBuffer.cb, ptr addrspace(12) @colors, ptr addrspace(12) @index}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
5+
; CHECK-DAG: %[[VEC4:[0-9]+]] = OpTypeVector %[[FLOAT]] 4
6+
; CHECK-DAG: %[[PTR_FLOAT:[0-9]+]] = OpTypePointer Uniform %[[FLOAT]]
7+
; CHECK-DAG: %[[PTR_VEC4:[0-9]+]] = OpTypePointer Uniform %[[VEC4]]
8+
; CHECK-DAG: %[[STRUCT:[0-9]+]] = OpTypeStruct %[[VEC4]] %[[FLOAT]]
9+
; CHECK-DAG: %[[CBUFFER_TYPE:[0-9]+]] = OpTypeStruct %[[STRUCT]]
10+
; CHECK-DAG: %[[PTR_CBUFFER:[0-9]+]] = OpTypePointer Uniform %[[CBUFFER_TYPE]]
11+
; CHECK-DAG: %[[INT:[0-9]+]] = OpTypeInt 32 0
12+
; CHECK-DAG: %[[ZERO:[0-9]+]] = OpConstant %[[INT]] 0{{$}}
13+
; CHECK-DAG: %[[ONE:[0-9]+]] = OpConstant %[[INT]] 1{{$}}
14+
15+
; CHECK-DAG: OpMemberDecorate %[[STRUCT]] 0 Offset 0
16+
; CHECK-DAG: OpMemberDecorate %[[STRUCT]] 1 Offset 16
17+
; CHECK-DAG: OpMemberDecorate %[[CBUFFER_TYPE]] 0 Offset 0
18+
; CHECK-DAG: OpDecorate %[[CBUFFER_TYPE]] Block
19+
20+
; CHECK-DAG: %[[CBUFFER:[0-9]+]] = OpVariable %[[PTR_CBUFFER]] Uniform
21+
22+
%__cblayout_MyCBuffer = type <{ <4 x float>, float }>
23+
24+
@MyCBuffer.cb = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) poison
25+
@color = external hidden local_unnamed_addr addrspace(12) global <4 x float>, align 16
26+
@factor = external hidden local_unnamed_addr addrspace(12) global float, align 4
27+
@MyCBuffer.str = private unnamed_addr constant [10 x i8] c"MyCBuffer\00", align 1
28+
@.str = private unnamed_addr constant [7 x i8] c"output\00", align 1
29+
30+
declare target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_s___cblayout_MyCBuffers_2_0t(i32, i32, i32, i32, ptr)
31+
32+
define void @main() #1 {
33+
entry:
34+
; CHECK: %[[COPY:[0-9]+]] = OpCopyObject %[[PTR_CBUFFER]] %[[CBUFFER]]
35+
; CHECK: %[[PTR_VEC4_ACCESS:[0-9]+]] = OpAccessChain %[[PTR_VEC4]] %[[COPY]] %[[ZERO]] %[[ZERO]]
36+
; CHECK: %[[PTR_FLOAT_ACCESS:[0-9]+]] = OpAccessChain %[[PTR_FLOAT]] %[[COPY]] %[[ZERO]] %[[ONE]]
37+
%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)
38+
store target("spirv.VulkanBuffer", %__cblayout_MyCBuffer, 2, 0) %MyCBuffer.cb_h.i.i, ptr @MyCBuffer.cb, align 8
39+
40+
%0 = tail call target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4f32_12_1t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
41+
%1 = tail call i32 @llvm.spv.thread.id.i32(i32 0)
42+
%2 = tail call i32 @llvm.spv.thread.id.i32(i32 1)
43+
%conv.i = uitofp i32 %1 to float
44+
%conv2.i = uitofp i32 %2 to float
45+
%3 = insertelement <4 x float> <float poison, float poison, float 0.000000e+00, float 1.000000e+00>, float %conv.i, i64 0
46+
%vecinit5.i = insertelement <4 x float> %3, float %conv2.i, i64 1
47+
48+
; CHECK: %[[VAL_VEC4:[0-9]+]] = OpLoad %[[VEC4]] %[[PTR_VEC4_ACCESS]] Aligned 16
49+
%4 = load <4 x float>, ptr addrspace(12) @color, align 16
50+
%mul.i = fmul reassoc nnan ninf nsz arcp afn <4 x float> %vecinit5.i, %4
51+
52+
; CHECK: %[[VAL_FLOAT:[0-9]+]] = OpLoad %[[FLOAT]] %[[PTR_FLOAT_ACCESS]] Aligned 4
53+
%5 = load float, ptr addrspace(12) @factor, align 4
54+
55+
%splat.splatinsert.i = insertelement <4 x float> poison, float %5, i64 0
56+
%splat.splat.i = shufflevector <4 x float> %splat.splatinsert.i, <4 x float> poison, <4 x i32> zeroinitializer
57+
%mul6.i = fmul reassoc nnan ninf nsz arcp afn <4 x float> %mul.i, %splat.splat.i
58+
%6 = tail call noundef align 16 dereferenceable(16) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4f32_12_1t(target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) %0, i32 0)
59+
store <4 x float> %mul6.i, ptr addrspace(11) %6, align 16
60+
ret void
61+
}
62+
63+
declare i32 @llvm.spv.thread.id.i32(i32)
64+
65+
declare target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0v4f32_12_1t(i32, i32, i32, i32, ptr)
66+
67+
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0v4f32_12_1t(target("spirv.VulkanBuffer", [0 x <4 x float>], 12, 1), i32)
68+
69+
attributes #1 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
70+
71+
!hlsl.cbs = !{!0}
72+
73+
!0 = !{ptr @MyCBuffer.cb, ptr addrspace(12) @color, ptr addrspace(12) @factor}

0 commit comments

Comments
 (0)