Skip to content

Commit 8d038bc

Browse files
committed
[SPIR-V] Use OpImageFetch instruction when loading from read-only buffer resource.
1 parent 3260a66 commit 8d038bc

File tree

2 files changed

+64
-21
lines changed

2 files changed

+64
-21
lines changed

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
352352
SPIRVType *widenTypeToVec4(const SPIRVType *Type, MachineInstr &I) const;
353353
bool extractSubvector(Register &ResVReg, const SPIRVType *ResType,
354354
Register &ReadReg, MachineInstr &InsertionPoint) const;
355-
bool generateImageRead(Register &ResVReg, const SPIRVType *ResType,
356-
Register ImageReg, Register IdxReg, DebugLoc Loc,
357-
MachineInstr &Pos) const;
355+
bool generateImageReadOrFetch(Register &ResVReg, const SPIRVType *ResType,
356+
Register ImageReg, Register IdxReg,
357+
DebugLoc Loc, MachineInstr &Pos) const;
358358
bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const;
359359
bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
360360
Register ResVReg, const SPIRVType *ResType,
@@ -1317,8 +1317,8 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
13171317
}
13181318

13191319
Register IdxReg = IntPtrDef->getOperand(3).getReg();
1320-
return generateImageRead(ResVReg, ResType, NewHandleReg, IdxReg,
1321-
I.getDebugLoc(), I);
1320+
return generateImageReadOrFetch(ResVReg, ResType, NewHandleReg, IdxReg,
1321+
I.getDebugLoc(), I);
13221322
}
13231323
}
13241324

@@ -3633,27 +3633,32 @@ bool SPIRVInstructionSelector::selectReadImageIntrinsic(
36333633
DebugLoc Loc = I.getDebugLoc();
36343634
MachineInstr &Pos = I;
36353635

3636-
return generateImageRead(ResVReg, ResType, NewImageReg, IdxReg, Loc, Pos);
3636+
return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
3637+
Pos);
36373638
}
36383639

3639-
bool SPIRVInstructionSelector::generateImageRead(Register &ResVReg,
3640-
const SPIRVType *ResType,
3641-
Register ImageReg,
3642-
Register IdxReg, DebugLoc Loc,
3643-
MachineInstr &Pos) const {
3640+
bool SPIRVInstructionSelector::generateImageReadOrFetch(
3641+
Register &ResVReg, const SPIRVType *ResType, Register ImageReg,
3642+
Register IdxReg, DebugLoc Loc, MachineInstr &Pos) const {
36443643
SPIRVType *ImageType = GR.getSPIRVTypeForVReg(ImageReg);
36453644
assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
36463645
"ImageReg is not an image type.");
3646+
36473647
bool IsSignedInteger =
36483648
sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
3649+
// Check if the "sampled" operand of the image type is 2.
3650+
auto SampledOp = ImageType->getOperand(6);
3651+
bool IsFetch = (SampledOp.getImm() != 2);
36493652

36503653
uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
36513654
if (ResultSize == 4) {
3652-
auto BMI = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead))
3653-
.addDef(ResVReg)
3654-
.addUse(GR.getSPIRVTypeID(ResType))
3655-
.addUse(ImageReg)
3656-
.addUse(IdxReg);
3655+
auto BMI =
3656+
BuildMI(*Pos.getParent(), Pos, Loc,
3657+
TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
3658+
.addDef(ResVReg)
3659+
.addUse(GR.getSPIRVTypeID(ResType))
3660+
.addUse(ImageReg)
3661+
.addUse(IdxReg);
36573662

36583663
if (IsSignedInteger)
36593664
BMI.addImm(0x1000); // SignExtend
@@ -3662,11 +3667,13 @@ bool SPIRVInstructionSelector::generateImageRead(Register &ResVReg,
36623667

36633668
SPIRVType *ReadType = widenTypeToVec4(ResType, Pos);
36643669
Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType));
3665-
auto BMI = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead))
3666-
.addDef(ReadReg)
3667-
.addUse(GR.getSPIRVTypeID(ReadType))
3668-
.addUse(ImageReg)
3669-
.addUse(IdxReg);
3670+
auto BMI =
3671+
BuildMI(*Pos.getParent(), Pos, Loc,
3672+
TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
3673+
.addDef(ReadReg)
3674+
.addUse(GR.getSPIRVTypeID(ReadType))
3675+
.addUse(ImageReg)
3676+
.addUse(IdxReg);
36703677
if (IsSignedInteger)
36713678
BMI.addImm(0x1000); // SignExtend
36723679
bool Succeed = BMI.constrainAllUses(TII, TRI, RBI);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}
3+
4+
; When accessing read-only `Buffer` types, SPIR-V should use `OpImageFetch` instead of `OpImageRead`.
5+
; https://github.com/llvm/llvm-project/issues/162891
6+
7+
; CHECK-DAG: OpCapability SampledBuffer
8+
; CHECK-DAG: OpCapability ImageBuffer
9+
; CHECK-DAG: [[TypeInt:%[0-9]+]] = OpTypeInt 32 0
10+
; CHECK-DAG: [[TypeImageBuffer:%[0-9]+]] = OpTypeImage [[TypeInt]] Buffer 2 0 0 1 Unknown
11+
; CHECK-DAG: [[TypePtrImageBuffer:%[0-9]+]] = OpTypePointer UniformConstant [[TypeImageBuffer]]
12+
; CHECK-DAG: [[TypeVector:%[0-9]+]] = OpTypeVector [[TypeInt]] 4
13+
; CHECK-DAG: [[Index:%[0-9]+]] = OpConstant [[TypeInt]] 98
14+
; CHECK-DAG: [[Variable:%[0-9]+]] = OpVariable [[TypePtrImageBuffer]] UniformConstant
15+
@.str = private unnamed_addr constant [7 x i8] c"rwbuff\00", align 1
16+
@.str.2 = private unnamed_addr constant [5 x i8] c"buff\00", align 1
17+
18+
define void @main() local_unnamed_addr #0 {
19+
entry:
20+
%0 = tail call target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) @llvm.spv.resource.handlefromimplicitbinding.tspirv.Image_i32_5_2_0_0_2_33t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
21+
%1 = tail call target("spirv.Image", i32, 5, 2, 0, 0, 1, 0) @llvm.spv.resource.handlefromimplicitbinding.tspirv.Image_i32_5_2_0_0_1_0t(i32 1, i32 0, i32 1, i32 0, ptr nonnull @.str.2)
22+
%2 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_1_0t(target("spirv.Image", i32, 5, 2, 0, 0, 1, 0) %1, i32 98)
23+
; CHECK: [[Load:%[0-9]+]] = OpLoad [[TypeImageBuffer]] [[Variable]]
24+
; CHECK: [[ImageFetch:%[0-9]+]] = OpImageFetch [[TypeVector]] [[Load]] [[Index]]
25+
; CHECK: {{.*}} = OpCompositeExtract [[TypeInt]] [[ImageFetch]] 0
26+
%3 = load i32, ptr addrspace(11) %2, align 4
27+
%4 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_33t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) %0, i32 99)
28+
store i32 %3, ptr addrspace(11) %4, align 4
29+
%5 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_33t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) %0, i32 96)
30+
; CHECK: {{%[0-9]+}} = OpLoad {{.*}}
31+
; CHECK: {{%[0-9]+}} = OpImageRead {{.*}}
32+
%6 = load i32, ptr addrspace(11) %5, align 4
33+
%7 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_33t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 33) %0, i32 97)
34+
store i32 %6, ptr addrspace(11) %7, align 4
35+
ret void
36+
}

0 commit comments

Comments
 (0)