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
This commit is contained in:
Michael Gottesman 2013-04-03 02:57:24 +00:00
parent 003d5f946d
commit a67a20c95f
4 changed files with 9 additions and 32 deletions

View File

@ -1440,8 +1440,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
break; break;
} }
// objc_autorelease(x), objc_autoreleaseRV -> objc_release(x) if x is // objc_autorelease(x) -> objc_release(x) if x is otherwise unused.
// otherwise unused.
if (IsAutorelease(Class) && Inst->use_empty()) { if (IsAutorelease(Class) && Inst->use_empty()) {
CallInst *Call = cast<CallInst>(Inst); CallInst *Call = cast<CallInst>(Inst);
const Value *Arg = Call->getArgOperand(0); const Value *Arg = Call->getArgOperand(0);
@ -2861,20 +2860,6 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
DependingInstructions.clear(); DependingInstructions.clear();
Visited.clear(); Visited.clear();
// Convert the autorelease to an autoreleaseRV, since it's
// returning the value.
if (AutoreleaseClass == IC_Autorelease) {
DEBUG(dbgs() << "ObjCARCOpt::OptimizeReturns: Converting autorelease "
"=> autoreleaseRV since it's returning a value.\n"
" In: " << *Autorelease
<< "\n");
Autorelease->setCalledFunction(getAutoreleaseRVCallee(F.getParent()));
DEBUG(dbgs() << " Out: " << *Autorelease
<< "\n");
Autorelease->setTailCall(); // Always tail call autoreleaseRV.
AutoreleaseClass = IC_AutoreleaseRV;
}
// Check that there is nothing that can affect the reference // Check that there is nothing that can affect the reference
// count between the retain and the call. // count between the retain and the call.
// Note that Retain need not be in BB. // Note that Retain need not be in BB.

View File

@ -428,11 +428,13 @@ entry:
ret void ret void
} }
; Same as test11 but the value is returned. Do an RV optimization. ; Same as test11 but the value is returned. Do not perform an RV optimization
; since if the frontend emitted code for an __autoreleasing variable, we may
; want it to be in the autorelease pool.
; CHECK: define i8* @test11b( ; CHECK: define i8* @test11b(
; CHECK: tail call i8* @objc_retain(i8* %x) [[NUW]] ; CHECK: tail call i8* @objc_retain(i8* %x) [[NUW]]
; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %0) [[NUW]] ; CHECK: call i8* @objc_autorelease(i8* %0) [[NUW]]
; CHECK: } ; CHECK: }
define i8* @test11b(i8* %x) nounwind { define i8* @test11b(i8* %x) nounwind {
entry: entry:

View File

@ -121,7 +121,7 @@ define i8* @test7() {
%p = call i8* @returner() %p = call i8* @returner()
call i8* @objc_retainAutoreleasedReturnValue(i8* %p) call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
%t = call i8* @objc_autoreleaseReturnValue(i8* %p) %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
call void @use_pointer(i8* %t) call void @use_pointer(i8* %p)
ret i8* %t ret i8* %t
} }
@ -133,7 +133,7 @@ define i8* @test7b() {
call void @use_pointer(i8* %p) call void @use_pointer(i8* %p)
call i8* @objc_retainAutoreleasedReturnValue(i8* %p) call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
%t = call i8* @objc_autoreleaseReturnValue(i8* %p) %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
ret i8* %t ret i8* %p
} }
; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
@ -156,11 +156,11 @@ define i8* @test9(i8* %p) {
ret i8* %p ret i8* %p
} }
; Apply the RV optimization. ; Do not apply the RV optimization.
; CHECK: define i8* @test10(i8* %p) ; CHECK: define i8* @test10(i8* %p)
; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]] ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) [[NUW]] ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]]
; CHECK-NEXT: ret i8* %p ; CHECK-NEXT: ret i8* %p
define i8* @test10(i8* %p) { define i8* @test10(i8* %p) {
%1 = call i8* @objc_retain(i8* %p) %1 = call i8* @objc_retain(i8* %p)

View File

@ -72,13 +72,3 @@ entry:
ret i8* %tmp0 ret i8* %tmp0
} }
; If we convert a called @objc_autorelease to an @objc_autoreleaseReturnValue,
; ensure that the tail call is added.
define i8* @test6(i8* %x) {
entry:
; CHECK: %tmp0 = tail call i8* @objc_retain(i8* %x)
%tmp0 = tail call i8* @objc_retain(i8* %x)
; CHECK: %tmp1 = tail call i8* @objc_autoreleaseReturnValue(i8* %x)
%tmp1 = call i8* @objc_autorelease(i8* %x)
ret i8* %x
}