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(); |