[llvm] [SPIR-V] Emit valid Lifestart/Lifestop instructions (PR #98475)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 1 04:53:45 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-spir-v
Author: Vyacheslav Levytskyy (VyacheslavLevytskyy)
<details>
<summary>Changes</summary>
This PR fixes emission of valid OpLifestart/OpLifestop instructions. According to https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpLifetimeStart: "Size must be 0 if Pointer is a pointer to a non-void type or the Addresses [capability](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Capability) is not declared.". The `Size` argument is set the corresponding intrinsics arguments, so Size is not zero we must ensure that Pointer has the required type by inserting a bitcast if needed.
---
Full diff: https://github.com/llvm/llvm-project/pull/98475.diff
3 Files Affected:
- (modified) llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp (+29)
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+1-3)
- (modified) llvm/test/CodeGen/SPIRV/llvm-intrinsics/lifetime.ll (+48-9)
``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
index ae4e039744286..69d72a75a428a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
@@ -203,6 +203,30 @@ static void validateGroupWaitEventsPtr(const SPIRVSubtarget &STI,
doInsertBitcast(STI, MRI, GR, I, OpReg, OpIdx, NewPtrType);
}
+static void validateLifetimeStart(const SPIRVSubtarget &STI,
+ MachineRegisterInfo *MRI,
+ SPIRVGlobalRegistry &GR, MachineInstr &I) {
+ Register PtrReg = I.getOperand(0).getReg();
+ MachineFunction *MF = I.getParent()->getParent();
+ Register PtrTypeReg = getTypeReg(MRI, PtrReg);
+ SPIRVType *PtrType = GR.getSPIRVTypeForVReg(PtrTypeReg, MF);
+ SPIRVType *PonteeElemType = PtrType ? GR.getPointeeType(PtrType) : nullptr;
+ if (!PonteeElemType || PonteeElemType->getOpcode() == SPIRV::OpTypeVoid ||
+ (PonteeElemType->getOpcode() == SPIRV::OpTypeInt &&
+ PonteeElemType->getOperand(1).getImm() == 8))
+ return;
+ // To keep the code valid a bitcast must be inserted
+ SPIRV::StorageClass::StorageClass SC =
+ static_cast<SPIRV::StorageClass::StorageClass>(
+ PtrType->getOperand(1).getImm());
+ MachineIRBuilder MIB(I);
+ LLVMContext &Context = MF->getFunction().getContext();
+ SPIRVType *ElemType =
+ GR.getOrCreateSPIRVType(IntegerType::getInt8Ty(Context), MIB);
+ SPIRVType *NewPtrType = GR.getOrCreateSPIRVPointerType(ElemType, MIB, SC);
+ doInsertBitcast(STI, MRI, GR, I, PtrReg, 0, NewPtrType);
+}
+
static void validateGroupAsyncCopyPtr(const SPIRVSubtarget &STI,
MachineRegisterInfo *MRI,
SPIRVGlobalRegistry &GR, MachineInstr &I,
@@ -413,6 +437,11 @@ void SPIRVTargetLowering::finalizeLowering(MachineFunction &MF) const {
SPIRV::OpTypeBool))
MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
break;
+ case SPIRV::OpLifetimeStart:
+ case SPIRV::OpLifetimeStop:
+ if (MI.getOperand(1).getImm() > 0)
+ validateLifetimeStart(STI, MRI, GR, MI);
+ break;
case SPIRV::OpGroupAsyncCopy:
validateGroupAsyncCopyPtr(STI, MRI, GR, MI, 3);
validateGroupAsyncCopyPtr(STI, MRI, GR, MI, 4);
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index ed786bd33aa05..5b04cc6661e49 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2088,9 +2088,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
: SPIRV::OpLifetimeStop;
int64_t Size = I.getOperand(I.getNumExplicitDefs() + 1).getImm();
Register PtrReg = I.getOperand(I.getNumExplicitDefs() + 2).getReg();
- unsigned PonteeOpType = GR.getPointeeTypeOp(PtrReg);
- bool IsNonvoidPtr = PonteeOpType != 0 && PonteeOpType != SPIRV::OpTypeVoid;
- if (Size == -1 || IsNonvoidPtr)
+ if (Size == -1)
Size = 0;
BuildMI(BB, I, I.getDebugLoc(), TII.get(Op)).addUse(PtrReg).addImm(Size);
} break;
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/lifetime.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/lifetime.ll
index 710a1581f760c..7fae8759c1f7d 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/lifetime.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/lifetime.ll
@@ -1,22 +1,61 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
-; CHECK: OpFunction
-; CHECK: %[[FooArg:.*]] = OpVariable
-; CHECK: OpLifetimeStart %[[FooArg]], 0
-; CHECK: OpCopyMemorySized
-; CHECK: OpBitcast
-; CHECK: OpInBoundsPtrAccessChain
-; CHECK: OpLifetimeStop %[[FooArg]], 0
+; CHECK-DAG: %[[#Char:]] = OpTypeInt 8 0
+; CHECK-DAG: %[[#PtrChar:]] = OpTypePointer Function %[[#Char]]
%tprange = type { %tparray }
%tparray = type { [2 x i64] }
+; CHECK: OpFunction
+; CHECK: %[[#FooVar:]] = OpVariable
+; CHECK: %[[#Casted1:]] = OpBitcast %[[#PtrChar]] %[[#FooVar]]
+; CHECK: OpLifetimeStart %[[#Casted1]], 72
+; CHECK: OpCopyMemorySized
+; CHECK: OpBitcast
+; CHECK: OpInBoundsPtrAccessChain
+; CHECK: %[[#Casted2:]] = OpBitcast %[[#PtrChar]] %[[#FooVar]]
+; CHECK: OpLifetimeStop %[[#Casted2]], 72
define spir_func void @foo(ptr noundef byval(%tprange) align 8 %_arg_UserRange) {
%RoundedRangeKernel = alloca %tprange, align 8
- call void @llvm.lifetime.start.p0(i64 72, ptr nonnull %RoundedRangeKernel) #7
+ call void @llvm.lifetime.start.p0(i64 72, ptr nonnull %RoundedRangeKernel)
call void @llvm.memcpy.p0.p0.i64(ptr align 8 %RoundedRangeKernel, ptr align 8 %_arg_UserRange, i64 16, i1 false)
%KernelFunc = getelementptr inbounds i8, ptr %RoundedRangeKernel, i64 16
- call void @llvm.lifetime.end.p0(i64 72, ptr nonnull %RoundedRangeKernel) #7
+ call void @llvm.lifetime.end.p0(i64 72, ptr nonnull %RoundedRangeKernel)
+ ret void
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#BarVar:]] = OpVariable
+; CHECK: OpLifetimeStart %[[#BarVar]], 0
+; CHECK: OpCopyMemorySized
+; CHECK: OpBitcast
+; CHECK: OpInBoundsPtrAccessChain
+; CHECK: OpLifetimeStop %[[#BarVar]], 0
+define spir_func void @bar(ptr noundef byval(%tprange) align 8 %_arg_UserRange) {
+ %RoundedRangeKernel = alloca %tprange, align 8
+ call void @llvm.lifetime.start.p0(i64 -1, ptr nonnull %RoundedRangeKernel)
+ call void @llvm.memcpy.p0.p0.i64(ptr align 8 %RoundedRangeKernel, ptr align 8 %_arg_UserRange, i64 16, i1 false)
+ %KernelFunc = getelementptr inbounds i8, ptr %RoundedRangeKernel, i64 16
+ call void @llvm.lifetime.end.p0(i64 -1, ptr nonnull %RoundedRangeKernel)
+ ret void
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#TestVar:]] = OpVariable
+; CHECK: OpLifetimeStart %[[#TestVar]], 1
+; CHECK: OpCopyMemorySized
+; CHECK: OpInBoundsPtrAccessChain
+; CHECK: OpLifetimeStop %[[#TestVar]], 1
+define spir_func void @test(ptr noundef align 8 %_arg) {
+ %var = alloca i8, align 8
+ call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %var)
+ call void @llvm.memcpy.p0.p0.i64(ptr align 8 %var, ptr align 8 %_arg, i64 1, i1 false)
+ %KernelFunc = getelementptr inbounds i8, ptr %var, i64 0
+ call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %var)
ret void
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/98475
More information about the llvm-commits
mailing list