summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/ObjCARC
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/ObjCARC')
-rw-r--r--llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h6
-rw-r--r--llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp5
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARC.h12
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp15
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp40
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp2
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp73
7 files changed, 72 insertions, 81 deletions
diff --git a/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h b/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
index e1e95cd6a4075..258dc92408150 100644
--- a/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
+++ b/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
@@ -22,19 +22,15 @@
#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_ARCRUNTIMEENTRYPOINTS_H
#define LLVM_LIB_TRANSFORMS_OBJCARC_ARCRUNTIMEENTRYPOINTS_H
-#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Attributes.h"
-#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
namespace llvm {
class Function;
-class LLVMContext;
+class Module;
namespace objcarc {
diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
index e8f8fb6f3a7c0..46bc586fe688a 100644
--- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
+++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp
@@ -95,10 +95,9 @@ bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr,
// of any other dynamic reference-counted pointers.
if (!IsPotentialRetainableObjPtr(ICI->getOperand(1), *PA.getAA()))
return false;
- } else if (auto CS = ImmutableCallSite(Inst)) {
+ } else if (const auto *CS = dyn_cast<CallBase>(Inst)) {
// For calls, just check the arguments (and not the callee operand).
- for (ImmutableCallSite::arg_iterator OI = CS.arg_begin(),
- OE = CS.arg_end(); OI != OE; ++OI) {
+ for (auto OI = CS->arg_begin(), OE = CS->arg_end(); OI != OE; ++OI) {
const Value *Op = *OI;
if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) &&
PA.related(Ptr, Op, DL))
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h
index d465630800b9a..b496842fcfc5d 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h
@@ -22,24 +22,12 @@
#ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
#define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Analysis/AliasAnalysis.h"
#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"
namespace llvm {
-class raw_ostream;
-}
-
-namespace llvm {
namespace objcarc {
/// Erase the given instruction.
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
index 7a01ec967fb5d..ac1db27f5e64c 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
@@ -41,7 +41,7 @@ namespace {
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnModule(Module &M) override;
- static bool MayAutorelease(ImmutableCallSite CS, unsigned Depth = 0);
+ static bool MayAutorelease(const CallBase &CB, unsigned Depth = 0);
static bool OptimizeBB(BasicBlock *BB);
public:
@@ -68,18 +68,17 @@ void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const {
/// Interprocedurally determine if calls made by the given call site can
/// possibly produce autoreleases.
-bool ObjCARCAPElim::MayAutorelease(ImmutableCallSite CS, unsigned Depth) {
- if (const Function *Callee = CS.getCalledFunction()) {
+bool ObjCARCAPElim::MayAutorelease(const CallBase &CB, unsigned Depth) {
+ if (const Function *Callee = CB.getCalledFunction()) {
if (!Callee->hasExactDefinition())
return true;
for (const BasicBlock &BB : *Callee) {
for (const Instruction &I : BB)
- if (ImmutableCallSite JCS = ImmutableCallSite(&I))
+ if (const CallBase *JCB = dyn_cast<CallBase>(&I))
// This recursion depth limit is arbitrary. It's just great
// enough to cover known interesting testcases.
- if (Depth < 3 &&
- !JCS.onlyReadsMemory() &&
- MayAutorelease(JCS, Depth + 1))
+ if (Depth < 3 && !JCB->onlyReadsMemory() &&
+ MayAutorelease(*JCB, Depth + 1))
return true;
}
return false;
@@ -115,7 +114,7 @@ bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) {
Push = nullptr;
break;
case ARCInstKind::CallOrUser:
- if (MayAutorelease(ImmutableCallSite(Inst)))
+ if (MayAutorelease(cast<CallBase>(*Inst)))
Push = nullptr;
break;
default:
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
index ecf8220ae95da..7fd4857c44903 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
@@ -33,6 +33,7 @@
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Operator.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
@@ -47,10 +48,6 @@ using namespace llvm::objcarc;
STATISTIC(NumPeeps, "Number of calls peephole-optimized");
STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
-static cl::opt<unsigned> MaxBBSize("arc-contract-max-bb-size", cl::Hidden,
- cl::desc("Maximum basic block size to discover the dominance relation of "
- "two instructions in the same basic block"), cl::init(65535));
-
//===----------------------------------------------------------------------===//
// Declarations
//===----------------------------------------------------------------------===//
@@ -119,8 +116,7 @@ namespace {
/// return value. We do this late so we do not disrupt the dataflow analysis in
/// ObjCARCOpt.
bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) {
- ImmutableCallSite CS(GetArgRCIdentityRoot(Retain));
- const Instruction *Call = CS.getInstruction();
+ const auto *Call = dyn_cast<CallBase>(GetArgRCIdentityRoot(Retain));
if (!Call)
return false;
if (Call->getParent() != Retain->getParent())
@@ -534,6 +530,7 @@ bool ObjCARCContract::tryToPeepholeInstruction(
return true;
case ARCInstKind::IntrinsicUser:
// Remove calls to @llvm.objc.clang.arc.use(...).
+ Changed = true;
Inst->eraseFromParent();
return true;
default:
@@ -580,23 +577,6 @@ bool ObjCARCContract::runOnFunction(Function &F) {
SmallPtrSet<Instruction *, 4> DependingInstructions;
SmallPtrSet<const BasicBlock *, 4> Visited;
- // Cache the basic block size.
- DenseMap<const BasicBlock *, unsigned> BBSizeMap;
-
- // A lambda that lazily computes the size of a basic block and determines
- // whether the size exceeds MaxBBSize.
- auto IsLargeBB = [&](const BasicBlock *BB) {
- unsigned BBSize;
- auto I = BBSizeMap.find(BB);
-
- if (I != BBSizeMap.end())
- BBSize = I->second;
- else
- BBSize = BBSizeMap[BB] = BB->size();
-
- return BBSize > MaxBBSize;
- };
-
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) {
Instruction *Inst = &*I++;
@@ -614,7 +594,7 @@ bool ObjCARCContract::runOnFunction(Function &F) {
// and such; to do the replacement, the argument must have type i8*.
// Function for replacing uses of Arg dominated by Inst.
- auto ReplaceArgUses = [Inst, IsLargeBB, this](Value *Arg) {
+ auto ReplaceArgUses = [Inst, this](Value *Arg) {
// If we're compiling bugpointed code, don't get in trouble.
if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
return;
@@ -626,17 +606,6 @@ bool ObjCARCContract::runOnFunction(Function &F) {
Use &U = *UI++;
unsigned OperandNo = U.getOperandNo();
- // Don't replace the uses if Inst and the user belong to the same basic
- // block and the size of the basic block is large. We don't want to call
- // DominatorTree::dominate in that case. We can remove this check if we
- // can use OrderedBasicBlock to compute the dominance relation between
- // two instructions, but that's not currently possible since it doesn't
- // recompute the instruction ordering when new instructions are inserted
- // to the basic block.
- if (Inst->getParent() == cast<Instruction>(U.getUser())->getParent() &&
- IsLargeBB(Inst->getParent()))
- continue;
-
// If the call's return value dominates a use of the call's argument
// value, rewrite the use to use the return value. We check for
// reachability here because an unreachable call is considered to
@@ -689,7 +658,6 @@ bool ObjCARCContract::runOnFunction(Function &F) {
}
};
-
Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
Value *OrigArg = Arg;
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp
index 205d8ddf151de..f8d872a7c9956 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp
@@ -30,9 +30,7 @@
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
-#include "llvm/PassAnalysisSupport.h"
#include "llvm/PassRegistry.h"
-#include "llvm/PassSupport.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index b80c1675050bf..cb1fa804fa114 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -43,7 +43,6 @@
#include "llvm/Analysis/ObjCARCInstKind.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
-#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
@@ -610,8 +609,7 @@ bool
ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
// Check for the argument being from an immediately preceding call or invoke.
const Value *Arg = GetArgRCIdentityRoot(RetainRV);
- ImmutableCallSite CS(Arg);
- if (const Instruction *Call = CS.getInstruction()) {
+ if (const Instruction *Call = dyn_cast<CallBase>(Arg)) {
if (Call->getParent() == RetainRV->getParent()) {
BasicBlock::const_iterator I(Call);
++I;
@@ -678,6 +676,7 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
// Delete the RV pair, starting with the AutoreleaseRV.
AutoreleaseRV->replaceAllUsesWith(
cast<CallInst>(AutoreleaseRV)->getArgOperand(0));
+ Changed = true;
EraseInstruction(AutoreleaseRV);
if (Class == ARCInstKind::RetainRV) {
// AutoreleaseRV and RetainRV cancel out. Delete the RetainRV.
@@ -877,23 +876,49 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
optimizeDelayedAutoreleaseRV();
}
+/// This function returns true if the value is inert. An ObjC ARC runtime call
+/// taking an inert operand can be safely deleted.
+static bool isInertARCValue(Value *V, SmallPtrSet<Value *, 1> &VisitedPhis) {
+ V = V->stripPointerCasts();
+
+ if (IsNullOrUndef(V))
+ return true;
+
+ // See if this is a global attribute annotated with an 'objc_arc_inert'.
+ if (auto *GV = dyn_cast<GlobalVariable>(V))
+ if (GV->hasAttribute("objc_arc_inert"))
+ return true;
+
+ if (auto PN = dyn_cast<PHINode>(V)) {
+ // Ignore this phi if it has already been discovered.
+ if (!VisitedPhis.insert(PN).second)
+ return true;
+ // Look through phis's operands.
+ for (Value *Opnd : PN->incoming_values())
+ if (!isInertARCValue(Opnd, VisitedPhis))
+ return false;
+ return true;
+ }
+
+ return false;
+}
+
void ObjCARCOpt::OptimizeIndividualCallImpl(
Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
Instruction *Inst, ARCInstKind Class, const Value *Arg) {
LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n");
- // Some of the ARC calls can be deleted if their arguments are global
- // variables that are inert in ARC.
- if (IsNoopOnGlobal(Class)) {
- Value *Opnd = Inst->getOperand(0);
- if (auto *GV = dyn_cast<GlobalVariable>(Opnd->stripPointerCasts()))
- if (GV->hasAttribute("objc_arc_inert")) {
- if (!Inst->getType()->isVoidTy())
- Inst->replaceAllUsesWith(Opnd);
- Inst->eraseFromParent();
- return;
- }
- }
+ // We can delete this call if it takes an inert value.
+ SmallPtrSet<Value *, 1> VisitedPhis;
+
+ if (IsNoopOnGlobal(Class))
+ if (isInertARCValue(Inst->getOperand(0), VisitedPhis)) {
+ if (!Inst->getType()->isVoidTy())
+ Inst->replaceAllUsesWith(Inst->getOperand(0));
+ Inst->eraseFromParent();
+ Changed = true;
+ return;
+ }
switch (Class) {
default:
@@ -1544,6 +1569,15 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
}
}
+ // Check that BB and MyStates have the same number of predecessors. This
+ // prevents retain calls that live outside a loop from being moved into the
+ // loop.
+ if (!BB->hasNPredecessors(MyStates.pred_end() - MyStates.pred_begin()))
+ for (auto I = MyStates.top_down_ptr_begin(),
+ E = MyStates.top_down_ptr_end();
+ I != E; ++I)
+ I->second.SetCFGHazardAfflicted(true);
+
LLVM_DEBUG(dbgs() << "Before:\n"
<< BBStates[BB] << "\n"
<< "Performing Dataflow:\n");
@@ -2020,6 +2054,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) {
// Delete objc_loadWeak calls with no users.
if (Class == ARCInstKind::LoadWeak && Inst->use_empty()) {
Inst->eraseFromParent();
+ Changed = true;
continue;
}
@@ -2310,6 +2345,14 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain,
DependingInstructions,
Visited, PA);
+
+ // Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call.
+ if (HasSafePathToCall &&
+ GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV &&
+ GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV &&
+ !cast<CallInst>(*DependingInstructions.begin())->isTailCall())
+ continue;
+
DependingInstructions.clear();
Visited.clear();