aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorahatanak <ahatanaka@apple.com>2020-03-09 13:20:58 -0700
committerahatanak <ahatanaka@apple.com>2020-03-09 13:21:38 -0700
commit1f5b471b8bf4c6d22fb13d8e24bc31c75245b0d0 (patch)
tree13460a58da076553b71d5ccb20fb121bf5270c6b /llvm
parenta50c031fab6747438af1454354ab85123558f6aa (diff)
downloadllvm-1f5b471b8bf4c6d22fb13d8e24bc31c75245b0d0.zip
llvm-1f5b471b8bf4c6d22fb13d8e24bc31c75245b0d0.tar.gz
llvm-1f5b471b8bf4c6d22fb13d8e24bc31c75245b0d0.tar.bz2
[ObjC][ARC] Don't remove autoreleaseRV/retainRV pairs if the call isn't
a tail call Previosly ARC optimizer removed the autoreleaseRV/retainRV pair in the following code, which caused the object returned by @something to be placed in the autorelease pool because the call to @something isn't a tail call: ``` %call = call i8* @something(...) %2 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) %3 = call i8* @objc_autoreleaseReturnValue(i8* %2) ret i8* %3 ``` Fix the bug by checking whether @something is a tail call. rdar://problem/59275894
Diffstat (limited to 'llvm')
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp9
-rw-r--r--llvm/test/Transforms/ObjCARC/rv.ll16
2 files changed, 23 insertions, 2 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 577a744..9a029cc 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -2296,7 +2296,7 @@ FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB,
/// Look for this pattern:
/// \code
-/// %call = call i8* @something(...)
+/// %call = tail call i8* @something(...)
/// %2 = call i8* @objc_retain(i8* %call)
/// %3 = call i8* @objc_autorelease(i8* %2)
/// ret i8* %3
@@ -2344,6 +2344,13 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain,
DependingInstructions,
Visited, PA);
+
+ // Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call.
+ if (GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV &&
+ GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV &&
+ !cast<CallInst>(*DependingInstructions.begin())->isTailCall())
+ continue;
+
DependingInstructions.clear();
Visited.clear();
diff --git a/llvm/test/Transforms/ObjCARC/rv.ll b/llvm/test/Transforms/ObjCARC/rv.ll
index 3d0d56c..ea06b38 100644
--- a/llvm/test/Transforms/ObjCARC/rv.ll
+++ b/llvm/test/Transforms/ObjCARC/rv.ll
@@ -77,7 +77,7 @@ define void @test2() {
; CHECK-NEXT: ret i8* %call
define i8* @test3() {
entry:
- %call = call i8* @returner()
+ %call = tail call i8* @returner()
%0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
%1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
ret i8* %1
@@ -387,6 +387,20 @@ bb3:
ret i32* %retval
}
+; Don't eliminate the retainRV/autoreleaseRV pair if the call isn't a tail call.
+
+; CHECK-LABEL: define i8* @test28(
+; CHECK: call i8* @returner()
+; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(
+; CHECK: call i8* @llvm.objc.autoreleaseReturnValue(
+define i8* @test28() {
+entry:
+ %call = call i8* @returner()
+ %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
+ %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
+ ret i8* %1
+}
+
!0 = !{}
; CHECK: attributes [[NUW]] = { nounwind }