@@ -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 (Pred->getContext (),
2545+ 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