diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Transforms/ObjCARC | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'lib/Transforms/ObjCARC')
-rw-r--r-- | lib/Transforms/ObjCARC/BlotMapVector.h | 2 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/DependencyAnalysis.h | 2 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ObjCARC.h | 24 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ObjCARCAPElim.cpp | 12 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ObjCARCContract.cpp | 177 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ObjCARCExpand.cpp | 15 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 202 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp | 15 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/ProvenanceAnalysis.h | 6 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/PtrState.cpp | 45 | ||||
-rw-r--r-- | lib/Transforms/ObjCARC/PtrState.h | 6 |
11 files changed, 327 insertions, 179 deletions
diff --git a/lib/Transforms/ObjCARC/BlotMapVector.h b/lib/Transforms/ObjCARC/BlotMapVector.h index 5518b49c4095..9ade14c1177a 100644 --- a/lib/Transforms/ObjCARC/BlotMapVector.h +++ b/lib/Transforms/ObjCARC/BlotMapVector.h @@ -18,7 +18,7 @@ namespace llvm { -/// \brief An associative container with fast insertion-order (deterministic) +/// An associative container with fast insertion-order (deterministic) /// iteration over its elements. Plus the special blot operation. template <class KeyT, class ValueT> class BlotMapVector { /// Map keys to indices in Vector. diff --git a/lib/Transforms/ObjCARC/DependencyAnalysis.h b/lib/Transforms/ObjCARC/DependencyAnalysis.h index 8cc1232b18ca..0f13b02c806f 100644 --- a/lib/Transforms/ObjCARC/DependencyAnalysis.h +++ b/lib/Transforms/ObjCARC/DependencyAnalysis.h @@ -38,7 +38,7 @@ namespace objcarc { class ProvenanceAnalysis; /// \enum DependenceKind -/// \brief Defines different dependence kinds among various ARC constructs. +/// Defines different dependence kinds among various ARC constructs. /// /// There are several kinds of dependence-like concepts in use here. /// diff --git a/lib/Transforms/ObjCARC/ObjCARC.h b/lib/Transforms/ObjCARC/ObjCARC.h index cd9b3d96a14f..1dbe72c7569f 100644 --- a/lib/Transforms/ObjCARC/ObjCARC.h +++ b/lib/Transforms/ObjCARC/ObjCARC.h @@ -28,13 +28,13 @@ #include "llvm/Analysis/ObjCARCAnalysisUtils.h" #include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/Analysis/Passes.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Transforms/ObjCARC.h" -#include "llvm/Transforms/Utils/Local.h" namespace llvm { class raw_ostream; @@ -43,7 +43,7 @@ class raw_ostream; namespace llvm { namespace objcarc { -/// \brief Erase the given instruction. +/// Erase the given instruction. /// /// Many ObjC calls return their argument verbatim, /// so if it's such a call and the return value has users, replace them with the @@ -82,6 +82,26 @@ static inline const Instruction *getreturnRVOperand(const Instruction &Inst, return dyn_cast<InvokeInst>(Opnd); } +/// Return the list of PHI nodes that are equivalent to PN. +template<class PHINodeTy, class VectorTy> +void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList) { + auto *BB = PN.getParent(); + for (auto &P : BB->phis()) { + if (&P == &PN) // Do not add PN to the list. + continue; + unsigned I = 0, E = PN.getNumIncomingValues(); + for (; I < E; ++I) { + auto *BB = PN.getIncomingBlock(I); + auto *PNOpnd = PN.getIncomingValue(I)->stripPointerCasts(); + auto *POpnd = P.getIncomingValueForBlock(BB)->stripPointerCasts(); + if (PNOpnd != POpnd) + break; + } + if (I == E) + PHIList.push_back(&P); + } +} + } // end namespace objcarc } // end namespace llvm diff --git a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp index b2c62a0e8eeb..8d3ef8fde534 100644 --- a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp @@ -36,7 +36,7 @@ using namespace llvm::objcarc; #define DEBUG_TYPE "objc-arc-ap-elim" namespace { - /// \brief Autorelease pool elimination. + /// Autorelease pool elimination. class ObjCARCAPElim : public ModulePass { void getAnalysisUsage(AnalysisUsage &AU) const override; bool runOnModule(Module &M) override; @@ -103,10 +103,12 @@ bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) { // zap the pair. if (Push && cast<CallInst>(Inst)->getArgOperand(0) == Push) { Changed = true; - DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop " - "autorelease pair:\n" - " Pop: " << *Inst << "\n" - << " Push: " << *Push << "\n"); + LLVM_DEBUG(dbgs() << "ObjCARCAPElim::OptimizeBB: Zapping push pop " + "autorelease pair:\n" + " Pop: " + << *Inst << "\n" + << " Push: " << *Push + << "\n"); Inst->eraseFromParent(); Push->eraseFromParent(); } diff --git a/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/lib/Transforms/ObjCARC/ObjCARCContract.cpp index c4e61218f3f3..1f1ea9f58739 100644 --- a/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -31,6 +31,7 @@ #include "ObjCARC.h" #include "ProvenanceAnalysis.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/EHPersonalities.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Operator.h" @@ -50,7 +51,7 @@ STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed"); //===----------------------------------------------------------------------===// namespace { - /// \brief Late ARC optimizations + /// Late ARC optimizations /// /// These change the IR in a way that makes it difficult to be analyzed by /// ObjCARCOpt, so it's run late. @@ -74,11 +75,12 @@ namespace { SmallPtrSet<CallInst *, 8> StoreStrongCalls; /// Returns true if we eliminated Inst. - bool tryToPeepholeInstruction(Function &F, Instruction *Inst, - inst_iterator &Iter, - SmallPtrSetImpl<Instruction *> &DepInsts, - SmallPtrSetImpl<const BasicBlock *> &Visited, - bool &TailOkForStoreStrong); + bool tryToPeepholeInstruction( + Function &F, Instruction *Inst, inst_iterator &Iter, + SmallPtrSetImpl<Instruction *> &DepInsts, + SmallPtrSetImpl<const BasicBlock *> &Visited, + bool &TailOkForStoreStrong, + const DenseMap<BasicBlock *, ColorVector> &BlockColors); bool optimizeRetainCall(Function &F, Instruction *Retain); @@ -88,8 +90,9 @@ namespace { SmallPtrSetImpl<Instruction *> &DependingInstructions, SmallPtrSetImpl<const BasicBlock *> &Visited); - void tryToContractReleaseIntoStoreStrong(Instruction *Release, - inst_iterator &Iter); + void tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap<BasicBlock *, ColorVector> &BlockColors); void getAnalysisUsage(AnalysisUsage &AU) const override; bool doInitialization(Module &M) override; @@ -129,16 +132,18 @@ bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) { Changed = true; ++NumPeeps; - DEBUG(dbgs() << "Transforming objc_retain => " - "objc_retainAutoreleasedReturnValue since the operand is a " - "return value.\nOld: "<< *Retain << "\n"); + LLVM_DEBUG( + dbgs() << "Transforming objc_retain => " + "objc_retainAutoreleasedReturnValue since the operand is a " + "return value.\nOld: " + << *Retain << "\n"); // We do not have to worry about tail calls/does not throw since // retain/retainRV have the same properties. Constant *Decl = EP.get(ARCRuntimeEntryPointKind::RetainRV); cast<CallInst>(Retain)->setCalledFunction(Decl); - DEBUG(dbgs() << "New: " << *Retain << "\n"); + LLVM_DEBUG(dbgs() << "New: " << *Retain << "\n"); return true; } @@ -177,16 +182,19 @@ bool ObjCARCContract::contractAutorelease( Changed = true; ++NumPeeps; - DEBUG(dbgs() << " Fusing retain/autorelease!\n" - " Autorelease:" << *Autorelease << "\n" - " Retain: " << *Retain << "\n"); + LLVM_DEBUG(dbgs() << " Fusing retain/autorelease!\n" + " Autorelease:" + << *Autorelease + << "\n" + " Retain: " + << *Retain << "\n"); Constant *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV ? ARCRuntimeEntryPointKind::RetainAutoreleaseRV : ARCRuntimeEntryPointKind::RetainAutorelease); Retain->setCalledFunction(Decl); - DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n"); + LLVM_DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n"); EraseInstruction(Autorelease); return true; @@ -303,6 +311,24 @@ findRetainForStoreStrongContraction(Value *New, StoreInst *Store, return Retain; } +/// Create a call instruction with the correct funclet token. Should be used +/// instead of calling CallInst::Create directly. +static CallInst * +createCallInst(Value *Func, ArrayRef<Value *> Args, const Twine &NameStr, + Instruction *InsertBefore, + const DenseMap<BasicBlock *, ColorVector> &BlockColors) { + SmallVector<OperandBundleDef, 1> OpBundles; + if (!BlockColors.empty()) { + const ColorVector &CV = BlockColors.find(InsertBefore->getParent())->second; + assert(CV.size() == 1 && "non-unique color for block!"); + Instruction *EHPad = CV.front()->getFirstNonPHI(); + if (EHPad->isEHPad()) + OpBundles.emplace_back("funclet", EHPad); + } + + return CallInst::Create(Func, Args, OpBundles, NameStr, InsertBefore); +} + /// Attempt to merge an objc_release with a store, load, and objc_retain to form /// an objc_storeStrong. An objc_storeStrong: /// @@ -330,8 +356,9 @@ findRetainForStoreStrongContraction(Value *New, StoreInst *Store, /// (4). /// 2. We need to make sure that any re-orderings of (1), (2), (3), (4) are /// safe. -void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release, - inst_iterator &Iter) { +void ObjCARCContract::tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap<BasicBlock *, ColorVector> &BlockColors) { // See if we are releasing something that we just loaded. auto *Load = dyn_cast<LoadInst>(GetArgRCIdentityRoot(Release)); if (!Load || !Load->isSimple()) @@ -365,7 +392,7 @@ void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release, Changed = true; ++NumStoreStrongs; - DEBUG( + LLVM_DEBUG( llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n" << " Old:\n" << " Store: " << *Store << "\n" @@ -383,7 +410,7 @@ void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release, if (Args[1]->getType() != I8X) Args[1] = new BitCastInst(Args[1], I8X, "", Store); Constant *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong); - CallInst *StoreStrong = CallInst::Create(Decl, Args, "", Store); + CallInst *StoreStrong = createCallInst(Decl, Args, "", Store, BlockColors); StoreStrong->setDoesNotThrow(); StoreStrong->setDebugLoc(Store->getDebugLoc()); @@ -392,7 +419,8 @@ void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release, // we can set the tail flag once we know it's safe. StoreStrongCalls.insert(StoreStrong); - DEBUG(llvm::dbgs() << " New Store Strong: " << *StoreStrong << "\n"); + LLVM_DEBUG(llvm::dbgs() << " New Store Strong: " << *StoreStrong + << "\n"); if (&*Iter == Retain) ++Iter; if (&*Iter == Store) ++Iter; @@ -407,7 +435,8 @@ bool ObjCARCContract::tryToPeepholeInstruction( Function &F, Instruction *Inst, inst_iterator &Iter, SmallPtrSetImpl<Instruction *> &DependingInsts, SmallPtrSetImpl<const BasicBlock *> &Visited, - bool &TailOkForStoreStrongs) { + bool &TailOkForStoreStrongs, + const DenseMap<BasicBlock *, ColorVector> &BlockColors) { // Only these library routines return their argument. In particular, // objc_retainBlock does not necessarily return its argument. ARCInstKind Class = GetBasicARCInstKind(Inst); @@ -449,15 +478,16 @@ bool ObjCARCContract::tryToPeepholeInstruction( } while (IsNoopInstruction(&*BBI)); if (&*BBI == GetArgRCIdentityRoot(Inst)) { - DEBUG(dbgs() << "Adding inline asm marker for the return value " - "optimization.\n"); + LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value " + "optimization.\n"); Changed = true; InlineAsm *IA = InlineAsm::get( FunctionType::get(Type::getVoidTy(Inst->getContext()), /*isVarArg=*/false), RVInstMarker->getString(), /*Constraints=*/"", /*hasSideEffects=*/true); - CallInst::Create(IA, "", Inst); + + createCallInst(IA, None, "", Inst, BlockColors); } decline_rv_optimization: return false; @@ -471,8 +501,8 @@ bool ObjCARCContract::tryToPeepholeInstruction( Changed = true; new StoreInst(Null, CI->getArgOperand(0), CI); - DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n" - << " New = " << *Null << "\n"); + LLVM_DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n" + << " New = " << *Null << "\n"); CI->replaceAllUsesWith(Null); CI->eraseFromParent(); @@ -482,7 +512,7 @@ bool ObjCARCContract::tryToPeepholeInstruction( case ARCInstKind::Release: // Try to form an objc store strong from our release. If we fail, there is // nothing further to do below, so continue. - tryToContractReleaseIntoStoreStrong(Inst, Iter); + tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors); return true; case ARCInstKind::User: // Be conservative if the function has any alloca instructions. @@ -518,7 +548,12 @@ bool ObjCARCContract::runOnFunction(Function &F) { PA.setAA(&getAnalysis<AAResultsWrapperPass>().getAAResults()); - DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n"); + DenseMap<BasicBlock *, ColorVector> BlockColors; + if (F.hasPersonalityFn() && + isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) + BlockColors = colorEHFunclets(F); + + LLVM_DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n"); // Track whether it's ok to mark objc_storeStrong calls with the "tail" // keyword. Be conservative if the function has variadic arguments. @@ -536,12 +571,12 @@ bool ObjCARCContract::runOnFunction(Function &F) { for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) { Instruction *Inst = &*I++; - DEBUG(dbgs() << "Visiting: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n"); // First try to peephole Inst. If there is nothing further we can do in // terms of undoing objc-arc-expand, process the next inst. if (tryToPeepholeInstruction(F, Inst, I, DependingInstructions, Visited, - TailOkForStoreStrongs)) + TailOkForStoreStrongs, BlockColors)) continue; // Otherwise, try to undo objc-arc-expand. @@ -568,35 +603,48 @@ bool ObjCARCContract::runOnFunction(Function &F) { // trivially dominate itself, which would lead us to rewriting its // argument in terms of its return value, which would lead to // infinite loops in GetArgRCIdentityRoot. - if (DT->isReachableFromEntry(U) && DT->dominates(Inst, U)) { - Changed = true; - Instruction *Replacement = Inst; - Type *UseTy = U.get()->getType(); - if (PHINode *PHI = dyn_cast<PHINode>(U.getUser())) { - // For PHI nodes, insert the bitcast in the predecessor block. - unsigned ValNo = PHINode::getIncomingValueNumForOperand(OperandNo); - BasicBlock *BB = PHI->getIncomingBlock(ValNo); - if (Replacement->getType() != UseTy) - Replacement = new BitCastInst(Replacement, UseTy, "", - &BB->back()); - // While we're here, rewrite all edges for this PHI, rather - // than just one use at a time, to minimize the number of - // bitcasts we emit. - for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) - if (PHI->getIncomingBlock(i) == BB) { - // Keep the UI iterator valid. - if (UI != UE && - &PHI->getOperandUse( - PHINode::getOperandNumForIncomingValue(i)) == &*UI) - ++UI; - PHI->setIncomingValue(i, Replacement); - } - } else { - if (Replacement->getType() != UseTy) - Replacement = new BitCastInst(Replacement, UseTy, "", - cast<Instruction>(U.getUser())); - U.set(Replacement); + if (!DT->isReachableFromEntry(U) || !DT->dominates(Inst, U)) + continue; + + Changed = true; + Instruction *Replacement = Inst; + Type *UseTy = U.get()->getType(); + if (PHINode *PHI = dyn_cast<PHINode>(U.getUser())) { + // For PHI nodes, insert the bitcast in the predecessor block. + unsigned ValNo = PHINode::getIncomingValueNumForOperand(OperandNo); + BasicBlock *IncomingBB = PHI->getIncomingBlock(ValNo); + if (Replacement->getType() != UseTy) { + // A catchswitch is both a pad and a terminator, meaning a basic + // block with a catchswitch has no insertion point. Keep going up + // the dominator tree until we find a non-catchswitch. + BasicBlock *InsertBB = IncomingBB; + while (isa<CatchSwitchInst>(InsertBB->getFirstNonPHI())) { + InsertBB = DT->getNode(InsertBB)->getIDom()->getBlock(); + } + + assert(DT->dominates(Inst, &InsertBB->back()) && + "Invalid insertion point for bitcast"); + Replacement = + new BitCastInst(Replacement, UseTy, "", &InsertBB->back()); } + + // While we're here, rewrite all edges for this PHI, rather + // than just one use at a time, to minimize the number of + // bitcasts we emit. + for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) + if (PHI->getIncomingBlock(i) == IncomingBB) { + // Keep the UI iterator valid. + if (UI != UE && + &PHI->getOperandUse( + PHINode::getOperandNumForIncomingValue(i)) == &*UI) + ++UI; + PHI->setIncomingValue(i, Replacement); + } + } else { + if (Replacement->getType() != UseTy) + Replacement = new BitCastInst(Replacement, UseTy, "", + cast<Instruction>(U.getUser())); + U.set(Replacement); } } }; @@ -618,8 +666,17 @@ bool ObjCARCContract::runOnFunction(Function &F) { else if (isa<GlobalAlias>(Arg) && !cast<GlobalAlias>(Arg)->isInterposable()) Arg = cast<GlobalAlias>(Arg)->getAliasee(); - else + else { + // If Arg is a PHI node, get PHIs that are equivalent to it and replace + // their uses. + if (PHINode *PN = dyn_cast<PHINode>(Arg)) { + SmallVector<Value *, 1> PHIList; + getEquivalentPHIs(*PN, PHIList); + for (Value *PHI : PHIList) + ReplaceArgUses(PHI); + } break; + } } // Replace bitcast users of Arg that are dominated by Inst. diff --git a/lib/Transforms/ObjCARC/ObjCARCExpand.cpp b/lib/Transforms/ObjCARC/ObjCARCExpand.cpp index bb6a0a0e73db..6a345ef56e1b 100644 --- a/lib/Transforms/ObjCARC/ObjCARCExpand.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCExpand.cpp @@ -47,7 +47,7 @@ using namespace llvm; using namespace llvm::objcarc; namespace { - /// \brief Early ARC transformations. + /// Early ARC transformations. class ObjCARCExpand : public FunctionPass { void getAnalysisUsage(AnalysisUsage &AU) const override; bool doInitialization(Module &M) override; @@ -91,12 +91,13 @@ bool ObjCARCExpand::runOnFunction(Function &F) { bool Changed = false; - DEBUG(dbgs() << "ObjCARCExpand: Visiting Function: " << F.getName() << "\n"); + LLVM_DEBUG(dbgs() << "ObjCARCExpand: Visiting Function: " << F.getName() + << "\n"); for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) { Instruction *Inst = &*I; - DEBUG(dbgs() << "ObjCARCExpand: Visiting: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << "ObjCARCExpand: Visiting: " << *Inst << "\n"); switch (GetBasicARCInstKind(Inst)) { case ARCInstKind::Retain: @@ -111,8 +112,10 @@ bool ObjCARCExpand::runOnFunction(Function &F) { // emitted here. We'll redo them in the contract pass. Changed = true; Value *Value = cast<CallInst>(Inst)->getArgOperand(0); - DEBUG(dbgs() << "ObjCARCExpand: Old = " << *Inst << "\n" - " New = " << *Value << "\n"); + LLVM_DEBUG(dbgs() << "ObjCARCExpand: Old = " << *Inst + << "\n" + " New = " + << *Value << "\n"); Inst->replaceAllUsesWith(Value); break; } @@ -121,7 +124,7 @@ bool ObjCARCExpand::runOnFunction(Function &F) { } } - DEBUG(dbgs() << "ObjCARCExpand: Finished List.\n\n"); + LLVM_DEBUG(dbgs() << "ObjCARCExpand: Finished List.\n\n"); return Changed; } diff --git a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 99ed6863c22e..21e2848030fc 100644 --- a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -38,6 +38,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/ObjCARCAliasAnalysis.h" #include "llvm/Analysis/ObjCARCAnalysisUtils.h" #include "llvm/Analysis/ObjCARCInstKind.h" @@ -76,7 +77,7 @@ using namespace llvm::objcarc; /// \defgroup ARCUtilities Utility declarations/definitions specific to ARC. /// @{ -/// \brief This is similar to GetRCIdentityRoot but it stops as soon +/// This is similar to GetRCIdentityRoot but it stops as soon /// as it finds a value with multiple uses. static const Value *FindSingleUseIdentifiedObject(const Value *Arg) { // ConstantData (like ConstantPointerNull and UndefValue) is used across @@ -174,7 +175,7 @@ STATISTIC(NumReleasesAfterOpt, namespace { - /// \brief Per-BasicBlock state. + /// Per-BasicBlock state. class BBState { /// The number of unique control paths from the entry which can reach this /// block. @@ -422,7 +423,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, BBState &BBInfo) { // Dump the pointers we are tracking. OS << " TopDown State:\n"; if (!BBInfo.hasTopDownPtrs()) { - DEBUG(dbgs() << " NONE!\n"); + LLVM_DEBUG(dbgs() << " NONE!\n"); } else { for (auto I = BBInfo.top_down_ptr_begin(), E = BBInfo.top_down_ptr_end(); I != E; ++I) { @@ -442,7 +443,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, BBState &BBInfo) { OS << " BottomUp State:\n"; if (!BBInfo.hasBottomUpPtrs()) { - DEBUG(dbgs() << " NONE!\n"); + LLVM_DEBUG(dbgs() << " NONE!\n"); } else { for (auto I = BBInfo.bottom_up_ptr_begin(), E = BBInfo.bottom_up_ptr_end(); I != E; ++I) { @@ -465,7 +466,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, BBState &BBInfo) { namespace { - /// \brief The main ARC optimization pass. + /// The main ARC optimization pass. class ObjCARCOpt : public FunctionPass { bool Changed; ProvenanceAnalysis PA; @@ -612,8 +613,8 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) { Changed = true; ++NumPeeps; - DEBUG(dbgs() << "Erasing autoreleaseRV,retainRV pair: " << *I << "\n" - << "Erasing " << *RetainRV << "\n"); + LLVM_DEBUG(dbgs() << "Erasing autoreleaseRV,retainRV pair: " << *I << "\n" + << "Erasing " << *RetainRV << "\n"); EraseInstruction(&*I); EraseInstruction(RetainRV); @@ -625,14 +626,15 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) { Changed = true; ++NumPeeps; - DEBUG(dbgs() << "Transforming objc_retainAutoreleasedReturnValue => " - "objc_retain since the operand is not a return value.\n" - "Old = " << *RetainRV << "\n"); + LLVM_DEBUG(dbgs() << "Transforming objc_retainAutoreleasedReturnValue => " + "objc_retain since the operand is not a return value.\n" + "Old = " + << *RetainRV << "\n"); Constant *NewDecl = EP.get(ARCRuntimeEntryPointKind::Retain); cast<CallInst>(RetainRV)->setCalledFunction(NewDecl); - DEBUG(dbgs() << "New = " << *RetainRV << "\n"); + LLVM_DEBUG(dbgs() << "New = " << *RetainRV << "\n"); return false; } @@ -652,6 +654,11 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, SmallVector<const Value *, 2> Users; Users.push_back(Ptr); + + // Add PHIs that are equivalent to Ptr to Users. + if (const PHINode *PN = dyn_cast<PHINode>(Ptr)) + getEquivalentPHIs(*PN, Users); + do { Ptr = Users.pop_back_val(); for (const User *U : Ptr->users()) { @@ -665,10 +672,12 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, Changed = true; ++NumPeeps; - DEBUG(dbgs() << "Transforming objc_autoreleaseReturnValue => " - "objc_autorelease since its operand is not used as a return " - "value.\n" - "Old = " << *AutoreleaseRV << "\n"); + LLVM_DEBUG( + dbgs() << "Transforming objc_autoreleaseReturnValue => " + "objc_autorelease since its operand is not used as a return " + "value.\n" + "Old = " + << *AutoreleaseRV << "\n"); CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV); Constant *NewDecl = EP.get(ARCRuntimeEntryPointKind::Autorelease); @@ -676,23 +685,53 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, AutoreleaseRVCI->setTailCall(false); // Never tail call objc_autorelease. Class = ARCInstKind::Autorelease; - DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n"); + LLVM_DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n"); +} + +namespace { +Instruction * +CloneCallInstForBB(CallInst &CI, BasicBlock &BB, + const DenseMap<BasicBlock *, ColorVector> &BlockColors) { + SmallVector<OperandBundleDef, 1> OpBundles; + for (unsigned I = 0, E = CI.getNumOperandBundles(); I != E; ++I) { + auto Bundle = CI.getOperandBundleAt(I); + // Funclets will be reassociated in the future. + if (Bundle.getTagID() == LLVMContext::OB_funclet) + continue; + OpBundles.emplace_back(Bundle); + } + + if (!BlockColors.empty()) { + const ColorVector &CV = BlockColors.find(&BB)->second; + assert(CV.size() == 1 && "non-unique color for block!"); + Instruction *EHPad = CV.front()->getFirstNonPHI(); + if (EHPad->isEHPad()) + OpBundles.emplace_back("funclet", EHPad); + } + + return CallInst::Create(&CI, OpBundles); +} } /// Visit each call, one at a time, and make simplifications without doing any /// additional analysis. void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { - DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeIndividualCalls ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeIndividualCalls ==\n"); // Reset all the flags in preparation for recomputing them. UsedInThisFunction = 0; + DenseMap<BasicBlock *, ColorVector> BlockColors; + if (F.hasPersonalityFn() && + isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) + BlockColors = colorEHFunclets(F); + // Visit all objc_* calls in F. for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) { Instruction *Inst = &*I++; ARCInstKind Class = GetBasicARCInstKind(Inst); - DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n"); switch (Class) { default: break; @@ -708,7 +747,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { case ARCInstKind::NoopCast: Changed = true; ++NumNoops; - DEBUG(dbgs() << "Erasing no-op cast: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << "Erasing no-op cast: " << *Inst << "\n"); EraseInstruction(Inst); continue; @@ -726,8 +765,10 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { Constant::getNullValue(Ty), CI); Value *NewValue = UndefValue::get(CI->getType()); - DEBUG(dbgs() << "A null pointer-to-weak-pointer is undefined behavior." - "\nOld = " << *CI << "\nNew = " << *NewValue << "\n"); + LLVM_DEBUG( + dbgs() << "A null pointer-to-weak-pointer is undefined behavior." + "\nOld = " + << *CI << "\nNew = " << *NewValue << "\n"); CI->replaceAllUsesWith(NewValue); CI->eraseFromParent(); continue; @@ -746,8 +787,10 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { CI); Value *NewValue = UndefValue::get(CI->getType()); - DEBUG(dbgs() << "A null pointer-to-weak-pointer is undefined behavior." - "\nOld = " << *CI << "\nNew = " << *NewValue << "\n"); + LLVM_DEBUG( + dbgs() << "A null pointer-to-weak-pointer is undefined behavior." + "\nOld = " + << *CI << "\nNew = " << *NewValue << "\n"); CI->replaceAllUsesWith(NewValue); CI->eraseFromParent(); @@ -782,9 +825,10 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { NewCall->setMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease), MDNode::get(C, None)); - DEBUG(dbgs() << "Replacing autorelease{,RV}(x) with objc_release(x) " - "since x is otherwise unused.\nOld: " << *Call << "\nNew: " - << *NewCall << "\n"); + LLVM_DEBUG( + dbgs() << "Replacing autorelease{,RV}(x) with objc_release(x) " + "since x is otherwise unused.\nOld: " + << *Call << "\nNew: " << *NewCall << "\n"); EraseInstruction(Call); Inst = NewCall; @@ -796,8 +840,10 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { // a tail keyword. if (IsAlwaysTail(Class)) { Changed = true; - DEBUG(dbgs() << "Adding tail keyword to function since it can never be " - "passed stack args: " << *Inst << "\n"); + LLVM_DEBUG( + dbgs() << "Adding tail keyword to function since it can never be " + "passed stack args: " + << *Inst << "\n"); cast<CallInst>(Inst)->setTailCall(); } @@ -805,16 +851,16 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { // semantics of ARC truly do not do so. if (IsNeverTail(Class)) { Changed = true; - DEBUG(dbgs() << "Removing tail keyword from function: " << *Inst << - "\n"); + LLVM_DEBUG(dbgs() << "Removing tail keyword from function: " << *Inst + << "\n"); cast<CallInst>(Inst)->setTailCall(false); } // Set nounwind as needed. if (IsNoThrow(Class)) { Changed = true; - DEBUG(dbgs() << "Found no throw class. Setting nounwind on: " << *Inst - << "\n"); + LLVM_DEBUG(dbgs() << "Found no throw class. Setting nounwind on: " + << *Inst << "\n"); cast<CallInst>(Inst)->setDoesNotThrow(); } @@ -829,8 +875,8 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { if (IsNullOrUndef(Arg)) { Changed = true; ++NumNoops; - DEBUG(dbgs() << "ARC calls with null are no-ops. Erasing: " << *Inst - << "\n"); + LLVM_DEBUG(dbgs() << "ARC calls with null are no-ops. Erasing: " << *Inst + << "\n"); EraseInstruction(Inst); continue; } @@ -922,22 +968,24 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { Value *Incoming = GetRCIdentityRoot(PN->getIncomingValue(i)); if (!IsNullOrUndef(Incoming)) { - CallInst *Clone = cast<CallInst>(CInst->clone()); Value *Op = PN->getIncomingValue(i); Instruction *InsertPos = &PN->getIncomingBlock(i)->back(); + CallInst *Clone = cast<CallInst>(CloneCallInstForBB( + *CInst, *InsertPos->getParent(), BlockColors)); if (Op->getType() != ParamTy) Op = new BitCastInst(Op, ParamTy, "", InsertPos); Clone->setArgOperand(0, Op); Clone->insertBefore(InsertPos); - DEBUG(dbgs() << "Cloning " - << *CInst << "\n" - "And inserting clone at " << *InsertPos << "\n"); + LLVM_DEBUG(dbgs() << "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"); + LLVM_DEBUG(dbgs() << "Erasing: " << *CInst << "\n"); EraseInstruction(CInst); continue; } @@ -1114,7 +1162,7 @@ bool ObjCARCOpt::VisitInstructionBottomUp( ARCInstKind Class = GetARCInstKind(Inst); const Value *Arg = nullptr; - DEBUG(dbgs() << " Class: " << Class << "\n"); + LLVM_DEBUG(dbgs() << " Class: " << Class << "\n"); switch (Class) { case ARCInstKind::Release: { @@ -1137,7 +1185,7 @@ bool ObjCARCOpt::VisitInstructionBottomUp( // Don't do retain+release tracking for ARCInstKind::RetainRV, because // it's better to let it remain as the first instruction after a call. if (Class != ARCInstKind::RetainRV) { - DEBUG(dbgs() << " Matching with: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << " Matching with: " << *Inst << "\n"); Retains[Inst] = S.GetRRInfo(); } S.ClearSequenceProgress(); @@ -1179,7 +1227,7 @@ bool ObjCARCOpt::VisitInstructionBottomUp( bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB, DenseMap<const BasicBlock *, BBState> &BBStates, BlotMapVector<Value *, RRInfo> &Retains) { - DEBUG(dbgs() << "\n== ObjCARCOpt::VisitBottomUp ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::VisitBottomUp ==\n"); bool NestingDetected = false; BBState &MyStates = BBStates[BB]; @@ -1202,8 +1250,9 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB, } } - DEBUG(dbgs() << "Before:\n" << BBStates[BB] << "\n" - << "Performing Dataflow:\n"); + LLVM_DEBUG(dbgs() << "Before:\n" + << BBStates[BB] << "\n" + << "Performing Dataflow:\n"); // Visit all the instructions, bottom-up. for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; --I) { @@ -1213,7 +1262,7 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB, if (isa<InvokeInst>(Inst)) continue; - DEBUG(dbgs() << " Visiting " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << " Visiting " << *Inst << "\n"); NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates); } @@ -1228,7 +1277,7 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB, NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates); } - DEBUG(dbgs() << "\nFinal State:\n" << BBStates[BB] << "\n"); + LLVM_DEBUG(dbgs() << "\nFinal State:\n" << BBStates[BB] << "\n"); return NestingDetected; } @@ -1241,7 +1290,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst, ARCInstKind Class = GetARCInstKind(Inst); const Value *Arg = nullptr; - DEBUG(dbgs() << " Class: " << Class << "\n"); + LLVM_DEBUG(dbgs() << " Class: " << Class << "\n"); switch (Class) { case ARCInstKind::RetainBlock: @@ -1267,7 +1316,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst, if (S.MatchWithRelease(MDKindCache, Inst)) { // If we succeed, copy S's RRInfo into the Release -> {Retain Set // Map}. Then we clear S. - DEBUG(dbgs() << " Matching with: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << " Matching with: " << *Inst << "\n"); Releases[Inst] = S.GetRRInfo(); S.ClearSequenceProgress(); } @@ -1307,7 +1356,7 @@ bool ObjCARCOpt::VisitTopDown(BasicBlock *BB, DenseMap<const BasicBlock *, BBState> &BBStates, DenseMap<Value *, RRInfo> &Releases) { - DEBUG(dbgs() << "\n== ObjCARCOpt::VisitTopDown ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::VisitTopDown ==\n"); bool NestingDetected = false; BBState &MyStates = BBStates[BB]; @@ -1329,20 +1378,21 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB, } } - DEBUG(dbgs() << "Before:\n" << BBStates[BB] << "\n" - << "Performing Dataflow:\n"); + LLVM_DEBUG(dbgs() << "Before:\n" + << BBStates[BB] << "\n" + << "Performing Dataflow:\n"); // Visit all the instructions, top-down. for (Instruction &Inst : *BB) { - DEBUG(dbgs() << " Visiting " << Inst << "\n"); + LLVM_DEBUG(dbgs() << " Visiting " << Inst << "\n"); NestingDetected |= VisitInstructionTopDown(&Inst, Releases, MyStates); } - DEBUG(dbgs() << "\nState Before Checking for CFG Hazards:\n" - << BBStates[BB] << "\n\n"); + LLVM_DEBUG(dbgs() << "\nState Before Checking for CFG Hazards:\n" + << BBStates[BB] << "\n\n"); CheckForCFGHazards(BB, BBStates, MyStates); - DEBUG(dbgs() << "Final State:\n" << BBStates[BB] << "\n"); + LLVM_DEBUG(dbgs() << "Final State:\n" << BBStates[BB] << "\n"); return NestingDetected; } @@ -1465,7 +1515,7 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, Type *ArgTy = Arg->getType(); Type *ParamTy = PointerType::getUnqual(Type::getInt8Ty(ArgTy->getContext())); - DEBUG(dbgs() << "== ObjCARCOpt::MoveCalls ==\n"); + LLVM_DEBUG(dbgs() << "== ObjCARCOpt::MoveCalls ==\n"); // Insert the new retain and release calls. for (Instruction *InsertPt : ReleasesToMove.ReverseInsertPts) { @@ -1476,8 +1526,10 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, Call->setDoesNotThrow(); Call->setTailCall(); - DEBUG(dbgs() << "Inserting new Retain: " << *Call << "\n" - "At insertion point: " << *InsertPt << "\n"); + LLVM_DEBUG(dbgs() << "Inserting new Retain: " << *Call + << "\n" + "At insertion point: " + << *InsertPt << "\n"); } for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) { Value *MyArg = ArgTy == ParamTy ? Arg : @@ -1491,20 +1543,22 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, if (ReleasesToMove.IsTailCallRelease) Call->setTailCall(); - DEBUG(dbgs() << "Inserting new Release: " << *Call << "\n" - "At insertion point: " << *InsertPt << "\n"); + LLVM_DEBUG(dbgs() << "Inserting new Release: " << *Call + << "\n" + "At insertion point: " + << *InsertPt << "\n"); } // Delete the original retain and release calls. for (Instruction *OrigRetain : RetainsToMove.Calls) { Retains.blot(OrigRetain); DeadInsts.push_back(OrigRetain); - DEBUG(dbgs() << "Deleting retain: " << *OrigRetain << "\n"); + LLVM_DEBUG(dbgs() << "Deleting retain: " << *OrigRetain << "\n"); } for (Instruction *OrigRelease : ReleasesToMove.Calls) { Releases.erase(OrigRelease); DeadInsts.push_back(OrigRelease); - DEBUG(dbgs() << "Deleting release: " << *OrigRelease << "\n"); + LLVM_DEBUG(dbgs() << "Deleting release: " << *OrigRelease << "\n"); } } @@ -1538,6 +1592,7 @@ bool ObjCARCOpt::PairUpRetainsAndReleases( assert(It != Retains.end()); const RRInfo &NewRetainRRI = It->second; KnownSafeTD &= NewRetainRRI.KnownSafe; + CFGHazardAfflicted |= NewRetainRRI.CFGHazardAfflicted; for (Instruction *NewRetainRelease : NewRetainRRI.Calls) { auto Jt = Releases.find(NewRetainRelease); if (Jt == Releases.end()) @@ -1710,7 +1765,7 @@ bool ObjCARCOpt::PerformCodePlacement( DenseMap<const BasicBlock *, BBState> &BBStates, BlotMapVector<Value *, RRInfo> &Retains, DenseMap<Value *, RRInfo> &Releases, Module *M) { - DEBUG(dbgs() << "\n== ObjCARCOpt::PerformCodePlacement ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::PerformCodePlacement ==\n"); bool AnyPairsCompletelyEliminated = false; SmallVector<Instruction *, 8> DeadInsts; @@ -1724,7 +1779,7 @@ bool ObjCARCOpt::PerformCodePlacement( Instruction *Retain = cast<Instruction>(V); - DEBUG(dbgs() << "Visiting: " << *Retain << "\n"); + LLVM_DEBUG(dbgs() << "Visiting: " << *Retain << "\n"); Value *Arg = GetArgRCIdentityRoot(Retain); @@ -1769,7 +1824,7 @@ bool ObjCARCOpt::PerformCodePlacement( /// Weak pointer optimizations. void ObjCARCOpt::OptimizeWeakCalls(Function &F) { - DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeWeakCalls ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeWeakCalls ==\n"); // First, do memdep-style RLE and S2L optimizations. We can't use memdep // itself because it uses AliasAnalysis and we need to do provenance @@ -1777,7 +1832,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) { for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) { Instruction *Inst = &*I++; - DEBUG(dbgs() << "Visiting: " << *Inst << "\n"); + LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n"); ARCInstKind Class = GetBasicARCInstKind(Inst); if (Class != ARCInstKind::LoadWeak && @@ -2036,7 +2091,7 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { if (!F.getReturnType()->isPointerTy()) return; - DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeReturns ==\n"); + LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeReturns ==\n"); SmallPtrSet<Instruction *, 4> DependingInstructions; SmallPtrSet<const BasicBlock *, 4> Visited; @@ -2045,7 +2100,7 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { if (!Ret) continue; - DEBUG(dbgs() << "Visiting: " << *Ret << "\n"); + LLVM_DEBUG(dbgs() << "Visiting: " << *Ret << "\n"); const Value *Arg = GetRCIdentityRoot(Ret->getOperand(0)); @@ -2083,8 +2138,8 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { // If so, we can zap the retain and autorelease. Changed = true; ++NumRets; - DEBUG(dbgs() << "Erasing: " << *Retain << "\nErasing: " - << *Autorelease << "\n"); + LLVM_DEBUG(dbgs() << "Erasing: " << *Retain << "\nErasing: " << *Autorelease + << "\n"); EraseInstruction(Retain); EraseInstruction(Autorelease); } @@ -2144,8 +2199,9 @@ bool ObjCARCOpt::runOnFunction(Function &F) { Changed = false; - DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName() << " >>>" - "\n"); + LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName() + << " >>>" + "\n"); PA.setAA(&getAnalysis<AAResultsWrapperPass>().getAAResults()); @@ -2193,7 +2249,7 @@ bool ObjCARCOpt::runOnFunction(Function &F) { } #endif - DEBUG(dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "\n"); return Changed; } diff --git a/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp b/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp index f89fc8eb62aa..3004fffb9745 100644 --- a/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp +++ b/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp @@ -115,14 +115,6 @@ static bool IsStoredObjCPointer(const Value *P) { bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B, const DataLayout &DL) { - // Skip past provenance pass-throughs. - A = GetUnderlyingObjCPtr(A, DL); - B = GetUnderlyingObjCPtr(B, DL); - - // Quick check. - if (A == B) - return true; - // Ask regular AliasAnalysis, for a first approximation. switch (AA->alias(A, B)) { case NoAlias: @@ -171,6 +163,13 @@ bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B, bool ProvenanceAnalysis::related(const Value *A, const Value *B, const DataLayout &DL) { + A = GetUnderlyingObjCPtrCached(A, DL, UnderlyingObjCPtrCache); + B = GetUnderlyingObjCPtrCached(B, DL, UnderlyingObjCPtrCache); + + // Quick check. + if (A == B) + return true; + // Begin by inserting a conservative value into the map. If the insertion // fails, we have the answer already. If it succeeds, leave it there until we // compute the real answer to guard against recursive queries. diff --git a/lib/Transforms/ObjCARC/ProvenanceAnalysis.h b/lib/Transforms/ObjCARC/ProvenanceAnalysis.h index 5e676167a6a1..1276f564a022 100644 --- a/lib/Transforms/ObjCARC/ProvenanceAnalysis.h +++ b/lib/Transforms/ObjCARC/ProvenanceAnalysis.h @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/IR/ValueHandle.h" #include <utility> namespace llvm { @@ -39,7 +40,7 @@ class Value; namespace objcarc { -/// \brief This is similar to BasicAliasAnalysis, and it uses many of the same +/// This is similar to BasicAliasAnalysis, and it uses many of the same /// techniques, except it uses special ObjC-specific reasoning about pointer /// relationships. /// @@ -56,6 +57,8 @@ class ProvenanceAnalysis { CachedResultsTy CachedResults; + DenseMap<const Value *, WeakTrackingVH> UnderlyingObjCPtrCache; + bool relatedCheck(const Value *A, const Value *B, const DataLayout &DL); bool relatedSelect(const SelectInst *A, const Value *B); bool relatedPHI(const PHINode *A, const Value *B); @@ -73,6 +76,7 @@ public: void clear() { CachedResults.clear(); + UnderlyingObjCPtrCache.clear(); } }; diff --git a/lib/Transforms/ObjCARC/PtrState.cpp b/lib/Transforms/ObjCARC/PtrState.cpp index e1774b88fd35..8a7b6a74fae2 100644 --- a/lib/Transforms/ObjCARC/PtrState.cpp +++ b/lib/Transforms/ObjCARC/PtrState.cpp @@ -126,22 +126,23 @@ bool RRInfo::Merge(const RRInfo &Other) { //===----------------------------------------------------------------------===// void PtrState::SetKnownPositiveRefCount() { - DEBUG(dbgs() << " Setting Known Positive.\n"); + LLVM_DEBUG(dbgs() << " Setting Known Positive.\n"); KnownPositiveRefCount = true; } void PtrState::ClearKnownPositiveRefCount() { - DEBUG(dbgs() << " Clearing Known Positive.\n"); + LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n"); KnownPositiveRefCount = false; } void PtrState::SetSeq(Sequence NewSeq) { - DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq << "\n"); + LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq + << "\n"); Seq = NewSeq; } void PtrState::ResetSequenceProgress(Sequence NewSeq) { - DEBUG(dbgs() << " Resetting sequence progress.\n"); + LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n"); SetSeq(NewSeq); Partial = false; RRI.clear(); @@ -184,7 +185,8 @@ bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) { // simple and avoids adding overhead for the non-nested case. bool NestingDetected = false; if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) { - DEBUG(dbgs() << " Found nested releases (i.e. a release pair)\n"); + LLVM_DEBUG( + dbgs() << " Found nested releases (i.e. a release pair)\n"); NestingDetected = true; } @@ -234,8 +236,8 @@ bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst, if (!CanAlterRefCount(Inst, Ptr, PA, Class)) return false; - DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " << *Ptr - << "\n"); + LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " + << *Ptr << "\n"); switch (S) { case S_Use: SetSeq(S_CanRelease); @@ -266,6 +268,11 @@ void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst, if (isa<InvokeInst>(Inst)) { const auto IP = BB->getFirstInsertionPt(); InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP; + if (isa<CatchSwitchInst>(InsertAfter)) + // A catchswitch must be the only non-phi instruction in its basic + // block, so attempting to insert an instruction into such a block would + // produce invalid IR. + SetCFGHazardAfflicted(true); } else { InsertAfter = std::next(Inst->getIterator()); } @@ -277,26 +284,26 @@ void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst, case S_Release: case S_MovableRelease: if (CanUse(Inst, Ptr, PA, Class)) { - DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr - << "\n"); + LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " + << *Ptr << "\n"); SetSeqAndInsertReverseInsertPt(S_Use); } else if (Seq == S_Release && IsUser(Class)) { - DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() << "; " - << *Ptr << "\n"); + LLVM_DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() + << "; " << *Ptr << "\n"); // Non-movable releases depend on any possible objc pointer use. SetSeqAndInsertReverseInsertPt(S_Stop); } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) { if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) { - DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; " - << *Ptr << "\n"); + LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; " + << *Ptr << "\n"); SetSeqAndInsertReverseInsertPt(S_Stop); } } break; case S_Stop: if (CanUse(Inst, Ptr, PA, Class)) { - DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() << "; " - << *Ptr << "\n"); + LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() + << "; " << *Ptr << "\n"); SetSeq(S_Use); } break; @@ -377,8 +384,8 @@ bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst, Class != ARCInstKind::IntrinsicUser) return false; - DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr - << "\n"); + LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " + << *Ptr << "\n"); ClearKnownPositiveRefCount(); switch (GetSeq()) { case S_Retain: @@ -410,8 +417,8 @@ void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr, case S_CanRelease: if (!CanUse(Inst, Ptr, PA, Class)) return; - DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr - << "\n"); + LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " + << *Ptr << "\n"); SetSeq(S_Use); return; case S_Retain: diff --git a/lib/Transforms/ObjCARC/PtrState.h b/lib/Transforms/ObjCARC/PtrState.h index e1e95afcf76b..f5b9b853d8e3 100644 --- a/lib/Transforms/ObjCARC/PtrState.h +++ b/lib/Transforms/ObjCARC/PtrState.h @@ -36,7 +36,7 @@ class ProvenanceAnalysis; /// \enum Sequence /// -/// \brief A sequence of states that a pointer may go through in which an +/// A sequence of states that a pointer may go through in which an /// objc_retain and objc_release are actually needed. enum Sequence { S_None, @@ -51,7 +51,7 @@ enum Sequence { raw_ostream &operator<<(raw_ostream &OS, const Sequence S) LLVM_ATTRIBUTE_UNUSED; -/// \brief Unidirectional information about either a +/// Unidirectional information about either a /// retain-decrement-use-release sequence or release-use-decrement-retain /// reverse sequence. struct RRInfo { @@ -97,7 +97,7 @@ struct RRInfo { bool Merge(const RRInfo &Other); }; -/// \brief This class summarizes several per-pointer runtime properties which +/// This class summarizes several per-pointer runtime properties which /// are propagated through the flow graph. class PtrState { protected: |