diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -405,8 +405,20 @@ return true; // Lifetime intrinsics are dead when their right-hand is undef. - if (II->isLifetimeStartOrEnd()) - return isa(II->getArgOperand(1)); + if (II->isLifetimeStartOrEnd()) { + auto Arg = II->getArgOperand(1); + if (isa(Arg)) { + return true; + } else if (isa(Arg) || isa(Arg)) { + return llvm::all_of(II->getArgOperand(1)->uses(), [](Use &use) { + if (IntrinsicInst *intrinsicUse = + dyn_cast(use.getUser())) + return intrinsicUse->isLifetimeStartOrEnd(); + return false; + }); + } + return false; + } // Assumptions are dead if their condition is trivially true. Guards on // true are operationally no-ops. In the future we can consider more diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -388,14 +388,14 @@ store i8 0, i8* %unknown ret void } -define void @callerE(i8* %arg) { +define i8* @callerE(i8* %arg) { ; CHECK: Function Attrs: argmemonly nounwind willreturn ; CHECK-LABEL: define {{[^@]+}}@callerE -; CHECK-SAME: (i8* nocapture [[ARG:%.*]]) +; CHECK-SAME: (i8* returned [[ARG:%.*]]) ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nocapture [[ARG]]) -; CHECK-NEXT: ret void +; CHECK-NEXT: ret i8* [[ARG]] ; call void @llvm.lifetime.start.p0i8(i64 4, i8* %arg) - ret void + ret i8* %arg } diff --git a/llvm/test/Transforms/Coroutines/coro-split-02.ll b/llvm/test/Transforms/Coroutines/coro-split-02.ll --- a/llvm/test/Transforms/Coroutines/coro-split-02.ll +++ b/llvm/test/Transforms/Coroutines/coro-split-02.ll @@ -32,6 +32,7 @@ %cast = bitcast i32* %testval to i8* call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast) call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast) + %dummy = load i8, i8* %cast call void @print(i32 %val) br label %exit exit: diff --git a/llvm/test/Transforms/DCE/basic.ll b/llvm/test/Transforms/DCE/basic.ll --- a/llvm/test/Transforms/DCE/basic.ll +++ b/llvm/test/Transforms/DCE/basic.ll @@ -11,5 +11,21 @@ ret void } +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) nounwind + +; CHECK-LABEL: @test_lifetime +define i32 @test_lifetime() { +; Check that lifetime intrinsics are removed along with the pointer. +; CHECK-NEXT: @llvm.dbg.value +; CHECK-NEXT: ret i32 0 +; CHECK-NOT: llvm.lifetime.start +; CHECK-NOT: llvm.lifetime.end + %i = alloca i8, align 4 + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %i) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %i) + ret i32 0 +} + ; CHECK: [[add]] = !DILocalVariable ; CHECK: [[sub]] = !DILocalVariable diff --git a/llvm/test/Transforms/DeadStoreElimination/lifetime.ll b/llvm/test/Transforms/DeadStoreElimination/lifetime.ll --- a/llvm/test/Transforms/DeadStoreElimination/lifetime.ll +++ b/llvm/test/Transforms/DeadStoreElimination/lifetime.ll @@ -12,7 +12,7 @@ store i8 0, i8* %A ;; Written to by memset call void @llvm.lifetime.end.p0i8(i64 1, i8* %A) -; CHECK: lifetime.end +; CHECK-NOT: lifetime.end call void @llvm.memset.p0i8.i8(i8* %A, i8 0, i8 -1, i1 false) ; CHECK-NOT: memset @@ -26,11 +26,9 @@ %Q = getelementptr i32, i32* %P, i32 1 %R = bitcast i32* %Q to i8* call void @llvm.lifetime.start.p0i8(i64 4, i8* %R) -; CHECK: lifetime.start store i32 0, i32* %Q ;; This store is dead. ; CHECK-NOT: store call void @llvm.lifetime.end.p0i8(i64 4, i8* %R) -; CHECK: lifetime.end ret void } diff --git a/llvm/test/Transforms/InstCombine/vararg.ll b/llvm/test/Transforms/InstCombine/vararg.ll --- a/llvm/test/Transforms/InstCombine/vararg.ll +++ b/llvm/test/Transforms/InstCombine/vararg.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -instcombine -instcombine-infinite-loop-threshold=2 -S | FileCheck %s +; RUN: opt < %s -instcombine -instcombine-infinite-loop-threshold=3 -S | FileCheck %s %struct.__va_list = type { i8*, i8*, i8*, i32, i32 }