bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU,
LoopInfo *LI, MemorySSAUpdater *MSSAU,
MemoryDependenceResults *MemDep,
- bool PredecessorWithTwoSuccessors) {
+ bool PredecessorWithTwoSuccessors,
+ DominatorTree *DT) {
if (BB->hasAddressTaken())
return false;
FoldSingleEntryPHINodes(BB, MemDep);
}
+ if (DT) {
+ assert(!DTU && "cannot use both DT and DTU for updates");
+ DomTreeNode *PredNode = DT->getNode(PredBB);
+ DomTreeNode *BBNode = DT->getNode(BB);
+ if (PredNode) {
+ assert(BBNode && "PredNode unreachable but BBNode reachable?");
+ for (DomTreeNode *C : to_vector(BBNode->children()))
+ C->setIDom(PredNode);
+ }
+ }
// DTU update: Collect all the edges that exit BB.
// These dominator edges will be redirected from Pred.
std::vector<DominatorTree::UpdateType> Updates;
if (DTU) {
+ assert(!DT && "cannot use both DT and DTU for updates");
// To avoid processing the same predecessor more than once.
SmallPtrSet<BasicBlock *, 8> SeenSuccs;
SmallPtrSet<BasicBlock *, 2> SuccsOfPredBB(succ_begin(PredBB),
if (DTU)
DTU->applyUpdates(Updates);
+ if (DT) {
+ assert(succ_empty(BB) &&
+ "successors should have been transferred to PredBB");
+ DT->eraseNode(BB);
+ }
+
// Finally, erase the old block and update dominator info.
DeleteDeadBlock(BB, DTU);
unsigned TripMultiple;
unsigned BreakoutTrip;
bool ExitOnTrue;
+ BasicBlock *FirstExitingBlock = nullptr;
SmallVector<BasicBlock *> ExitingBlocks;
};
DenseMap<BasicBlock *, ExitInfo> ExitInfos;
assert(!UnrollVerifyDomtree ||
DT->verify(DominatorTree::VerificationLevel::Fast));
- DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
-
+ SmallVector<DominatorTree::UpdateType> DTUpdates;
auto SetDest = [&](BasicBlock *Src, bool WillExit, bool ExitOnTrue) {
auto *Term = cast<BranchInst>(Src->getTerminator());
const unsigned Idx = ExitOnTrue ^ WillExit;
BranchInst::Create(Dest, Term);
Term->eraseFromParent();
- DTU.applyUpdates({{DominatorTree::Delete, Src, DeadSucc}});
+ DTUpdates.emplace_back(DominatorTree::Delete, Src, DeadSucc);
};
auto WillExit = [&](const ExitInfo &Info, unsigned i, unsigned j,
// Fold branches for iterations where we know that they will exit or not
// exit.
- for (const auto &Pair : ExitInfos) {
- const ExitInfo &Info = Pair.second;
+ for (auto &Pair : ExitInfos) {
+ ExitInfo &Info = Pair.second;
for (unsigned i = 0, e = Info.ExitingBlocks.size(); i != e; ++i) {
// The branch destination.
unsigned j = (i + 1) % e;
bool IsLatch = Pair.first == LatchBlock;
std::optional<bool> KnownWillExit = WillExit(Info, i, j, IsLatch);
- if (!KnownWillExit)
+ if (!KnownWillExit) {
+ if (!Info.FirstExitingBlock)
+ Info.FirstExitingBlock = Info.ExitingBlocks[i];
continue;
+ }
// We don't fold known-exiting branches for non-latch exits here,
// because this ensures that both all loop blocks and all exit blocks
// remain reachable in the CFG.
// TODO: We could fold these branches, but it would require much more
// sophisticated updates to LoopInfo.
- if (*KnownWillExit && !IsLatch)
+ if (*KnownWillExit && !IsLatch) {
+ if (!Info.FirstExitingBlock)
+ Info.FirstExitingBlock = Info.ExitingBlocks[i];
continue;
+ }
SetDest(Info.ExitingBlocks[i], *KnownWillExit, Info.ExitOnTrue);
}
}
+ DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+ DomTreeUpdater *DTUToUse = &DTU;
+ if (ExitingBlocks.size() == 1) {
+ // Manually update the DT if there's a single exiting node. In that case
+ // there's a single exit node and it is sufficient to update the nodes
+ // immediately dominated by the original exiting block. They will become
+ // dominated by the first exiting block that leaves the loop after
+ // unrolling. Note that the CFG inside the loop does not change, so there's
+ // no need to update the DT inside the unrolled loop.
+ DTUToUse = nullptr;
+ auto &[OriginalExit, Info] = *ExitInfos.begin();
+ if (!Info.FirstExitingBlock)
+ Info.FirstExitingBlock = Info.ExitingBlocks.back();
+ for (auto *C : to_vector(DT->getNode(OriginalExit)->children())) {
+ if (L->contains(C->getBlock()))
+ continue;
+ C->setIDom(DT->getNode(Info.FirstExitingBlock));
+ }
+ } else {
+ DTU.applyUpdates(DTUpdates);
+ }
+
// When completely unrolling, the last latch becomes unreachable.
if (!LatchIsExiting && CompletelyUnroll) {
// There is no need to update the DT here, because there must be a unique
if (Term && Term->isUnconditional()) {
BasicBlock *Dest = Term->getSuccessor(0);
BasicBlock *Fold = Dest->getUniquePredecessor();
- if (MergeBlockIntoPredecessor(Dest, &DTU, LI)) {
+ if (MergeBlockIntoPredecessor(Dest, /*DTU=*/DTUToUse, LI,
+ /*MSSAU=*/nullptr, /*MemDep=*/nullptr,
+ /*PredecessorWithTwoSuccessors=*/false,
+ DTUToUse ? nullptr : DT)) {
// Dest has been folded into Fold. Update our worklists accordingly.
std::replace(Latches.begin(), Latches.end(), Dest, Fold);
llvm::erase_value(UnrolledLoopBlocks, Dest);
}
}
}
- // Apply updates to the DomTree.
- DT = &DTU.getDomTree();
+ if (DTUToUse) {
+ // Apply updates to the DomTree.
+ DT = &DTU.getDomTree();
+ }
assert(!UnrollVerifyDomtree ||
DT->verify(DominatorTree::VerificationLevel::Fast));