blob: 2b153914c38bc8e4ba3600db68a76c30a4c2c85f [file] [log] [blame]
; RUN: opt -basic-aa -objc-arc -S < %s | FileCheck %s
target datalayout = "e-p:64:64:64"
declare i8* @llvm.objc.retain(i8*)
declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*)
declare void @opaque()
declare void @llvm.lifetime.start(i64, i8* nocapture)
declare void @llvm.lifetime.end(i64, i8* nocapture)
; CHECK-LABEL: define i8* @elide_with_retainRV(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_retainRV(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_retainRV_bitcast(
; CHECK-NEXT: entry:
; CHECK-NEXT: %c = bitcast i32* %x to i8*
; CHECK-NEXT: ret i8* %c
define i8* @elide_with_retainRV_bitcast(i32* %x) nounwind {
entry:
%a = bitcast i32* %x to i8*
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%c = bitcast i32* %x to i8*
%d = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %c) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_retainRV_phi(
; CHECK-NOT: define
; CHECK: phis:
; CHECK-NEXT: phi i8*
; CHECK-NEXT: ret i8*
define i8* @elide_with_retainRV_phi(i8* %x) nounwind {
entry:
br label %phis
phis:
%a = phi i8* [ %x, %entry ]
%c = phi i8* [ %x, %entry ]
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%d = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %c) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_retainRV_splitByRetain(
; CHECK-NEXT: entry:
; CHECK-NEXT: %b = call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %b)
define i8* @elide_with_retainRV_splitByRetain(i8* %x) nounwind {
entry:
; Cleanup is blocked by other ARC intrinsics for ease of implementation; we
; only delay processing AutoreleaseRV until the very next ARC intrinsic. In
; practice, it would be very strange for this to matter.
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.retain(i8* %x) nounwind
%d = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_retainRV_splitByOpaque(
; CHECK-NEXT: entry:
; CHECK-NEXT: %b = call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: call void @opaque()
; CHECK-NEXT: %d = tail call i8* @llvm.objc.retain(i8* %b)
; CHECK-NEXT: ret i8* %d
define i8* @elide_with_retainRV_splitByOpaque(i8* %x) nounwind {
entry:
; Cleanup should get blocked by opaque calls.
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
call void @opaque() nounwind
%d = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_retainRV_splitByLifetime(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %x)
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %x)
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_retainRV_splitByLifetime(i8* %x) nounwind {
entry:
; Cleanup should skip over lifetime intrinsics.
call void @llvm.lifetime.start(i64 8, i8* %x)
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
call void @llvm.lifetime.end(i64 8, i8* %x)
%d = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_retainRV_wrongArg(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.objc.release(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %y)
define i8* @elide_with_retainRV_wrongArg(i8* %x, i8* %y) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_retainRV_wrongBB(
; CHECK-NEXT: entry:
; CHECK-NEXT: call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: br label %next
; CHECK: next:
; CHECK-NEXT: tail call i8* @llvm.objc.retain(
; CHECK-NEXT: ret i8*
define i8* @elide_with_retainRV_wrongBB(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
br label %next
next:
%c = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_retainRV_beforeAutoreleaseRV(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_retainRV_beforeAutoreleaseRV(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
%d = call i8* @llvm.objc.autoreleaseReturnValue(i8* %c) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_retainRV_afterRetain(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %x)
; CHECK-NEXT: ret i8* %a
define i8* @elide_with_retainRV_afterRetain(i8* %x) nounwind {
entry:
%a = call i8* @llvm.objc.retain(i8* %x) nounwind
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%c = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_claimRV(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @llvm.objc.release(i8* %x)
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_claimRV(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_claimRV_bitcast(
; CHECK-NEXT: entry:
; CHECK-NEXT: %c = bitcast i32* %x to i8*
; CHECK-NEXT: tail call void @llvm.objc.release(i8* %c)
; CHECK-NEXT: ret i8* %c
define i8* @elide_with_claimRV_bitcast(i32* %x) nounwind {
entry:
%a = bitcast i32* %x to i8*
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%c = bitcast i32* %x to i8*
%d = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %c) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_claimRV_phi(
; CHECK-NOT: define
; CHECK: phis:
; CHECK-NEXT: %c = phi i8*
; CHECK-NEXT: tail call void @llvm.objc.release(i8* %c)
; CHECK-NEXT: ret i8* %c
define i8* @elide_with_claimRV_phi(i8* %x) nounwind {
entry:
br label %phis
phis:
%a = phi i8* [ %x, %entry ]
%c = phi i8* [ %x, %entry ]
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%d = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %c) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_claimRV_splitByRetain(
; CHECK-NEXT: entry:
; CHECK-NEXT: %b = call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b)
define i8* @elide_with_claimRV_splitByRetain(i8* %x) nounwind {
entry:
; Cleanup is blocked by other ARC intrinsics for ease of implementation; we
; only delay processing AutoreleaseRV until the very next ARC intrinsic. In
; practice, it would be very strange for this to matter.
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.retain(i8* %x) nounwind
%d = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_claimRV_splitByOpaque(
; CHECK-NEXT: entry:
; CHECK-NEXT: %b = call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: call void @opaque()
; CHECK-NEXT: %d = tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b)
; CHECK-NEXT: ret i8* %d
define i8* @elide_with_claimRV_splitByOpaque(i8* %x) nounwind {
entry:
; Cleanup should get blocked by opaque calls.
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
call void @opaque() nounwind
%d = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_claimRV_splitByLifetime(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %x)
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %x)
; CHECK-NEXT: tail call void @llvm.objc.release(i8* %x)
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_claimRV_splitByLifetime(i8* %x) nounwind {
entry:
; Cleanup should skip over lifetime intrinsics.
call void @llvm.lifetime.start(i64 8, i8* %x)
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
call void @llvm.lifetime.end(i64 8, i8* %x)
%d = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %d
}
; CHECK-LABEL: define i8* @elide_with_claimRV_wrongArg(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.objc.release(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %y)
define i8* @elide_with_claimRV_wrongArg(i8* %x, i8* %y) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %y) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_claimRV_wrongBB(
; CHECK-NEXT: entry:
; CHECK-NEXT: call i8* @llvm.objc.autorelease(i8* %x)
; CHECK-NEXT: br label %next
; CHECK: next:
; CHECK-NEXT: tail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(
; CHECK-NEXT: ret i8*
define i8* @elide_with_claimRV_wrongBB(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
br label %next
next:
%c = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_claimRV_beforeAutoreleaseRV(
; CHECK-NEXT: entry:
; CHECK-NEXT: tail call void @llvm.objc.release(i8* %x)
; CHECK-NEXT: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %x)
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_claimRV_beforeAutoreleaseRV(i8* %x) nounwind {
entry:
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %x) nounwind
%c = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
%d = call i8* @llvm.objc.autoreleaseReturnValue(i8* %c) nounwind
ret i8* %c
}
; CHECK-LABEL: define i8* @elide_with_claimRV_afterRetain(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i8* %x
define i8* @elide_with_claimRV_afterRetain(i8* %x) nounwind {
entry:
%a = call i8* @llvm.objc.retain(i8* %x) nounwind
%b = call i8* @llvm.objc.autoreleaseReturnValue(i8* %a) nounwind
%c = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %b) nounwind
ret i8* %c
}