summaryrefslogtreecommitdiff
path: root/lib/Transforms/ObjCARC
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Transforms/ObjCARC
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/Transforms/ObjCARC')
-rw-r--r--lib/Transforms/ObjCARC/BlotMapVector.h2
-rw-r--r--lib/Transforms/ObjCARC/DependencyAnalysis.h2
-rw-r--r--lib/Transforms/ObjCARC/ObjCARC.h24
-rw-r--r--lib/Transforms/ObjCARC/ObjCARCAPElim.cpp12
-rw-r--r--lib/Transforms/ObjCARC/ObjCARCContract.cpp177
-rw-r--r--lib/Transforms/ObjCARC/ObjCARCExpand.cpp15
-rw-r--r--lib/Transforms/ObjCARC/ObjCARCOpts.cpp202
-rw-r--r--lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp15
-rw-r--r--lib/Transforms/ObjCARC/ProvenanceAnalysis.h6
-rw-r--r--lib/Transforms/ObjCARC/PtrState.cpp45
-rw-r--r--lib/Transforms/ObjCARC/PtrState.h6
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: