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
2 changes: 2 additions & 0 deletions llvm-spirv/lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
SPIRVLifetimeStart *LTStart = static_cast<SPIRVLifetimeStart *>(BV);
IRBuilder<> Builder(BB);
auto *Var = transValue(LTStart->getObject(), F, BB);
Var = Var->stripPointerCasts();
Copy link
Contributor Author

@MrSidims MrSidims Oct 6, 2025

Choose a reason for hiding this comment

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

This strip bitcast is missing in intel/llvm, but it present in every other repository, both Khronos and downstream.

CallInst *Start = Builder.CreateLifetimeStart(Var);
return mapValue(BV, Start);
}
Expand All @@ -1885,6 +1886,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
SPIRVLifetimeStop *LTStop = static_cast<SPIRVLifetimeStop *>(BV);
IRBuilder<> Builder(BB);
auto *Var = transValue(LTStop->getObject(), F, BB);
Var = Var->stripPointerCasts();
for (const auto &I : Var->users())
if (auto *II = getLifetimeStartIntrinsic(dyn_cast<Instruction>(I)))
return mapValue(BV, Builder.CreateLifetimeEnd(II->getOperand(0)));
Expand Down
14 changes: 13 additions & 1 deletion llvm-spirv/lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4872,16 +4872,28 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,

unsigned PtrAS = cast<PointerType>(LLVMPtrOp->getType())->getAddressSpace();
auto *PtrOp = transValue(LLVMPtrOp, BB);
if (PtrAS == SPIRAS_Private)
// INTEL_CUSTOMIZATION begin
// Workaround to make older versions of SPIRVReader working with new
// rules of LLVM lifetime intrinsics.
// TODO: to remove the W/A.
if (PtrAS == SPIRAS_Private) {
auto *Int8PtrTy =
transPointerType(Type::getInt8Ty(M->getContext()), SPIRAS_Private);
PtrOp = BM->addUnaryInst(OpBitcast, Int8PtrTy, PtrOp, BB);
return BM->addLifetimeInst(OC, PtrOp, Size, BB);
}
// If pointer address space is Generic - use original allocation.
BM->getErrorLog().checkError(
PtrAS == SPIRAS_Generic, SPIRVEC_InvalidInstruction, II,
"lifetime intrinsic pointer operand must be in private or generic AS");
if (PtrOp->getOpCode() == OpPtrCastToGeneric) {
auto *UI = static_cast<SPIRVUnary *>(PtrOp);
PtrOp = UI->getOperand(0);
auto *Int8PtrTy =
transPointerType(Type::getInt8Ty(M->getContext()), SPIRAS_Private);
PtrOp = BM->addUnaryInst(OpBitcast, Int8PtrTy, PtrOp, BB);
}
// INTEL_CUSTOMIZATION end
return BM->addLifetimeInst(OC, PtrOp, Size, BB);
}
// We don't want to mix translation of regular code and debug info, because
Expand Down
79 changes: 44 additions & 35 deletions llvm-spirv/test/llvm-intrinsics/lifetime.ll
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,35 @@
; RUN: llvm-spirv -r %t.spv -o %t.spv.bc
; RUN: llvm-dis < %t.spv.bc | FileCheck %s --check-prefix=CHECK-LLVM

; CHECK-SPIRV-DAG: EntryPoint [[#]] [[#SimpleF:]] "lifetime_simple"
; CHECK-SPIRV-DAG: EntryPoint [[#]] [[#SizedF:]] "lifetime_sized"
; CHECK-SPIRV-DAG: EntryPoint [[#]] [[#GenericF:]] "lifetime_generic"
; CHECK-SPIRV-DAG: Name [[#SimpleF:]] "lifetime_simple"
; CHECK-SPIRV-DAG: Name [[#SizedF:]] "lifetime_sized"
; CHECK-SPIRV-DAG: Name [[#GenericF:]] "lifetime_generic"
; CHECK-SPIRV-DAG: TypeStruct [[#StructTy:]] [[#]]
; CHECK-SPIRV-DAG: TypePointer [[#PrivatePtrTy:]] 7 [[#StructTy]]

; INTEL_CUSTOMIZATION:
; CHECK-SPIRV: Function [[#]] [[#SimpleF:]]
; CHECK-SPIRV: LifetimeStart [[#Tmp:]] 0
; CHECK-SPIRV: LifetimeStop [[#Tmp]] 0
; CHECK-SPIRV: Variable [[#]] [[#Var:]]
; CHECK-SPIRV: Bitcast [[#]] [[#Cast1:]] [[#Var]]
; CHECK-SPIRV: LifetimeStart [[#Cast1]] 4
; CHECK-SPIRV: Bitcast [[#]] [[#Cast2:]] [[#Var]]
; CHECK-SPIRV: LifetimeStop [[#Cast2]] 4

; CHECK-SPIRV: Function [[#]] [[#SizedF:]]
; CHECK-SPIRV: LifetimeStart [[#Tmp:]] 1
; CHECK-SPIRV: LifetimeStop [[#Tmp]] 1
; CHECK-SPIRV: Variable [[#]] [[#Var:]]
; CHECK-SPIRV: Bitcast [[#]] [[#Cast1:]] [[#Var]]
; CHECK-SPIRV: LifetimeStart [[#Cast1]] 1
; CHECK-SPIRV: Bitcast [[#]] [[#Cast2:]] [[#Var]]
; CHECK-SPIRV: LifetimeStop [[#Cast2]] 1

; CHECK-SPIRV: Function [[#]] [[#GenericF:]]
; CHECK-SPIRV: Variable [[#PrivatePtrTy]] [[#Var:]] 7
; CHECK-SPIRV: PtrCastToGeneric [[#]] [[#Cast1:]] [[#Var]]
; CHECK-SPIRV: LifetimeStart [[#Var]] 0
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[#]] [[#Cast1]]
; CHECK-SPIRV: LifetimeStop [[#Var]] 0
; CHECK-SPIRV: PtrCastToGeneric [[#]] [[#ASCast:]] [[#Var]]
; CHECK-SPIRV: Bitcast [[#]] [[#Cast1:]] [[#Var]]
; CHECK-SPIRV: LifetimeStart [[#Cast1]] 1
; CHECK-SPIRV: FunctionCall [[#]] [[#]] [[#]] [[#ASCast]]
; CHECK-SPIRV: Bitcast [[#]] [[#Cast2:]] [[#Var]]
; CHECK-SPIRV: LifetimeStop [[#Cast2]] 1

; CHECK-LLVM-LABEL: lifetime_simple
; CHECK-LLVM: %[[#Alloca:]] = alloca i32
Expand All @@ -49,6 +58,7 @@
; CHECK-LLVM: call void @llvm.lifetime.start.p0(ptr %[[#Alloca]])
; CHECK-LLVM: call spir_func void @boo(ptr addrspace(4) %[[#Cast1]])
; CHECK-LLVM: call void @llvm.lifetime.end.p0(ptr %[[#Alloca]])
; INTEL_CUSTOMIZATION end

; ModuleID = 'main'
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
Expand All @@ -57,64 +67,63 @@ target triple = "spir64-unknown-unknown"
%class.anon = type { i8 }

; Function Attrs: nounwind
define spir_kernel void @lifetime_simple(i32 addrspace(1)* captures(none) %res, i32 addrspace(1)* captures(none) %lhs, i32 addrspace(1)* captures(none) %rhs) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !5 !kernel_arg_type_qual !4 {
define spir_kernel void @lifetime_simple(ptr addrspace(1) captures(none) %res, ptr addrspace(1) captures(none) %lhs, ptr addrspace(1) captures(none) %rhs) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !5 !kernel_arg_type_qual !4 {
%1 = alloca i32
%2 = call spir_func i64 @_Z13get_global_idj(i32 0) #1
%3 = shl i64 %2, 32
%4 = ashr exact i64 %3, 32
%5 = getelementptr inbounds i32, i32 addrspace(1)* %lhs, i64 %4
%6 = load i32, i32 addrspace(1)* %5, align 4
%7 = getelementptr inbounds i32, i32 addrspace(1)* %rhs, i64 %4
%5 = getelementptr inbounds i32, ptr addrspace(1) %lhs, i64 %4
%6 = load i32, ptr addrspace(1) %5, align 4
%7 = getelementptr inbounds i32, ptr addrspace(1) %rhs, i64 %4
%8 = load i32, i32 addrspace(1)* %7, align 4
%9 = sub i32 %6, %8
%10 = bitcast i32* %1 to i8*
call void @llvm.lifetime.start.p0i8(i64 -1, i8* %10)
store i32 %9, i32* %1
%11 = load i32, i32* %1
call void @llvm.lifetime.end.p0i8(i64 -1, i8* %10)
%12 = getelementptr inbounds i32, i32 addrspace(1)* %res, i64 %4
store i32 %11, i32 addrspace(1)* %12, align 4
call void @llvm.lifetime.start.p0(ptr %1)
store i32 %9, ptr %1
%11 = load i32, ptr %1
call void @llvm.lifetime.end.p0(ptr %1)
%12 = getelementptr inbounds i32, ptr addrspace(1) %res, i64 %4
store i32 %11, ptr addrspace(1) %12, align 4
ret void
}

define spir_kernel void @lifetime_sized() #0 !kernel_arg_addr_space !8 !kernel_arg_access_qual !8 !kernel_arg_type !8 !kernel_arg_base_type !8 !kernel_arg_type_qual !8 {
entry:
%0 = alloca i8, align 1
call void @llvm.lifetime.start.p0i8(i64 1, i8* %0) #0
call spir_func void @goo(i8* %0)
call void @llvm.lifetime.end.p0i8(i64 1, i8* %0) #0
call void @llvm.lifetime.start.p0(ptr %0) #0
call spir_func void @goo(ptr %0)
call void @llvm.lifetime.end.p0(ptr %0) #0
ret void
}

declare spir_func void @foo(%class.anon* %this) #0
declare spir_func void @foo(ptr %this) #0

declare spir_func void @goo(i8* %this) #0
declare spir_func void @goo(ptr %this) #0

; Function Attrs: nounwind
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* captures(none)) #0
declare void @llvm.lifetime.start.p0(ptr captures(none)) #0

; Function Attrs: nounwind
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* captures(none)) #0
declare void @llvm.lifetime.end.p0(ptr captures(none)) #0

; Function Attrs: nounwind readnone
declare spir_func i64 @_Z13get_global_idj(i32) #1

define spir_kernel void @lifetime_generic() #0 !kernel_arg_addr_space !8 !kernel_arg_access_qual !8 !kernel_arg_type !8 !kernel_arg_base_type !8 !kernel_arg_type_qual !8 {
entry:
%0 = alloca %class.anon, align 1, addrspace(4)
call void @llvm.lifetime.start.p4i8(i64 -1, i8 addrspace(4)* %0) #0
call spir_func void @boo(%class.anon addrspace(4)* %0)
call void @llvm.lifetime.end.p4i8(i64 -1, i8 addrspace(4)* %0) #0
call void @llvm.lifetime.start.p4(ptr addrspace(4) %0) #0
call spir_func void @boo(ptr addrspace(4) %0)
call void @llvm.lifetime.end.p4(ptr addrspace(4) %0) #0
ret void
}

declare spir_func void @boo(%class.anon addrspace(4)* %this) #0
declare spir_func void @boo(ptr addrspace(4) %this) #0

; Function Attrs: nounwind
declare void @llvm.lifetime.start.p4i8(i64 immarg, i8 addrspace(4)* captures(none)) #0
declare void @llvm.lifetime.start.p4(ptr addrspace(4) captures(none)) #0

; Function Attrs: nounwind
declare void @llvm.lifetime.end.p4i8(i64 immarg, i8 addrspace(4)* captures(none)) #0
declare void @llvm.lifetime.end.p4(ptr addrspace(4) captures(none)) #0


attributes #0 = { nounwind }
Expand Down
18 changes: 12 additions & 6 deletions llvm-spirv/test/llvm-intrinsics/memmove.ll
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@
; CHECK-SPIRV: Variable [[#]] [[#MEM:]]
; CHECK-SPIRV: Bitcast [[#]] [[#I8_ARG_IN:]] [[#ARG_IN]]
; CHECK-SPIRV: Bitcast [[#]] [[#I8_ARG_OUT:]] [[#ARG_OUT]]
; CHECK-SPIRV: LifetimeStart [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_1:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStart [[#MEM_CAST_1]]
; CHECK-SPIRV: CopyMemorySized [[#MEM]] [[#I8_ARG_IN]] [[#C128]] 2 64
; CHECK-SPIRV: CopyMemorySized [[#I8_ARG_OUT]] [[#MEM]] [[#C128]] 2 64
; CHECK-SPIRV: LifetimeStop [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_2:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStop [[#MEM_CAST_2]]

; CHECK-SPIRV-LABEL: [[#]] Function [[#]]
; CHECK-SPIRV: FunctionParameter [[#I8GLOBAL_PTR]] [[#ARG_IN:]]
Expand All @@ -46,20 +48,24 @@
; CHECK-SPIRV: Bitcast [[#]] [[#I8_ARG_IN:]] [[#ARG_IN]]
; CHECK-SPIRV: Bitcast [[#]] [[#I8_ARG_OUT_GENERIC:]] [[#ARG_OUT]]
; CHECK-SPIRV: GenericCastToPtr [[#]] [[#I8_ARG_OUT:]] [[#I8_ARG_OUT_GENERIC]]
; CHECK-SPIRV: LifetimeStart [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_1:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStart [[#MEM_CAST_1]]
; CHECK-SPIRV: CopyMemorySized [[#MEM]] [[#I8_ARG_IN]] [[#C68]] 2 64
; CHECK-SPIRV: CopyMemorySized [[#I8_ARG_OUT]] [[#MEM]] [[#C68]] 2 64
; CHECK-SPIRV: LifetimeStop [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_2:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStop [[#MEM_CAST_2]]

; CHECK-SPIRV-LABEL: [[#]] Function [[#]]
; CHECK-SPIRV: FunctionParameter [[#]] [[#ARG_IN:]]
; CHECK-SPIRV: FunctionParameter [[#]] [[#ARG_OUT:]]
;
; CHECK-SPIRV: Variable [[#]] [[#MEM:]]
; CHECK-SPIRV: LifetimeStart [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_1:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStart [[#MEM_CAST_1]]
; CHECK-SPIRV: CopyMemorySized [[#MEM]] [[#ARG_IN]] [[#C72]] 0
; CHECK-SPIRV: CopyMemorySized [[#ARG_OUT]] [[#MEM]] [[#C72]] 0
; CHECK-SPIRV: LifetimeStop [[#MEM]]
; CHECK-SPIRV: Bitcast [[#]] [[#MEM_CAST_2:]] [[#MEM]]
; CHECK-SPIRV: LifetimeStop [[#MEM_CAST_2]]

; xCHECK-SPIRV-LABEL: [[#]] Function [[#]]
;
Expand Down
Loading