summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
authorMichael Gottesman <mgottesman@apple.com>2013-01-12 01:25:15 +0000
committerMichael Gottesman <mgottesman@apple.com>2013-01-12 01:25:15 +0000
commitc9656faf1e73998b0ca0f0aff6652fec69c02c64 (patch)
tree234b8723a4012673e6580cce670537e3d4534ea2 /llvm/lib/Transforms
parente274088db052f89254a050c3f255bad9f92ddea5 (diff)
downloadbcm5719-llvm-c9656faf1e73998b0ca0f0aff6652fec69c02c64.tar.gz
bcm5719-llvm-c9656faf1e73998b0ca0f0aff6652fec69c02c64.zip
Fixed a bug where we were tail calling objc_autorelease causing an object to not be placed into an autorelease pool.
The reason that this occurs is that tail calling objc_autorelease eventually tail calls -[NSObject autorelease] which supports fast autorelease. This can cause us to violate the semantic gaurantees of __autoreleasing variables that assignment to an __autoreleasing variables always yields an object that is placed into the innermost autorelease pool. The fix included in this patch works by: 1. In the peephole optimization function OptimizeIndividualFunctions, always remove tail call from objc_autorelease. 2. Whenever we convert to/from an objc_autorelease, set/unset the tail call keyword as appropriate. *NOTE* I also handled the case where objc_autorelease is converted in OptimizeReturns to an autoreleaseRV which still violates the ARC semantics. I will be removing that in a later patch and I wanted to make sure that the tree is in a consistent state vis-a-vis ARC always. Additionally some test cases are provided and all tests that have tail call marked objc_autorelease keywords have been modified so that tail call has been removed. *NOTE* One test fails due to a separate bug that I am going to commit soon. Thus I marked the check line TMP: instead of CHECK: so make check does not fail. llvm-svn: 172287
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/Scalar/ObjCARC.cpp27
1 files changed, 25 insertions, 2 deletions
diff --git a/llvm/lib/Transforms/Scalar/ObjCARC.cpp b/llvm/lib/Transforms/Scalar/ObjCARC.cpp
index 34700ebb02c..1607e8e80a5 100644
--- a/llvm/lib/Transforms/Scalar/ObjCARC.cpp
+++ b/llvm/lib/Transforms/Scalar/ObjCARC.cpp
@@ -426,10 +426,20 @@ static bool IsAlwaysTail(InstructionClass Class) {
// IC_RetainBlock may be given a stack argument.
return Class == IC_Retain ||
Class == IC_RetainRV ||
- Class == IC_Autorelease ||
Class == IC_AutoreleaseRV;
}
+/// \brief Test if the given class represents instructions which are never safe
+/// to mark with the "tail" keyword.
+static bool IsNeverTail(InstructionClass Class) {
+ /// It is never safe to tail call objc_autorelease since by tail calling
+ /// objc_autorelease, we also tail call -[NSObject autorelease] which supports
+ /// fast autoreleasing causing our object to be potentially reclaimed from the
+ /// autorelease pool which violates the semantics of __autoreleasing types in
+ /// ARC.
+ return Class == IC_Autorelease;
+}
+
/// IsNoThrow - Test if the given class represents instructions which are always
/// safe to mark with the nounwind attribute..
static bool IsNoThrow(InstructionClass Class) {
@@ -2306,8 +2316,10 @@ ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV) {
" Old: "
<< *AutoreleaseRV << "\n");
- cast<CallInst>(AutoreleaseRV)->
+ CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV);
+ AutoreleaseRVCI->
setCalledFunction(getAutoreleaseCallee(F.getParent()));
+ AutoreleaseRVCI->setTailCall(false); // Never tail call objc_autorelease.
DEBUG(dbgs() << " New: "
<< *AutoreleaseRV << "\n");
@@ -2449,6 +2461,16 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
cast<CallInst>(Inst)->setTailCall();
}
+ // Ensure that functions that can never have a "tail" keyword due to the
+ // semantics of ARC truly do not do so.
+ if (IsNeverTail(Class)) {
+ Changed = true;
+ DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Removing tail keyword"
+ " from function: " << *Inst <<
+ "\n");
+ cast<CallInst>(Inst)->setTailCall(false);
+ }
+
// Set nounwind as needed.
if (IsNoThrow(Class)) {
Changed = true;
@@ -3756,6 +3778,7 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
Autorelease->setCalledFunction(getAutoreleaseRVCallee(F.getParent()));
DEBUG(dbgs() << " Out: " << *Autorelease
<< "\n");
+ Autorelease->setTailCall(); // Always tail call autoreleaseRV.
AutoreleaseClass = IC_AutoreleaseRV;
}
OpenPOWER on IntegriCloud