-
Notifications
You must be signed in to change notification settings - Fork 11.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SPIR-V] Emit valid Lifestart/Lifestop instructions #98475
[SPIR-V] Emit valid Lifestart/Lifestop instructions #98475
Conversation
8a7436e
to
6235356
Compare
@llvm/pr-subscribers-backend-spir-v Author: Vyacheslav Levytskyy (VyacheslavLevytskyy) ChangesThis 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 is not declared.". The Full diff: https://github.com/llvm/llvm-project/pull/98475.diff 3 Files Affected:
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
}
|
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.
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 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.