summaryrefslogtreecommitdiff
path: root/lib/Transforms/ObjCARC/ObjCARCContract.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/ObjCARC/ObjCARCContract.cpp')
-rw-r--r--lib/Transforms/ObjCARC/ObjCARCContract.cpp177
1 files changed, 117 insertions, 60 deletions
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.