Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 29 additions & 21 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
SPIRVType *widenTypeToVec4(const SPIRVType *Type, MachineInstr &I) const;
bool extractSubvector(Register &ResVReg, const SPIRVType *ResType,
Register &ReadReg, MachineInstr &InsertionPoint) const;
bool generateImageRead(Register &ResVReg, const SPIRVType *ResType,
Register ImageReg, Register IdxReg, DebugLoc Loc,
MachineInstr &Pos) const;
bool generateImageReadOrFetch(Register &ResVReg, const SPIRVType *ResType,
Register ImageReg, Register IdxReg,
DebugLoc Loc, MachineInstr &Pos) const;
bool BuildCOPY(Register DestReg, Register SrcReg, MachineInstr &I) const;
bool loadVec3BuiltinInputID(SPIRV::BuiltIn::BuiltIn BuiltInValue,
Register ResVReg, const SPIRVType *ResType,
Expand Down Expand Up @@ -1317,8 +1317,8 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
}

Register IdxReg = IntPtrDef->getOperand(3).getReg();
return generateImageRead(ResVReg, ResType, NewHandleReg, IdxReg,
I.getDebugLoc(), I);
return generateImageReadOrFetch(ResVReg, ResType, NewHandleReg, IdxReg,
I.getDebugLoc(), I);
}
}

Expand Down Expand Up @@ -3633,27 +3633,33 @@ bool SPIRVInstructionSelector::selectReadImageIntrinsic(
DebugLoc Loc = I.getDebugLoc();
MachineInstr &Pos = I;

return generateImageRead(ResVReg, ResType, NewImageReg, IdxReg, Loc, Pos);
return generateImageReadOrFetch(ResVReg, ResType, NewImageReg, IdxReg, Loc,
Pos);
}

bool SPIRVInstructionSelector::generateImageRead(Register &ResVReg,
const SPIRVType *ResType,
Register ImageReg,
Register IdxReg, DebugLoc Loc,
MachineInstr &Pos) const {
bool SPIRVInstructionSelector::generateImageReadOrFetch(
Register &ResVReg, const SPIRVType *ResType, Register ImageReg,
Register IdxReg, DebugLoc Loc, MachineInstr &Pos) const {
SPIRVType *ImageType = GR.getSPIRVTypeForVReg(ImageReg);
assert(ImageType && ImageType->getOpcode() == SPIRV::OpTypeImage &&
"ImageReg is not an image type.");

bool IsSignedInteger =
sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ImageType));
// Check if the "sampled" operand of the image type is 1.
// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpImageFetch
auto SampledOp = ImageType->getOperand(6);
bool IsFetch = (SampledOp.getImm() == 1);

uint64_t ResultSize = GR.getScalarOrVectorComponentCount(ResType);
if (ResultSize == 4) {
auto BMI = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead))
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(ImageReg)
.addUse(IdxReg);
auto BMI =
BuildMI(*Pos.getParent(), Pos, Loc,
TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
.addUse(ImageReg)
.addUse(IdxReg);

if (IsSignedInteger)
BMI.addImm(0x1000); // SignExtend
Expand All @@ -3662,11 +3668,13 @@ bool SPIRVInstructionSelector::generateImageRead(Register &ResVReg,

SPIRVType *ReadType = widenTypeToVec4(ResType, Pos);
Register ReadReg = MRI->createVirtualRegister(GR.getRegClass(ReadType));
auto BMI = BuildMI(*Pos.getParent(), Pos, Loc, TII.get(SPIRV::OpImageRead))
.addDef(ReadReg)
.addUse(GR.getSPIRVTypeID(ReadType))
.addUse(ImageReg)
.addUse(IdxReg);
auto BMI =
BuildMI(*Pos.getParent(), Pos, Loc,
TII.get(IsFetch ? SPIRV::OpImageFetch : SPIRV::OpImageRead))
.addDef(ReadReg)
.addUse(GR.getSPIRVTypeID(ReadType))
.addUse(ImageReg)
.addUse(IdxReg);
if (IsSignedInteger)
BMI.addImm(0x1000); // SignExtend
bool Succeed = BMI.constrainAllUses(TII, TRI, RBI);
Expand Down
36 changes: 36 additions & 0 deletions llvm/test/CodeGen/SPIRV/hlsl-resources/TypedBufferLoad.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - | FileCheck %s
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val %}

; When accessing read-only `Buffer` types, SPIR-V should use `OpImageFetch` instead of `OpImageRead`.
; https://github.com/llvm/llvm-project/issues/162891

; CHECK-DAG: OpCapability SampledBuffer
; CHECK-DAG: OpCapability ImageBuffer
; CHECK-DAG: [[TypeInt:%[0-9]+]] = OpTypeInt 32 0
; CHECK-DAG: [[TypeImageBuffer:%[0-9]+]] = OpTypeImage [[TypeInt]] Buffer 2 0 0 1 Unknown
; CHECK-DAG: [[TypePtrImageBuffer:%[0-9]+]] = OpTypePointer UniformConstant [[TypeImageBuffer]]
; CHECK-DAG: [[TypeVector:%[0-9]+]] = OpTypeVector [[TypeInt]] 4
; CHECK-DAG: [[Index:%[0-9]+]] = OpConstant [[TypeInt]] 98
; CHECK-DAG: [[Variable:%[0-9]+]] = OpVariable [[TypePtrImageBuffer]] UniformConstant
@.str = private unnamed_addr constant [7 x i8] c"rwbuff\00", align 1
@.str.2 = private unnamed_addr constant [5 x i8] c"buff\00", align 1

define void @main() local_unnamed_addr #0 {
entry:
%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)
%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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a test for sampled = 0? Add another handle frombinding in the same file.

%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)
; CHECK: [[Load:%[0-9]+]] = OpLoad [[TypeImageBuffer]] [[Variable]]
; CHECK: [[ImageFetch:%[0-9]+]] = OpImageFetch [[TypeVector]] [[Load]] [[Index]]
; CHECK: {{.*}} = OpCompositeExtract [[TypeInt]] [[ImageFetch]] 0
%3 = load i32, ptr addrspace(11) %2, align 4
%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)
store i32 %3, ptr addrspace(11) %4, align 4
%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)
; CHECK: {{%[0-9]+}} = OpLoad {{.*}}
; CHECK: {{%[0-9]+}} = OpImageRead {{.*}}
%6 = load i32, ptr addrspace(11) %5, align 4
%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)
store i32 %6, ptr addrspace(11) %7, align 4
ret void
}