aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
diff options
context:
space:
mode:
authorSidharth Baveja <sidharth.baveja@ibm.com>2021-04-06 21:24:40 +0000
committerSidharth Baveja <sidharth.baveja@ibm.com>2021-04-06 21:24:40 +0000
commitd81d9e8b8604c85709de0a22bb8dd672a28f0401 (patch)
tree3f4bfa056b56a0e07c87b6f8872dcc361e9b61a1 /llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
parentc060945b23a1c54d4b2a053ff4b093a2277b303d (diff)
downloadllvm-d81d9e8b8604c85709de0a22bb8dd672a28f0401.zip
llvm-d81d9e8b8604c85709de0a22bb8dd672a28f0401.tar.gz
llvm-d81d9e8b8604c85709de0a22bb8dd672a28f0401.tar.bz2
[SplitEdge] Update SplitCriticalEdge to return a nullptr only when the edge is not critical
Summary: The function SplitCriticalEdge (called by SplitEdge) can return a nullptr in cases where the edge is a critical. SplitEdge uses SplitCriticalEdge assuming it can always split all critical edges, which is an incorrect assumption. The three cases where the function SplitCriticalEdge will return a nullptr is: 1. DestBB is an exception block 2. Options.IgnoreUnreachableDests is set to true and isa(DestBB->getFirstNonPHIOrDbgOrLifetime()) is not equal to a nullptr 3. LoopSimplify form must be preserved (Options.PreserveLoopSimplify is true) and it cannot be maintained for a loop due to indirect branches For each of these situations they are handled in the following way: 1. Modified the function ehAwareSplitEdge originally from llvm/lib/Transforms/Coroutines/CoroFrame.cpp to handle the cases when the DestBB is an exception block. This function is called directly in SplitEdge. SplitEdge does not call SplitCriticalEdge in this case 2. Options.IgnoreUnreachableDests is set to false by default, so this situation does not apply. 3. Return a nullptr in this situation since the SplitCriticalEdge also returned nullptr. Nothing we can do in this case. Reviewed By: asbirlea Differential Revision:https://reviews.llvm.org/D94619
Diffstat (limited to 'llvm/lib/Transforms/Utils/BasicBlockUtils.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/BasicBlockUtils.cpp231
1 files changed, 225 insertions, 6 deletions
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index 2d5f1dd..5364dd9 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -501,13 +501,20 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
const Twine &BBName) {
unsigned SuccNum = GetSuccessorNumber(BB, Succ);
- // If this is a critical edge, let SplitCriticalEdge do it.
Instruction *LatchTerm = BB->getTerminator();
- if (SplitCriticalEdge(
- LatchTerm, SuccNum,
- CriticalEdgeSplittingOptions(DT, LI, MSSAU).setPreserveLCSSA(),
- BBName))
- return LatchTerm->getSuccessor(SuccNum);
+
+ CriticalEdgeSplittingOptions Options =
+ CriticalEdgeSplittingOptions(DT, LI, MSSAU).setPreserveLCSSA();
+
+ if ((isCriticalEdge(LatchTerm, SuccNum, Options.MergeIdenticalEdges))) {
+ // If it is a critical edge, and the succesor is an exception block, handle
+ // the split edge logic in this specific function
+ if (Succ->isEHPad())
+ return ehAwareSplitEdge(BB, Succ, nullptr, nullptr, Options, BBName);
+
+ // If this is a critical edge, let SplitKnownCriticalEdge do it.
+ return SplitKnownCriticalEdge(LatchTerm, SuccNum, Options, BBName);
+ }
// If the edge isn't critical, then BB has a single successor or Succ has a
// single pred. Split the block.
@@ -527,6 +534,218 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
return SplitBlock(BB, BB->getTerminator(), DT, LI, MSSAU, BBName);
}
+void llvm::setUnwindEdgeTo(Instruction *TI, BasicBlock *Succ) {
+ if (auto *II = dyn_cast<InvokeInst>(TI))
+ II->setUnwindDest(Succ);
+ else if (auto *CS = dyn_cast<CatchSwitchInst>(TI))
+ CS->setUnwindDest(Succ);
+ else if (auto *CR = dyn_cast<CleanupReturnInst>(TI))
+ CR->setUnwindDest(Succ);
+ else
+ llvm_unreachable("unexpected terminator instruction");
+}
+
+void llvm::updatePhiNodes(BasicBlock *DestBB, BasicBlock *OldPred,
+ BasicBlock *NewPred, PHINode *Until) {
+ int BBIdx = 0;
+ for (PHINode &PN : DestBB->phis()) {
+ // We manually update the LandingPadReplacement PHINode and it is the last
+ // PHI Node. So, if we find it, we are done.
+ if (Until == &PN)
+ break;
+
+ // Reuse the previous value of BBIdx if it lines up. In cases where we
+ // have multiple phi nodes with *lots* of predecessors, this is a speed
+ // win because we don't have to scan the PHI looking for TIBB. This
+ // happens because the BB list of PHI nodes are usually in the same
+ // order.
+ if (PN.getIncomingBlock(BBIdx) != OldPred)
+ BBIdx = PN.getBasicBlockIndex(OldPred);
+
+ assert(BBIdx != -1 && "Invalid PHI Index!");
+ PN.setIncomingBlock(BBIdx, NewPred);
+ }
+}
+
+BasicBlock *llvm::ehAwareSplitEdge(BasicBlock *BB, BasicBlock *Succ,
+ LandingPadInst *OriginalPad,
+ PHINode *LandingPadReplacement,
+ const CriticalEdgeSplittingOptions &Options,
+ const Twine &BBName) {
+
+ auto *PadInst = Succ->getFirstNonPHI();
+ if (!LandingPadReplacement && !PadInst->isEHPad())
+ return SplitEdge(BB, Succ, Options.DT, Options.LI, Options.MSSAU, BBName);
+
+ auto *LI = Options.LI;
+ SmallVector<BasicBlock *, 4> LoopPreds;
+ // Check if extra modifications will be required to preserve loop-simplify
+ // form after splitting. If it would require splitting blocks with IndirectBr
+ // terminators, bail out if preserving loop-simplify form is requested.
+ if (Options.PreserveLoopSimplify && LI) {
+ if (Loop *BBLoop = LI->getLoopFor(BB)) {
+
+ // The only way that we can break LoopSimplify form by splitting a
+ // critical edge is when there exists some edge from BBLoop to Succ *and*
+ // the only edge into Succ from outside of BBLoop is that of NewBB after
+ // the split. If the first isn't true, then LoopSimplify still holds,
+ // NewBB is the new exit block and it has no non-loop predecessors. If the
+ // second isn't true, then Succ was not in LoopSimplify form prior to
+ // the split as it had a non-loop predecessor. In both of these cases,
+ // the predecessor must be directly in BBLoop, not in a subloop, or again
+ // LoopSimplify doesn't hold.
+ for (BasicBlock *P : predecessors(Succ)) {
+ if (P == BB)
+ continue; // The new block is known.
+ if (LI->getLoopFor(P) != BBLoop) {
+ // Loop is not in LoopSimplify form, no need to re simplify after
+ // splitting edge.
+ LoopPreds.clear();
+ break;
+ }
+ LoopPreds.push_back(P);
+ }
+ // Loop-simplify form can be preserved, if we can split all in-loop
+ // predecessors.
+ if (any_of(LoopPreds, [](BasicBlock *Pred) {
+ return isa<IndirectBrInst>(Pred->getTerminator());
+ })) {
+ return nullptr;
+ }
+ }
+ }
+
+ auto *NewBB =
+ BasicBlock::Create(BB->getContext(), BBName, BB->getParent(), Succ);
+ setUnwindEdgeTo(BB->getTerminator(), NewBB);
+ updatePhiNodes(Succ, BB, NewBB, LandingPadReplacement);
+
+ if (LandingPadReplacement) {
+ auto *NewLP = OriginalPad->clone();
+ auto *Terminator = BranchInst::Create(Succ, NewBB);
+ NewLP->insertBefore(Terminator);
+ LandingPadReplacement->addIncoming(NewLP, NewBB);
+ } else {
+ Value *ParentPad = nullptr;
+ if (auto *FuncletPad = dyn_cast<FuncletPadInst>(PadInst))
+ ParentPad = FuncletPad->getParentPad();
+ else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(PadInst))
+ ParentPad = CatchSwitch->getParentPad();
+ else if (auto *CleanupPad = dyn_cast<CleanupPadInst>(PadInst))
+ ParentPad = CleanupPad->getParentPad();
+ else if (auto *LandingPad = dyn_cast<LandingPadInst>(PadInst))
+ ParentPad = LandingPad->getParent();
+ else
+ llvm_unreachable("handling for other EHPads not implemented yet");
+
+ auto *NewCleanupPad = CleanupPadInst::Create(ParentPad, {}, BBName, NewBB);
+ CleanupReturnInst::Create(NewCleanupPad, Succ, NewBB);
+ }
+
+ auto *DT = Options.DT;
+ auto *MSSAU = Options.MSSAU;
+ if (!DT && !LI)
+ return NewBB;
+
+ if (DT) {
+ DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+ SmallVector<DominatorTree::UpdateType, 3> Updates;
+
+ Updates.push_back({DominatorTree::Insert, BB, NewBB});
+ Updates.push_back({DominatorTree::Insert, NewBB, Succ});
+ Updates.push_back({DominatorTree::Delete, BB, Succ});
+
+ DTU.applyUpdates(Updates);
+ DTU.flush();
+
+ if (MSSAU) {
+ MSSAU->applyUpdates(Updates, *DT);
+ if (VerifyMemorySSA)
+ MSSAU->getMemorySSA()->verifyMemorySSA();
+ }
+ }
+
+ if (LI) {
+ if (Loop *BBLoop = LI->getLoopFor(BB)) {
+ // If one or the other blocks were not in a loop, the new block is not
+ // either, and thus LI doesn't need to be updated.
+ if (Loop *SuccLoop = LI->getLoopFor(Succ)) {
+ if (BBLoop == SuccLoop) {
+ // Both in the same loop, the NewBB joins loop.
+ SuccLoop->addBasicBlockToLoop(NewBB, *LI);
+ } else if (BBLoop->contains(SuccLoop)) {
+ // Edge from an outer loop to an inner loop. Add to the outer loop.
+ BBLoop->addBasicBlockToLoop(NewBB, *LI);
+ } else if (SuccLoop->contains(BBLoop)) {
+ // Edge from an inner loop to an outer loop. Add to the outer loop.
+ SuccLoop->addBasicBlockToLoop(NewBB, *LI);
+ } else {
+ // Edge from two loops with no containment relation. Because these
+ // are natural loops, we know that the destination block must be the
+ // header of its loop (adding a branch into a loop elsewhere would
+ // create an irreducible loop).
+ assert(SuccLoop->getHeader() == Succ &&
+ "Should not create irreducible loops!");
+ if (Loop *P = SuccLoop->getParentLoop())
+ P->addBasicBlockToLoop(NewBB, *LI);
+ }
+ }
+
+ // If BB is in a loop and Succ is outside of that loop, we may need to
+ // update LoopSimplify form and LCSSA form.
+ if (!BBLoop->contains(Succ)) {
+ assert(!BBLoop->contains(NewBB) &&
+ "Split point for loop exit is contained in loop!");
+
+ // Update LCSSA form in the newly created exit block.
+ if (Options.PreserveLCSSA) {
+ createPHIsForSplitLoopExit(BB, NewBB, Succ);
+ }
+
+ if (!LoopPreds.empty()) {
+ BasicBlock *NewExitBB = SplitBlockPredecessors(
+ Succ, LoopPreds, "split", DT, LI, MSSAU, Options.PreserveLCSSA);
+ if (Options.PreserveLCSSA)
+ createPHIsForSplitLoopExit(LoopPreds, NewExitBB, Succ);
+ }
+ }
+ }
+ }
+
+ return NewBB;
+}
+
+void llvm::createPHIsForSplitLoopExit(ArrayRef<BasicBlock *> Preds,
+ BasicBlock *SplitBB, BasicBlock *DestBB) {
+ // SplitBB shouldn't have anything non-trivial in it yet.
+ assert((SplitBB->getFirstNonPHI() == SplitBB->getTerminator() ||
+ SplitBB->isLandingPad()) &&
+ "SplitBB has non-PHI nodes!");
+
+ // For each PHI in the destination block.
+ for (PHINode &PN : DestBB->phis()) {
+ int Idx = PN.getBasicBlockIndex(SplitBB);
+ assert(Idx >= 0 && "Invalid Block Index");
+ Value *V = PN.getIncomingValue(Idx);
+
+ // If the input is a PHI which already satisfies LCSSA, don't create
+ // a new one.
+ if (const PHINode *VP = dyn_cast<PHINode>(V))
+ if (VP->getParent() == SplitBB)
+ continue;
+
+ // Otherwise a new PHI is needed. Create one and populate it.
+ PHINode *NewPN = PHINode::Create(
+ PN.getType(), Preds.size(), "split",
+ SplitBB->isLandingPad() ? &SplitBB->front() : SplitBB->getTerminator());
+ for (BasicBlock *BB : Preds)
+ NewPN->addIncoming(V, BB);
+
+ // Update the original PHI.
+ PN.setIncomingValue(Idx, NewPN);
+ }
+}
+
unsigned
llvm::SplitAllCriticalEdges(Function &F,
const CriticalEdgeSplittingOptions &Options) {