llvm-6502/test/Transforms/ObjCARC/tail-call-invariant-enforcement.ll
Michael Gottesman a67a20c95f Remove an optimization where we were changing an objc_autorelease into an objc_autoreleaseReturnValue.
The semantics of ARC implies that a pointer passed into an objc_autorelease
must live until some point (potentially down the stack) where an
autorelease pool is popped. On the other hand, an
objc_autoreleaseReturnValue just signifies that the object must live
until the end of the given function at least.

Thus objc_autorelease is stronger than objc_autoreleaseReturnValue in
terms of the semantics of ARC* implying that performing the given
strength reduction without any knowledge of how this relates to
the autorelease pool pop that is further up the stack violates the
semantics of ARC.

*Even though objc_autoreleaseReturnValue if you know that no RV
optimization will occur is more computationally expensive.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178612 91177308-0d34-0410-b5e6-96231b3b80d8
2013-04-03 02:57:24 +00:00

75 lines
2.2 KiB
LLVM

; RUN: opt -objc-arc -S < %s | FileCheck %s
declare i8* @objc_release(i8* %x)
declare i8* @objc_retain(i8* %x)
declare i8* @objc_autorelease(i8* %x)
declare i8* @objc_autoreleaseReturnValue(i8* %x)
declare i8* @objc_retainAutoreleasedReturnValue(i8* %x)
; Never tail call objc_autorelease.
define i8* @test0(i8* %x) {
entry:
; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x)
%tmp0 = call i8* @objc_autorelease(i8* %x)
; CHECK: %tmp1 = call i8* @objc_autorelease(i8* %x)
%tmp1 = tail call i8* @objc_autorelease(i8* %x)
ret i8* %x
}
; Always tail call autoreleaseReturnValue.
define i8* @test1(i8* %x) {
entry:
; CHECK: %tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
%tmp0 = call i8* @objc_autoreleaseReturnValue(i8* %x)
; CHECK: %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
%tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
ret i8* %x
}
; Always tail call objc_retain.
define i8* @test2(i8* %x) {
entry:
; CHECK: %tmp0 = tail call i8* @objc_retain(i8* %x)
%tmp0 = call i8* @objc_retain(i8* %x)
; CHECK: %tmp1 = tail call i8* @objc_retain(i8* %x)
%tmp1 = tail call i8* @objc_retain(i8* %x)
ret i8* %x
}
define i8* @tmp(i8* %x) {
ret i8* %x
}
; Always tail call objc_retainAutoreleasedReturnValue.
define i8* @test3(i8* %x) {
entry:
%y = call i8* @tmp(i8* %x)
; CHECK: %tmp0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
%tmp0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
%z = call i8* @tmp(i8* %x)
; CHECK: %tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
%tmp1 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %z)
ret i8* %x
}
; By itself, we should never change whether or not objc_release is tail called.
define i8* @test4(i8* %x) {
entry:
; CHECK: %tmp0 = call i8* @objc_release(i8* %x)
%tmp0 = call i8* @objc_release(i8* %x)
; CHECK: %tmp1 = tail call i8* @objc_release(i8* %x)
%tmp1 = tail call i8* @objc_release(i8* %x)
ret i8* %x
}
; If we convert a tail called @objc_autoreleaseReturnValue to an
; @objc_autorelease, ensure that the tail call is removed.
define i8* @test5(i8* %x) {
entry:
; CHECK: %tmp0 = call i8* @objc_autorelease(i8* %x)
%tmp0 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
ret i8* %tmp0
}