diff options
Diffstat (limited to 'llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp')
| -rw-r--r-- | llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 73 | 
1 files changed, 58 insertions, 15 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index b80c1675050b..cb1fa804fa11 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -43,7 +43,6 @@  #include "llvm/Analysis/ObjCARCInstKind.h"  #include "llvm/IR/BasicBlock.h"  #include "llvm/IR/CFG.h" -#include "llvm/IR/CallSite.h"  #include "llvm/IR/Constant.h"  #include "llvm/IR/Constants.h"  #include "llvm/IR/DerivedTypes.h" @@ -610,8 +609,7 @@ bool  ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {    // Check for the argument being from an immediately preceding call or invoke.    const Value *Arg = GetArgRCIdentityRoot(RetainRV); -  ImmutableCallSite CS(Arg); -  if (const Instruction *Call = CS.getInstruction()) { +  if (const Instruction *Call = dyn_cast<CallBase>(Arg)) {      if (Call->getParent() == RetainRV->getParent()) {        BasicBlock::const_iterator I(Call);        ++I; @@ -678,6 +676,7 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(    // Delete the RV pair, starting with the AutoreleaseRV.    AutoreleaseRV->replaceAllUsesWith(        cast<CallInst>(AutoreleaseRV)->getArgOperand(0)); +  Changed = true;    EraseInstruction(AutoreleaseRV);    if (Class == ARCInstKind::RetainRV) {      // AutoreleaseRV and RetainRV cancel out.  Delete the RetainRV. @@ -877,23 +876,49 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {    optimizeDelayedAutoreleaseRV();  } +/// This function returns true if the value is inert. An ObjC ARC runtime call +/// taking an inert operand can be safely deleted. +static bool isInertARCValue(Value *V, SmallPtrSet<Value *, 1> &VisitedPhis) { +  V = V->stripPointerCasts(); + +  if (IsNullOrUndef(V)) +    return true; + +  // See if this is a global attribute annotated with an 'objc_arc_inert'. +  if (auto *GV = dyn_cast<GlobalVariable>(V)) +    if (GV->hasAttribute("objc_arc_inert")) +      return true; + +  if (auto PN = dyn_cast<PHINode>(V)) { +    // Ignore this phi if it has already been discovered. +    if (!VisitedPhis.insert(PN).second) +      return true; +    // Look through phis's operands. +    for (Value *Opnd : PN->incoming_values()) +      if (!isInertARCValue(Opnd, VisitedPhis)) +        return false; +    return true; +  } + +  return false; +} +  void ObjCARCOpt::OptimizeIndividualCallImpl(      Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,      Instruction *Inst, ARCInstKind Class, const Value *Arg) {    LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n"); -  // Some of the ARC calls can be deleted if their arguments are global -  // variables that are inert in ARC. -  if (IsNoopOnGlobal(Class)) { -    Value *Opnd = Inst->getOperand(0); -    if (auto *GV = dyn_cast<GlobalVariable>(Opnd->stripPointerCasts())) -      if (GV->hasAttribute("objc_arc_inert")) { -        if (!Inst->getType()->isVoidTy()) -          Inst->replaceAllUsesWith(Opnd); -        Inst->eraseFromParent(); -        return; -      } -  } +  // We can delete this call if it takes an inert value. +  SmallPtrSet<Value *, 1> VisitedPhis; + +  if (IsNoopOnGlobal(Class)) +    if (isInertARCValue(Inst->getOperand(0), VisitedPhis)) { +      if (!Inst->getType()->isVoidTy()) +        Inst->replaceAllUsesWith(Inst->getOperand(0)); +      Inst->eraseFromParent(); +      Changed = true; +      return; +    }    switch (Class) {    default: @@ -1544,6 +1569,15 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,      }    } +  // Check that BB and MyStates have the same number of predecessors. This +  // prevents retain calls that live outside a loop from being moved into the +  // loop. +  if (!BB->hasNPredecessors(MyStates.pred_end() - MyStates.pred_begin())) +    for (auto I = MyStates.top_down_ptr_begin(), +              E = MyStates.top_down_ptr_end(); +         I != E; ++I) +      I->second.SetCFGHazardAfflicted(true); +    LLVM_DEBUG(dbgs() << "Before:\n"                      << BBStates[BB] << "\n"                      << "Performing Dataflow:\n"); @@ -2020,6 +2054,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {      // Delete objc_loadWeak calls with no users.      if (Class == ARCInstKind::LoadWeak && Inst->use_empty()) {        Inst->eraseFromParent(); +      Changed = true;        continue;      } @@ -2310,6 +2345,14 @@ 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 (HasSafePathToCall && +        GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV && +        GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV && +        !cast<CallInst>(*DependingInstructions.begin())->isTailCall()) +      continue; +      DependingInstructions.clear();      Visited.clear();  | 
