diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 57147076402f7..c9b66ccfbdbd1 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -411,6 +411,7 @@ bool isConvergenceIntrinsic(const Instruction *I) { bool expectIgnoredInIRTranslation(const Instruction *I) { return match(I, m_AnyIntrinsic()); } @@ -1022,7 +1023,8 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper( // TODO: maybe improve performance by caching demangled names auto *II = dyn_cast(I); - if (II && II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { + if (II && (II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer || + II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) { auto *HandleType = cast(II->getOperand(0)->getType()); if (HandleType->getTargetExtName() == "spirv.Image" || HandleType->getTargetExtName() == "spirv.SignedImage") { @@ -1034,12 +1036,15 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper( } else if (HandleType->getTargetExtName() == "spirv.VulkanBuffer") { // This call is supposed to index into an array Ty = HandleType->getTypeParameter(0); - if (Ty->isArrayTy()) - Ty = Ty->getArrayElementType(); - else { - assert(Ty && Ty->isStructTy()); - uint32_t Index = cast(II->getOperand(1))->getZExtValue(); - Ty = cast(Ty)->getElementType(Index); + if (II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { + if (Ty->isArrayTy()) + Ty = Ty->getArrayElementType(); + else { + assert(Ty && Ty->isStructTy()); + uint32_t Index = + cast(II->getOperand(1))->getZExtValue(); + Ty = cast(Ty)->getElementType(Index); + } } Ty = reconstitutePeeledArrayType(Ty); } else { diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 5f71069b6b1dd..4559e9a661e36 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -704,6 +704,7 @@ static bool intrinsicHasSideEffects(Intrinsic::ID ID) { case Intrinsic::spv_radians: case Intrinsic::spv_reflect: case Intrinsic::spv_refract: + case Intrinsic::spv_resource_getbasepointer: case Intrinsic::spv_resource_getpointer: case Intrinsic::spv_resource_handlefrombinding: case Intrinsic::spv_resource_handlefromimplicitbinding: @@ -1893,7 +1894,9 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg, auto *PtrDef = getVRegDef(*MRI, Ptr); auto *IntPtrDef = dyn_cast(PtrDef); if (IntPtrDef && - IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { + (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer || + IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) { + Register HandleReg = IntPtrDef->getOperand(2).getReg(); SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg); if (HandleType->getOpcode() == SPIRV::OpTypeImage) { @@ -1985,7 +1988,9 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const { auto *PtrDef = getVRegDef(*MRI, Ptr); auto *IntPtrDef = dyn_cast(PtrDef); if (IntPtrDef && - IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) { + (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer || + IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) { + Register HandleReg = IntPtrDef->getOperand(2).getReg(); Register NewHandleReg = MRI->createVirtualRegister(MRI->getRegClass(HandleReg)); @@ -5135,6 +5140,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, case Intrinsic::spv_resource_gather: case Intrinsic::spv_resource_gather_cmp: return selectGatherIntrinsic(ResVReg, ResType, I); + case Intrinsic::spv_resource_getbasepointer: case Intrinsic::spv_resource_getpointer: { return selectResourceGetPointer(ResVReg, ResType, I); } @@ -5940,16 +5946,20 @@ bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg, assert(ResType->getOpcode() == SPIRV::OpTypePointer); MachineIRBuilder MIRBuilder(I); - Register IndexReg = I.getOperand(3).getReg(); Register ZeroReg = buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I); - BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain)) - .addDef(ResVReg) - .addUse(GR.getSPIRVTypeID(ResType)) - .addUse(ResourcePtr) - .addUse(ZeroReg) - .addUse(IndexReg) - .constrainAllUses(TII, TRI, RBI); + auto MIB = + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain)) + .addDef(ResVReg) + .addUse(GR.getSPIRVTypeID(ResType)) + .addUse(ResourcePtr) + .addUse(ZeroReg); + + if (I.getNumExplicitOperands() > 3) { + Register IndexReg = I.getOperand(3).getReg(); + MIB.addUse(IndexReg); + } + MIB.constrainAllUses(TII, TRI, RBI); return true; } diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll new file mode 100644 index 0000000000000..aefeea0981871 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll @@ -0,0 +1,54 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %} + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1" + +@.str.1 = private unnamed_addr constant [2 x i8] c"B\00", align 1 +@.str.2 = private unnamed_addr constant [2 x i8] c"S\00", align 1 + +; CHECK-DAG: [[int:%[0-9]+]] = OpTypeInt 32 0 +; CHECK-DAG: [[zero:%[0-9]+]] = OpConstant [[int]] 0 + +; CHECK-DAG: [[ArrayType:%.+]] = OpTypeRuntimeArray [[int]] +; CHECK-DAG: [[BufferType:%.+]] = OpTypeStruct [[ArrayType]] +; CHECK-DAG: [[BufferPtrType:%.+]] = OpTypePointer StorageBuffer [[BufferType]] +; CHECK-DAG: [[BufferVar:%.+]] = OpVariable [[BufferPtrType]] StorageBuffer + +; CHECK-DAG: [[StructType:%.+]] = OpTypeStruct [[int]] [[int]] +; CHECK-DAG: [[StructWrapper:%.+]] = OpTypeStruct [[StructType]] +; CHECK-DAG: [[StructPtrType:%.+]] = OpTypePointer StorageBuffer [[StructWrapper]] +; CHECK-DAG: [[StructVar:%.+]] = OpVariable [[StructPtrType]] StorageBuffer + +define i32 @main() local_unnamed_addr { +entry: +; CHECK-DAG: [[BufferHandle:%.+]] = OpCopyObject [[BufferPtrType]] [[BufferVar]] +; CHECK-DAG: [[StructHandle:%.+]] = OpCopyObject [[StructPtrType]] [[StructVar]] + + %BufferHandle = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer(i32 0, i32 1, i32 1, i32 0, ptr nonnull @.str.1) + %StructHandle = tail call target("spirv.VulkanBuffer", {i32, i32}, 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBufferStruct(i32 0, i32 2, i32 1, i32 0, ptr nonnull @.str.2) + +; CHECK: [[AC2:%.+]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] +; CHECK-NOT: [[AC2]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] % + %2 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %BufferHandle) + %load2 = load i32, ptr addrspace(11) %2 + +; CHECK: [[AC3:%.+]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] [[index:%[0-9]+]] + %3 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %BufferHandle, i32 42) + %load3 = load i32, ptr addrspace(11) %3 + +; CHECK: [[AC4:%.+]] = OpAccessChain {{.*}} [[StructHandle]] [[zero]] +; CHECK-NOT: [[AC4]] = OpAccessChain {{.*}} [[StructHandle]] [[zero]] % + %4 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBufferStruct(target("spirv.VulkanBuffer", {i32, i32}, 12, 0) %StructHandle) + %load4 = load i32, ptr addrspace(11) %4 + + %res1 = add i32 %load2, %load3 + %res2 = add i32 %res1, %load4 + ret i32 %res2 +} + +declare target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer(i32, i32, i32, i32, ptr) +declare target("spirv.VulkanBuffer", {i32, i32}, 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBufferStruct(i32, i32, i32, i32, ptr) + +declare ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0)) +declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0), i32) +declare ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBufferStruct(target("spirv.VulkanBuffer", {i32, i32}, 12, 0))