summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp')
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp305
1 files changed, 148 insertions, 157 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index cb1fa804fa11..1c447499519c 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -65,6 +65,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/ObjCARC.h"
#include <cassert>
#include <iterator>
#include <utility>
@@ -480,123 +481,133 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, BBState &BBInfo) {
namespace {
/// The main ARC optimization pass.
- class ObjCARCOpt : public FunctionPass {
- bool Changed;
- ProvenanceAnalysis PA;
+class ObjCARCOpt {
+ bool Changed;
+ ProvenanceAnalysis PA;
- /// A cache of references to runtime entry point constants.
- ARCRuntimeEntryPoints EP;
+ /// A cache of references to runtime entry point constants.
+ ARCRuntimeEntryPoints EP;
- /// A cache of MDKinds that can be passed into other functions to propagate
- /// MDKind identifiers.
- ARCMDKindCache MDKindCache;
+ /// A cache of MDKinds that can be passed into other functions to propagate
+ /// MDKind identifiers.
+ ARCMDKindCache MDKindCache;
- /// A flag indicating whether this optimization pass should run.
- bool Run;
+ /// A flag indicating whether this optimization pass should run.
+ bool Run;
- /// A flag indicating whether the optimization that removes or moves
- /// retain/release pairs should be performed.
- bool DisableRetainReleasePairing = false;
+ /// A flag indicating whether the optimization that removes or moves
+ /// retain/release pairs should be performed.
+ bool DisableRetainReleasePairing = false;
- /// Flags which determine whether each of the interesting runtime functions
- /// is in fact used in the current function.
- unsigned UsedInThisFunction;
+ /// Flags which determine whether each of the interesting runtime functions
+ /// is in fact used in the current function.
+ unsigned UsedInThisFunction;
- bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV);
- void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
- ARCInstKind &Class);
- void OptimizeIndividualCalls(Function &F);
+ bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV);
+ void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
+ ARCInstKind &Class);
+ void OptimizeIndividualCalls(Function &F);
- /// Optimize an individual call, optionally passing the
- /// GetArgRCIdentityRoot if it has already been computed.
- void OptimizeIndividualCallImpl(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, ARCInstKind Class, const Value *Arg);
+ /// Optimize an individual call, optionally passing the
+ /// GetArgRCIdentityRoot if it has already been computed.
+ void OptimizeIndividualCallImpl(
+ Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
+ Instruction *Inst, ARCInstKind Class, const Value *Arg);
- /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the
- /// optimization occurs, returns true to indicate that the caller should
- /// assume the instructions are dead.
- bool OptimizeInlinedAutoreleaseRVCall(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, const Value *&Arg, ARCInstKind Class,
- Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg);
+ /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the
+ /// optimization occurs, returns true to indicate that the caller should
+ /// assume the instructions are dead.
+ bool OptimizeInlinedAutoreleaseRVCall(
+ Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
+ Instruction *Inst, const Value *&Arg, ARCInstKind Class,
+ Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg);
- void CheckForCFGHazards(const BasicBlock *BB,
- DenseMap<const BasicBlock *, BBState> &BBStates,
- BBState &MyStates) const;
- bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB,
- BlotMapVector<Value *, RRInfo> &Retains,
- BBState &MyStates);
- bool VisitBottomUp(BasicBlock *BB,
- DenseMap<const BasicBlock *, BBState> &BBStates,
- BlotMapVector<Value *, RRInfo> &Retains);
- bool VisitInstructionTopDown(Instruction *Inst,
- DenseMap<Value *, RRInfo> &Releases,
- BBState &MyStates);
- bool VisitTopDown(BasicBlock *BB,
- DenseMap<const BasicBlock *, BBState> &BBStates,
- DenseMap<Value *, RRInfo> &Releases);
- bool Visit(Function &F, DenseMap<const BasicBlock *, BBState> &BBStates,
- BlotMapVector<Value *, RRInfo> &Retains,
- DenseMap<Value *, RRInfo> &Releases);
+ void CheckForCFGHazards(const BasicBlock *BB,
+ DenseMap<const BasicBlock *, BBState> &BBStates,
+ BBState &MyStates) const;
+ bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB,
+ BlotMapVector<Value *, RRInfo> &Retains,
+ BBState &MyStates);
+ bool VisitBottomUp(BasicBlock *BB,
+ DenseMap<const BasicBlock *, BBState> &BBStates,
+ BlotMapVector<Value *, RRInfo> &Retains);
+ bool VisitInstructionTopDown(Instruction *Inst,
+ DenseMap<Value *, RRInfo> &Releases,
+ BBState &MyStates);
+ bool VisitTopDown(BasicBlock *BB,
+ DenseMap<const BasicBlock *, BBState> &BBStates,
+ DenseMap<Value *, RRInfo> &Releases);
+ bool Visit(Function &F, DenseMap<const BasicBlock *, BBState> &BBStates,
+ BlotMapVector<Value *, RRInfo> &Retains,
+ DenseMap<Value *, RRInfo> &Releases);
- void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove,
- BlotMapVector<Value *, RRInfo> &Retains,
- DenseMap<Value *, RRInfo> &Releases,
- SmallVectorImpl<Instruction *> &DeadInsts, Module *M);
+ void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove,
+ BlotMapVector<Value *, RRInfo> &Retains,
+ DenseMap<Value *, RRInfo> &Releases,
+ SmallVectorImpl<Instruction *> &DeadInsts, Module *M);
- bool
- PairUpRetainsAndReleases(DenseMap<const BasicBlock *, BBState> &BBStates,
- BlotMapVector<Value *, RRInfo> &Retains,
- DenseMap<Value *, RRInfo> &Releases, Module *M,
- Instruction * Retain,
- SmallVectorImpl<Instruction *> &DeadInsts,
- RRInfo &RetainsToMove, RRInfo &ReleasesToMove,
- Value *Arg, bool KnownSafe,
- bool &AnyPairsCompletelyEliminated);
+ bool PairUpRetainsAndReleases(DenseMap<const BasicBlock *, BBState> &BBStates,
+ BlotMapVector<Value *, RRInfo> &Retains,
+ DenseMap<Value *, RRInfo> &Releases, Module *M,
+ Instruction *Retain,
+ SmallVectorImpl<Instruction *> &DeadInsts,
+ RRInfo &RetainsToMove, RRInfo &ReleasesToMove,
+ Value *Arg, bool KnownSafe,
+ bool &AnyPairsCompletelyEliminated);
- bool PerformCodePlacement(DenseMap<const BasicBlock *, BBState> &BBStates,
- BlotMapVector<Value *, RRInfo> &Retains,
- DenseMap<Value *, RRInfo> &Releases, Module *M);
+ bool PerformCodePlacement(DenseMap<const BasicBlock *, BBState> &BBStates,
+ BlotMapVector<Value *, RRInfo> &Retains,
+ DenseMap<Value *, RRInfo> &Releases, Module *M);
- void OptimizeWeakCalls(Function &F);
+ void OptimizeWeakCalls(Function &F);
- bool OptimizeSequences(Function &F);
+ bool OptimizeSequences(Function &F);
- void OptimizeReturns(Function &F);
+ void OptimizeReturns(Function &F);
#ifndef NDEBUG
- void GatherStatistics(Function &F, bool AfterOptimization = false);
+ void GatherStatistics(Function &F, bool AfterOptimization = false);
#endif
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- bool doInitialization(Module &M) override;
- bool runOnFunction(Function &F) override;
- void releaseMemory() override;
-
public:
- static char ID;
+ void init(Module &M);
+ bool run(Function &F, AAResults &AA);
+ void releaseMemory();
+};
- ObjCARCOpt() : FunctionPass(ID) {
- initializeObjCARCOptPass(*PassRegistry::getPassRegistry());
- }
- };
+/// The main ARC optimization pass.
+class ObjCARCOptLegacyPass : public FunctionPass {
+public:
+ ObjCARCOptLegacyPass() : FunctionPass(ID) {
+ initializeObjCARCOptLegacyPassPass(*PassRegistry::getPassRegistry());
+ }
+ void getAnalysisUsage(AnalysisUsage &AU) const override;
+ bool doInitialization(Module &M) override {
+ OCAO.init(M);
+ return false;
+ }
+ bool runOnFunction(Function &F) override {
+ return OCAO.run(F, getAnalysis<AAResultsWrapperPass>().getAAResults());
+ }
+ void releaseMemory() override { OCAO.releaseMemory(); }
+ static char ID;
+private:
+ ObjCARCOpt OCAO;
+};
} // end anonymous namespace
-char ObjCARCOpt::ID = 0;
+char ObjCARCOptLegacyPass::ID = 0;
-INITIALIZE_PASS_BEGIN(ObjCARCOpt,
- "objc-arc", "ObjC ARC optimization", false, false)
+INITIALIZE_PASS_BEGIN(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization",
+ false, false)
INITIALIZE_PASS_DEPENDENCY(ObjCARCAAWrapperPass)
-INITIALIZE_PASS_END(ObjCARCOpt,
- "objc-arc", "ObjC ARC optimization", false, false)
+INITIALIZE_PASS_END(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization",
+ false, false)
-Pass *llvm::createObjCARCOptPass() {
- return new ObjCARCOpt();
-}
+Pass *llvm::createObjCARCOptPass() { return new ObjCARCOptLegacyPass(); }
-void ObjCARCOpt::getAnalysisUsage(AnalysisUsage &AU) const {
+void ObjCARCOptLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<ObjCARCAAWrapperPass>();
AU.addRequired<AAResultsWrapperPass>();
// ARC optimization doesn't currently split critical edges.
@@ -664,7 +675,7 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
SmallVector<const Value *, 4> ArgUsers;
getEquivalentPHIs(*PN, ArgUsers);
- if (llvm::find(ArgUsers, AutoreleaseRVArg) == ArgUsers.end())
+ if (!llvm::is_contained(ArgUsers, AutoreleaseRVArg))
return false;
}
@@ -1114,8 +1125,7 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(
if (!HasNull)
continue;
- SmallPtrSet<Instruction *, 4> DependingInstructions;
- SmallPtrSet<const BasicBlock *, 4> Visited;
+ Instruction *DepInst = nullptr;
// Check that there is nothing that cares about the reference
// count between the call and the phi.
@@ -1127,13 +1137,13 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(
case ARCInstKind::Release:
// These can't be moved across things that care about the retain
// count.
- FindDependencies(NeedsPositiveRetainCount, Arg, Inst->getParent(), Inst,
- DependingInstructions, Visited, PA);
+ DepInst = findSingleDependency(NeedsPositiveRetainCount, Arg,
+ Inst->getParent(), Inst, PA);
break;
case ARCInstKind::Autorelease:
// These can't be moved across autorelease pool scope boundaries.
- FindDependencies(AutoreleasePoolBoundary, Arg, Inst->getParent(), Inst,
- DependingInstructions, Visited, PA);
+ DepInst = findSingleDependency(AutoreleasePoolBoundary, Arg,
+ Inst->getParent(), Inst, PA);
break;
case ARCInstKind::ClaimRV:
case ARCInstKind::RetainRV:
@@ -1147,9 +1157,7 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(
llvm_unreachable("Invalid dependence flavor");
}
- if (DependingInstructions.size() != 1)
- continue;
- if (*DependingInstructions.begin() != PN)
+ if (DepInst != PN)
continue;
Changed = true;
@@ -2223,25 +2231,21 @@ bool ObjCARCOpt::OptimizeSequences(Function &F) {
/// Check if there is a dependent call earlier that does not have anything in
/// between the Retain and the call that can affect the reference count of their
/// shared pointer argument. Note that Retain need not be in BB.
-static bool
-HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain,
- SmallPtrSetImpl<Instruction *> &DepInsts,
- SmallPtrSetImpl<const BasicBlock *> &Visited,
- ProvenanceAnalysis &PA) {
- FindDependencies(CanChangeRetainCount, Arg, Retain->getParent(), Retain,
- DepInsts, Visited, PA);
- if (DepInsts.size() != 1)
- return false;
-
- auto *Call = dyn_cast_or_null<CallInst>(*DepInsts.begin());
+static CallInst *HasSafePathToPredecessorCall(const Value *Arg,
+ Instruction *Retain,
+ ProvenanceAnalysis &PA) {
+ auto *Call = dyn_cast_or_null<CallInst>(findSingleDependency(
+ CanChangeRetainCount, Arg, Retain->getParent(), Retain, PA));
// Check that the pointer is the return value of the call.
if (!Call || Arg != Call)
- return false;
+ return nullptr;
// Check that the call is a regular call.
ARCInstKind Class = GetBasicARCInstKind(Call);
- return Class == ARCInstKind::CallOrUser || Class == ARCInstKind::Call;
+ return Class == ARCInstKind::CallOrUser || Class == ARCInstKind::Call
+ ? Call
+ : nullptr;
}
/// Find a dependent retain that precedes the given autorelease for which there
@@ -2250,15 +2254,9 @@ HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain,
static CallInst *
FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB,
Instruction *Autorelease,
- SmallPtrSetImpl<Instruction *> &DepInsts,
- SmallPtrSetImpl<const BasicBlock *> &Visited,
ProvenanceAnalysis &PA) {
- FindDependencies(CanChangeRetainCount, Arg,
- BB, Autorelease, DepInsts, Visited, PA);
- if (DepInsts.size() != 1)
- return nullptr;
-
- auto *Retain = dyn_cast_or_null<CallInst>(*DepInsts.begin());
+ auto *Retain = dyn_cast_or_null<CallInst>(
+ findSingleDependency(CanChangeRetainCount, Arg, BB, Autorelease, PA));
// Check that we found a retain with the same argument.
if (!Retain || !IsRetain(GetBasicARCInstKind(Retain)) ||
@@ -2275,15 +2273,11 @@ FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB,
static CallInst *
FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB,
ReturnInst *Ret,
- SmallPtrSetImpl<Instruction *> &DepInsts,
- SmallPtrSetImpl<const BasicBlock *> &V,
ProvenanceAnalysis &PA) {
- FindDependencies(NeedsPositiveRetainCount, Arg,
- BB, Ret, DepInsts, V, PA);
- if (DepInsts.size() != 1)
- return nullptr;
+ SmallPtrSet<Instruction *, 4> DepInsts;
+ auto *Autorelease = dyn_cast_or_null<CallInst>(
+ findSingleDependency(NeedsPositiveRetainCount, Arg, BB, Ret, PA));
- auto *Autorelease = dyn_cast_or_null<CallInst>(*DepInsts.begin());
if (!Autorelease)
return nullptr;
ARCInstKind AutoreleaseClass = GetBasicARCInstKind(Autorelease);
@@ -2309,8 +2303,6 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeReturns ==\n");
- SmallPtrSet<Instruction *, 4> DependingInstructions;
- SmallPtrSet<const BasicBlock *, 4> Visited;
for (BasicBlock &BB: F) {
ReturnInst *Ret = dyn_cast<ReturnInst>(&BB.back());
if (!Ret)
@@ -2323,40 +2315,27 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
// Look for an ``autorelease'' instruction that is a predecessor of Ret and
// dependent on Arg such that there are no instructions dependent on Arg
// that need a positive ref count in between the autorelease and Ret.
- CallInst *Autorelease = FindPredecessorAutoreleaseWithSafePath(
- Arg, &BB, Ret, DependingInstructions, Visited, PA);
- DependingInstructions.clear();
- Visited.clear();
+ CallInst *Autorelease =
+ FindPredecessorAutoreleaseWithSafePath(Arg, &BB, Ret, PA);
if (!Autorelease)
continue;
CallInst *Retain = FindPredecessorRetainWithSafePath(
- Arg, Autorelease->getParent(), Autorelease, DependingInstructions,
- Visited, PA);
- DependingInstructions.clear();
- Visited.clear();
+ Arg, Autorelease->getParent(), Autorelease, PA);
if (!Retain)
continue;
// Check that there is nothing that can affect the reference count
// between the retain and the call. Note that Retain need not be in BB.
- bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain,
- DependingInstructions,
- Visited, PA);
+ CallInst *Call = HasSafePathToPredecessorCall(Arg, Retain, PA);
// Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call.
- if (HasSafePathToCall &&
- GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV &&
- GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV &&
- !cast<CallInst>(*DependingInstructions.begin())->isTailCall())
- continue;
-
- DependingInstructions.clear();
- Visited.clear();
-
- if (!HasSafePathToCall)
+ if (!Call ||
+ (!Call->isTailCall() &&
+ GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV &&
+ GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV))
continue;
// If so, we can zap the retain and autorelease.
@@ -2393,14 +2372,14 @@ ObjCARCOpt::GatherStatistics(Function &F, bool AfterOptimization) {
}
#endif
-bool ObjCARCOpt::doInitialization(Module &M) {
+void ObjCARCOpt::init(Module &M) {
if (!EnableARCOpts)
- return false;
+ return;
// If nothing in the Module uses ARC, don't do anything.
Run = ModuleHasARC(M);
if (!Run)
- return false;
+ return;
// Intuitively, objc_retain and others are nocapture, however in practice
// they are not, because they return their argument value. And objc_release
@@ -2409,11 +2388,9 @@ bool ObjCARCOpt::doInitialization(Module &M) {
// Initialize our runtime entry point cache.
EP.init(&M);
-
- return false;
}
-bool ObjCARCOpt::runOnFunction(Function &F) {
+bool ObjCARCOpt::run(Function &F, AAResults &AA) {
if (!EnableARCOpts)
return false;
@@ -2427,7 +2404,7 @@ bool ObjCARCOpt::runOnFunction(Function &F) {
<< " >>>"
"\n");
- PA.setAA(&getAnalysis<AAResultsWrapperPass>().getAAResults());
+ PA.setAA(&AA);
#ifndef NDEBUG
if (AreStatisticsEnabled()) {
@@ -2484,3 +2461,17 @@ void ObjCARCOpt::releaseMemory() {
/// @}
///
+
+PreservedAnalyses ObjCARCOptPass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ ObjCARCOpt OCAO;
+ OCAO.init(*F.getParent());
+
+ bool Changed = OCAO.run(F, AM.getResult<AAManager>(F));
+ if (Changed) {
+ PreservedAnalyses PA;
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+ }
+ return PreservedAnalyses::all();
+}