Skip to content

Commit 2c2afa6

Browse files
committed
Think in terms of blocks
Handle critical edges for ObjCARC
1 parent dcec224 commit 2c2afa6

File tree

10 files changed

+2852
-1060
lines changed

10 files changed

+2852
-1060
lines changed

llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,6 @@ static const Value *FindSingleUseIdentifiedObject(const Value *Arg) {
138138
// calls followed by objc_autoreleasePoolPop calls (perhaps in ObjC++ code
139139
// after inlining) can be turned into plain release calls.
140140

141-
// TODO: Critical-edge splitting. If the optimial insertion point is
142-
// a critical edge, the current algorithm has to fail, because it doesn't
143-
// know how to split edges. It should be possible to make the optimizer
144-
// think in terms of edges, rather than blocks, and then split critical
145-
// edges on demand.
146-
147141
// TODO: OptimizeSequences could generalized to be Interprocedural.
148142

149143
// TODO: Recognize that a bunch of other objc runtime calls have
@@ -599,6 +593,7 @@ class ObjCARCOpt {
599593
void init(Function &F);
600594
bool run(Function &F, AAResults &AA);
601595
bool hasCFGChanged() const { return CFGChanged; }
596+
BasicBlock *SplitCriticalEdge(BasicBlock *Pred, BasicBlock *Succ);
602597
};
603598
} // end anonymous namespace
604599

@@ -1765,8 +1760,50 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
17651760
Module *M) {
17661761
LLVM_DEBUG(dbgs() << "== ObjCARCOpt::MoveCalls ==\n");
17671762

1768-
// Insert the new retain and release calls.
1763+
// First, handle critical edges for retain insertion points
1764+
SmallVector<Instruction *, 4> NewRetainInsertPts;
1765+
for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) {
1766+
BasicBlock *BB = InsertPt->getParent();
1767+
BasicBlock *Pred = BB->getUniquePredecessor();
1768+
1769+
// If this is a critical edge, split it
1770+
if (!Pred && BB->hasNPredecessors(1)) {
1771+
for (BasicBlock *PredBB : predecessors(BB)) {
1772+
if (PredBB->getTerminator()->getNumSuccessors() > 1) {
1773+
if (BasicBlock *NewBB = SplitCriticalEdge(PredBB, BB)) {
1774+
// Add the new block as an insertion point
1775+
NewRetainInsertPts.push_back(NewBB->getTerminator());
1776+
}
1777+
}
1778+
}
1779+
} else {
1780+
NewRetainInsertPts.push_back(InsertPt);
1781+
}
1782+
}
1783+
1784+
// Then handle critical edges for release insertion points
1785+
SmallVector<Instruction *, 4> NewReleaseInsertPts;
17691786
for (Instruction *InsertPt : ReleasesToMove.ReverseInsertPts) {
1787+
BasicBlock *BB = InsertPt->getParent();
1788+
BasicBlock *Pred = BB->getUniquePredecessor();
1789+
1790+
// If this is a critical edge, split it
1791+
if (!Pred && BB->hasNPredecessors(1)) {
1792+
for (BasicBlock *PredBB : predecessors(BB)) {
1793+
if (PredBB->getTerminator()->getNumSuccessors() > 1) {
1794+
if (BasicBlock *NewBB = SplitCriticalEdge(PredBB, BB)) {
1795+
// Add the new block as an insertion point
1796+
NewReleaseInsertPts.push_back(NewBB->getTerminator());
1797+
}
1798+
}
1799+
}
1800+
} else {
1801+
NewReleaseInsertPts.push_back(InsertPt);
1802+
}
1803+
}
1804+
1805+
// Now insert the new retain calls at the split points
1806+
for (Instruction *InsertPt : NewRetainInsertPts) {
17701807
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);
17711808
SmallVector<OperandBundleDef, 1> BundleList;
17721809
addOpBundleForFunclet(InsertPt->getParent(), BundleList);
@@ -1780,7 +1817,9 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
17801817
"At insertion point: "
17811818
<< *InsertPt << "\n");
17821819
}
1783-
for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) {
1820+
1821+
// And insert the new release calls at the split points
1822+
for (Instruction *InsertPt : NewReleaseInsertPts) {
17841823
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release);
17851824
SmallVector<OperandBundleDef, 1> BundleList;
17861825
addOpBundleForFunclet(InsertPt->getParent(), BundleList);
@@ -2488,6 +2527,53 @@ bool ObjCARCOpt::run(Function &F, AAResults &AA) {
24882527
return Changed;
24892528
}
24902529

2530+
/// Split critical edges where we need to insert retain/release calls
2531+
BasicBlock *ObjCARCOpt::SplitCriticalEdge(BasicBlock *Pred, BasicBlock *Succ) {
2532+
// Don't split if either block is a landing pad - we want to maintain
2533+
// the property that landing pads have exactly one predecessor
2534+
if (Succ->isLandingPad() || isa<InvokeInst>(Pred->getTerminator()))
2535+
return nullptr;
2536+
2537+
// We need both multiple successors in predecessor and
2538+
// multiple predecessors in successor
2539+
if (Pred->getTerminator()->getNumSuccessors() <= 1 ||
2540+
Succ->getUniquePredecessor())
2541+
return nullptr;
2542+
2543+
// Create a new basic block for the split edge
2544+
BasicBlock *NewBB = BasicBlock::Create(
2545+
Pred->getContext(), Pred->getName() + "." + Succ->getName() + ".arc",
2546+
Pred->getParent());
2547+
2548+
// Update the terminator of Pred to branch to NewBB instead of Succ
2549+
BranchInst *Term = cast<BranchInst>(Pred->getTerminator());
2550+
for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
2551+
if (Term->getSuccessor(i) == Succ) {
2552+
Term->setSuccessor(i, NewBB);
2553+
break;
2554+
}
2555+
}
2556+
2557+
// Create an unconditional branch from NewBB to Succ
2558+
BranchInst::Create(Succ, NewBB);
2559+
2560+
// Update PHI nodes in Succ
2561+
for (PHINode &PHI : Succ->phis()) {
2562+
Value *V = PHI.getIncomingValueForBlock(Pred);
2563+
PHI.setIncomingBlock(PHI.getBasicBlockIndex(Pred), NewBB);
2564+
PHI.addIncoming(V, Pred);
2565+
}
2566+
2567+
// Update any funclet bundles
2568+
if (!BlockEHColors.empty()) {
2569+
const ColorVector &CV = BlockEHColors.find(Pred)->second;
2570+
BlockEHColors[NewBB] = CV;
2571+
}
2572+
2573+
CFGChanged = true;
2574+
return NewBB;
2575+
}
2576+
24912577
/// @}
24922578
///
24932579

0 commit comments

Comments
 (0)