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 @@ -406,7 +406,13 @@ // Lifetime intrinsics are dead when their right-hand is undef. if (II->isLifetimeStartOrEnd()) - return isa(II->getArgOperand(1)); + return isa(II->getArgOperand(1)) || + llvm::all_of(II->getArgOperand(1)->uses(), [](Use &use) { + if (IntrinsicInst *intrinsicUse = + dyn_cast(use.getUser())) + return intrinsicUse->isLifetimeStartOrEnd(); + 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,23 @@ 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: @llvm.dbg.value +; CHECK-NEXT: ret i32 0 +; CHECK-NOT: llvm.lifetime.start +; CHECK-NOT: llvm.lifetime.end + %i = alloca i32, align 4 + %i.ptr = bitcast i32* %i to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %i.ptr) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %i.ptr) + 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,6 @@ store i8 0, i8* %A ;; Written to by memset call void @llvm.lifetime.end.p0i8(i64 1, i8* %A) -; CHECK: lifetime.end call void @llvm.memset.p0i8.i8(i8* %A, i8 0, i8 -1, i1 false) ; CHECK-NOT: memset @@ -26,11 +25,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/Inline/byval-tail-call.ll b/llvm/test/Transforms/Inline/byval-tail-call.ll --- a/llvm/test/Transforms/Inline/byval-tail-call.ll +++ b/llvm/test/Transforms/Inline/byval-tail-call.ll @@ -17,8 +17,7 @@ define void @foo(i32* %x) { ; CHECK-LABEL: define void @foo( -; CHECK: llvm.lifetime.start -; CHECK: store i32 %2, i32* %x +; CHECK: store i32 %1, i32* %x call void @bar(i32* byval %x) ret void } diff --git a/llvm/test/Transforms/InstCombine/lower-dbg-declare.ll b/llvm/test/Transforms/InstCombine/lower-dbg-declare.ll --- a/llvm/test/Transforms/InstCombine/lower-dbg-declare.ll +++ b/llvm/test/Transforms/InstCombine/lower-dbg-declare.ll @@ -35,7 +35,7 @@ br label %while.cond, !dbg !22 while.cond: ; preds = %while.body, %entry -; CHECK: dbg.value(metadata i32 %1, metadata [[METADATA_IDX1]], metadata !DIExpression()) +; CHECK: dbg.value(metadata i32 %0, metadata [[METADATA_IDX1]], metadata !DIExpression()) ; CHECK-NEXT: call zeroext i1 @_ZL5emptyi %1 = load i32, i32* %d1, align 4, !dbg !22 %call = call zeroext i1 @_ZL5emptyi(i32 %1), !dbg !22 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 } diff --git a/llvm/test/Transforms/OpenMP/parallel_deletion.ll b/llvm/test/Transforms/OpenMP/parallel_deletion.ll --- a/llvm/test/Transforms/OpenMP/parallel_deletion.ll +++ b/llvm/test/Transforms/OpenMP/parallel_deletion.ll @@ -141,15 +141,11 @@ ; CHECK-LABEL: define {{[^@]+}}@delete_parallel_2() ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull align 4 dereferenceable(4) [[TMP]]) #0 ; CHECK-NEXT: store i32 0, i32* [[A]], align 4 ; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 1, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*)* @.omp_outlined..3 to void (i32*, i32*, ...)*), i32* nocapture nofree nonnull align 4 dereferenceable(4) [[A]]) ; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 1, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*)* @.omp_outlined..4 to void (i32*, i32*, ...)*), i32* nocapture nonnull align 4 dereferenceable(4) [[A]]) ; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 1, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*)* @.omp_outlined..5 to void (i32*, i32*, ...)*), i32* nocapture nonnull align 4 dereferenceable(4) [[A]]) ; CHECK-NEXT: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull align 8 dereferenceable(24) @0, i32 1, void (i32*, i32*, ...)* nonnull bitcast (void (i32*, i32*, i32*)* @.omp_outlined..6 to void (i32*, i32*, ...)*), i32* nocapture nonnull align 4 dereferenceable(4) [[A]]) -; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[TMP1]]) ; CHECK-NEXT: ret void ; entry: