II->getIntrinsicID() == Intrinsic::launder_invariant_group)
return true;
- if (II->isLifetimeStartOrEnd()) {
- auto *Arg = II->getArgOperand(1);
- // Lifetime intrinsics are dead when their right-hand is undef.
- if (isa<UndefValue>(Arg))
- return true;
- // If the right-hand is an alloc, global, or argument and the only uses
- // are lifetime intrinsics then the intrinsics are dead.
- if (isa<AllocaInst>(Arg) || isa<GlobalValue>(Arg) || isa<Argument>(Arg))
- return llvm::all_of(Arg->uses(), [](Use &Use) {
- if (IntrinsicInst *IntrinsicUse =
- dyn_cast<IntrinsicInst>(Use.getUser()))
- return IntrinsicUse->isLifetimeStartOrEnd();
- return false;
- });
- return false;
- }
+ // Lifetime intrinsics are dead when their right-hand is undef.
+ if (II->isLifetimeStartOrEnd())
+ return isa<UndefValue>(II->getArgOperand(1));
// Assumptions are dead if their condition is trivially true. Guards on
// true are operationally no-ops. In the future we can consider more
store i8 0, i8* %unknown
ret void
}
-
-; CHECK: Function Attrs: nofree {{(norecurse )?}}nosync nounwind readnone willreturn
+; CHECK: Function Attrs: argmemonly nounwind willreturn
define void @callerE(i8* %arg) {
; CHECK-LABEL: define {{[^@]+}}@callerE
-; CHECK-SAME: (i8* nocapture nofree readnone [[ARG:%.*]])
+; CHECK-SAME: (i8* nocapture [[ARG:%.*]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* nocapture [[ARG]])
; CHECK-NEXT: ret void
;
call void @llvm.lifetime.start.p0i8(i64 4, i8* %arg)
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_alloca
-define i32 @test_lifetime_alloca() {
-; 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-LABEL: @test_lifetime_arg
-define i32 @test_lifetime_arg(i8*) {
-; 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
- call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0)
- call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0)
- ret i32 0
-}
-
-@glob = global i8 1
-
-; CHECK-LABEL: @test_lifetime_global
-define i32 @test_lifetime_global() {
-; 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
- call void @llvm.lifetime.start.p0i8(i64 -1, i8* @glob)
- call void @llvm.lifetime.end.p0i8(i64 -1, i8* @glob)
- ret i32 0
-}
-
-; CHECK-LABEL: @test_lifetime_bitcast
-define i32 @test_lifetime_bitcast(i32*) {
-; Check that lifetime intrinsics are NOT removed when the pointer is a bitcast.
-; It's not uncommon for two bitcasts to be made: one for lifetime, one for use.
-; TODO: Support the above case.
-; CHECK-NEXT: bitcast
-; CHECK-NEXT: llvm.dbg.value
-; CHECK-NEXT: llvm.lifetime.start
-; CHECK-NEXT: llvm.lifetime.end
-; CHECK-NEXT: ret i32 0
- %2 = bitcast i32* %0 to i8*
- call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2)
- call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2)
- ret i32 0
-}
-
; CHECK: [[add]] = !DILocalVariable
; CHECK: [[sub]] = !DILocalVariable
store i8 0, i8* %A ;; Written to by memset
call void @llvm.lifetime.end.p0i8(i64 1, i8* %A)
-; CHECK-NOT: lifetime.end
+; CHECK: lifetime.end
call void @llvm.memset.p0i8.i8(i8* %A, i8 0, i8 -1, i1 false)
; CHECK-NOT: memset
%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
}