Fixed a bug where we were tail calling objc_autorelease causing an object to not...
[oota-llvm.git] / lib / Transforms / Scalar / ObjCARC.cpp
index c840e6e4c8c481016e4f20912b72830c7bbd968d..1607e8e80a5d5b6d58e3f77144048a6f8dd8acae 100644 (file)
@@ -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) {
@@ -886,9 +896,9 @@ bool ObjCARCExpand::runOnFunction(Function &F) {
 
   for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
     Instruction *Inst = &*I;
-    
+
     DEBUG(dbgs() << "ObjCARCExpand: Visiting: " << *Inst << "\n");
-    
+
     switch (GetBasicInstructionClass(Inst)) {
     case IC_Retain:
     case IC_RetainRV:
@@ -911,9 +921,9 @@ bool ObjCARCExpand::runOnFunction(Function &F) {
       break;
     }
   }
-  
+
   DEBUG(dbgs() << "ObjCARCExpand: Finished List.\n\n");
-  
+
   return Changed;
 }
 
@@ -2199,13 +2209,13 @@ ObjCARCOpt::OptimizeRetainCall(Function &F, Instruction *Retain) {
   // Turn it to an objc_retainAutoreleasedReturnValue..
   Changed = true;
   ++NumPeeps;
-  
+
   DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainCall: Transforming "
                   "objc_retainAutoreleasedReturnValue => "
                   "objc_retain since the operand is not a return value.\n"
                   "                                Old: "
                << *Retain << "\n");
-  
+
   cast<CallInst>(Retain)->setCalledFunction(getRetainRVCallee(F.getParent()));
 
   DEBUG(dbgs() << "                                New: "
@@ -2247,11 +2257,11 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
         GetObjCArg(I) == Arg) {
       Changed = true;
       ++NumPeeps;
-      
+
       DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainRVCall: Erasing " << *I << "\n"
                    << "                                  Erasing " << *RetainRV
                    << "\n");
-      
+
       EraseInstruction(I);
       EraseInstruction(RetainRV);
       return true;
@@ -2261,13 +2271,13 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
   // Turn it to a plain objc_retain.
   Changed = true;
   ++NumPeeps;
-  
+
   DEBUG(dbgs() << "ObjCARCOpt::OptimizeRetainRVCall: Transforming "
                   "objc_retainAutoreleasedReturnValue => "
                   "objc_retain since the operand is not a return value.\n"
                   "                                  Old: "
                << *RetainRV << "\n");
-  
+
   cast<CallInst>(RetainRV)->setCalledFunction(getRetainCallee(F.getParent()));
 
   DEBUG(dbgs() << "                                  New: "
@@ -2306,12 +2316,14 @@ 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");
-  
+
 }
 
 /// OptimizeIndividualCalls - Visit each call, one at a time, and make
@@ -2361,12 +2373,12 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
         new StoreInst(UndefValue::get(cast<PointerType>(Ty)->getElementType()),
                       Constant::getNullValue(Ty),
                       CI);
-        llvm::Value *NewValue = UndefValue::get(CI->getType());        
+        llvm::Value *NewValue = UndefValue::get(CI->getType());
         DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: A null "
                         "pointer-to-weak-pointer is undefined behavior.\n"
                         "                                     Old = " << *CI <<
                         "\n                                     New = " <<
-                        *NewValue << "\n");        
+                        *NewValue << "\n");
         CI->replaceAllUsesWith(NewValue);
         CI->eraseFromParent();
         continue;
@@ -2390,7 +2402,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
                         "                                     Old = " << *CI <<
                         "\n                                     New = " <<
                         *NewValue << "\n");
-        
+
         CI->replaceAllUsesWith(NewValue);
         CI->eraseFromParent();
         continue;
@@ -2425,14 +2437,14 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
                            Call->getArgOperand(0), "", Call);
         NewCall->setMetadata(ImpreciseReleaseMDKind,
                              MDNode::get(C, ArrayRef<Value *>()));
-        
+
         DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Replacing "
                         "objc_autorelease(x) with objc_release(x) since x is "
                         "otherwise unused.\n"
                         "                                     Old: " << *Call <<
                         "\n                                     New: " <<
                         *NewCall << "\n");
-        
+
         EraseInstruction(Call);
         Inst = NewCall;
         Class = IC_Release;
@@ -2449,9 +2461,21 @@ 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;
+      DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Found no throw"
+            " class. Setting nounwind on: " << *Inst << "\n");
       cast<CallInst>(Inst)->setDoesNotThrow();
     }
 
@@ -2466,6 +2490,8 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
     if (isNullOrUndef(Arg)) {
       Changed = true;
       ++NumNoops;
+      DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: ARC calls with "
+            " null are no-ops. Erasing: " << *Inst << "\n");
       EraseInstruction(Inst);
       continue;
     }
@@ -2558,10 +2584,16 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
                 Op = new BitCastInst(Op, ParamTy, "", InsertPos);
               Clone->setArgOperand(0, Op);
               Clone->insertBefore(InsertPos);
+
+              DEBUG(dbgs() << "ObjCARCOpt::OptimizeIndividualCalls: Cloning "
+                           << *CInst << "\n"
+                           "                                     And inserting "
+                           "clone at " << *InsertPos << "\n");
               Worklist.push_back(std::make_pair(Clone, Incoming));
             }
           }
           // Erase the original call.
+          DEBUG(dbgs() << "Erasing: " << *CInst << "\n");
           EraseInstruction(CInst);
           continue;
         }
@@ -3222,6 +3254,11 @@ void ObjCARCOpt::MoveCalls(Value *Arg,
                         MDNode::get(M->getContext(), ArrayRef<Value *>()));
     else
       Call->setTailCall();
+
+    DEBUG(dbgs() << "ObjCARCOpt::MoveCalls: Inserting new Release: " << *Call
+                 << "\n"
+                    "                       At insertion point: " << *InsertPt
+                 << "\n");
   }
   for (SmallPtrSet<Instruction *, 2>::const_iterator
        PI = RetainsToMove.ReverseInsertPts.begin(),
@@ -3237,6 +3274,11 @@ void ObjCARCOpt::MoveCalls(Value *Arg,
     Call->setDoesNotThrow();
     if (ReleasesToMove.IsTailCallRelease)
       Call->setTailCall();
+
+    DEBUG(dbgs() << "ObjCARCOpt::MoveCalls: Inserting new Retain: " << *Call
+                 << "\n"
+                    "                       At insertion point: " << *InsertPt
+                 << "\n");
   }
 
   // Delete the original retain and release calls.
@@ -3246,6 +3288,8 @@ void ObjCARCOpt::MoveCalls(Value *Arg,
     Instruction *OrigRetain = *AI;
     Retains.blot(OrigRetain);
     DeadInsts.push_back(OrigRetain);
+    DEBUG(dbgs() << "ObjCARCOpt::MoveCalls: Deleting retain: " << *OrigRetain <<
+                    "\n");
   }
   for (SmallPtrSet<Instruction *, 2>::const_iterator
        AI = ReleasesToMove.Calls.begin(),
@@ -3253,6 +3297,8 @@ void ObjCARCOpt::MoveCalls(Value *Arg,
     Instruction *OrigRelease = *AI;
     Releases.erase(OrigRelease);
     DeadInsts.push_back(OrigRelease);
+    DEBUG(dbgs() << "ObjCARCOpt::MoveCalls: Deleting release: " << *OrigRelease
+                 << "\n");
   }
 }
 
@@ -3278,6 +3324,10 @@ ObjCARCOpt::PerformCodePlacement(DenseMap<const BasicBlock *, BBState>
     if (!V) continue; // blotted
 
     Instruction *Retain = cast<Instruction>(V);
+
+    DEBUG(dbgs() << "ObjCARCOpt::PerformCodePlacement: Visiting: " << *Retain
+          << "\n");
+
     Value *Arg = GetObjCArg(Retain);
 
     // If the object being released is in static or stack storage, we know it's
@@ -3622,9 +3672,9 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
     done:;
     }
   }
-  
+
   DEBUG(dbgs() << "ObjCARCOpt::OptimizeWeakCalls: Finished List.\n\n");
-  
+
 }
 
 /// OptimizeSequences - Identify program paths which execute sequences of
@@ -3721,7 +3771,14 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
         // 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;
         }
 
@@ -3749,6 +3806,9 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
           // If so, we can zap the retain and autorelease.
           Changed = true;
           ++NumRets;
+          DEBUG(dbgs() << "ObjCARCOpt::OptimizeReturns: Erasing: " << *Retain
+                       << "\n                             Erasing: "
+                       << *Autorelease << "\n");
           EraseInstruction(Retain);
           EraseInstruction(Autorelease);
         }
@@ -3759,9 +3819,9 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
     DependingInstructions.clear();
     Visited.clear();
   }
-  
+
   DEBUG(dbgs() << "ObjCARCOpt::OptimizeReturns: Finished List.\n\n");
-  
+
 }
 
 bool ObjCARCOpt::doInitialization(Module &M) {
@@ -4021,11 +4081,19 @@ ObjCARCContract::ContractAutorelease(Function &F, Instruction *Autorelease,
   Changed = true;
   ++NumPeeps;
 
+  DEBUG(dbgs() << "ObjCARCContract::ContractAutorelease: Fusing "
+                  "retain/autorelease. Erasing: " << *Autorelease << "\n"
+                  "                                      Old Retain: "
+               << *Retain << "\n");
+
   if (Class == IC_AutoreleaseRV)
     Retain->setCalledFunction(getRetainAutoreleaseRVCallee(F.getParent()));
   else
     Retain->setCalledFunction(getRetainAutoreleaseCallee(F.getParent()));
 
+  DEBUG(dbgs() << "                                      New Retain: "
+               << *Retain << "\n");
+
   EraseInstruction(Autorelease);
   return true;
 }
@@ -4175,9 +4243,9 @@ bool ObjCARCContract::runOnFunction(Function &F) {
   SmallPtrSet<const BasicBlock *, 4> Visited;
   for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
     Instruction *Inst = &*I++;
-    
+
     DEBUG(dbgs() << "ObjCARCContract: Visiting: " << *Inst << "\n");
-    
+
     // Only these library routines return their argument. In particular,
     // objc_retainBlock does not necessarily return its argument.
     InstructionClass Class = GetBasicInstructionClass(Inst);
@@ -4236,10 +4304,10 @@ bool ObjCARCContract::runOnFunction(Function &F) {
           ConstantPointerNull::get(cast<PointerType>(CI->getType()));
         Changed = true;
         new StoreInst(Null, CI->getArgOperand(0), CI);
-        
+
         DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n"
                      << "                 New = " << *Null << "\n");
-        
+
         CI->replaceAllUsesWith(Null);
         CI->eraseFromParent();
       }