diff options
author | ahatanak <ahatanaka@apple.com> | 2020-03-09 13:20:58 -0700 |
---|---|---|
committer | ahatanak <ahatanaka@apple.com> | 2020-03-09 13:21:38 -0700 |
commit | 1f5b471b8bf4c6d22fb13d8e24bc31c75245b0d0 (patch) | |
tree | 13460a58da076553b71d5ccb20fb121bf5270c6b /llvm | |
parent | a50c031fab6747438af1454354ab85123558f6aa (diff) | |
download | llvm-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.cpp | 9 | ||||
-rw-r--r-- | llvm/test/Transforms/ObjCARC/rv.ll | 16 |
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 } |