109467b48Spatrick //===- DomTreeUpdater.cpp - DomTree/Post DomTree Updater --------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements the DomTreeUpdater class, which provides a uniform way
1009467b48Spatrick // to update dominator tree related data structures.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick
1409467b48Spatrick #include "llvm/Analysis/DomTreeUpdater.h"
1509467b48Spatrick #include "llvm/ADT/SmallSet.h"
1609467b48Spatrick #include "llvm/Analysis/PostDominators.h"
17*d415bd75Srobert #include "llvm/IR/Constants.h"
18097a140dSpatrick #include "llvm/IR/Instructions.h"
1909467b48Spatrick #include "llvm/Support/GenericDomTree.h"
2009467b48Spatrick #include <algorithm>
2109467b48Spatrick #include <functional>
2209467b48Spatrick #include <utility>
2309467b48Spatrick
2409467b48Spatrick namespace llvm {
2509467b48Spatrick
isUpdateValid(const DominatorTree::UpdateType Update) const2609467b48Spatrick bool DomTreeUpdater::isUpdateValid(
2709467b48Spatrick const DominatorTree::UpdateType Update) const {
2809467b48Spatrick const auto *From = Update.getFrom();
2909467b48Spatrick const auto *To = Update.getTo();
3009467b48Spatrick const auto Kind = Update.getKind();
3109467b48Spatrick
3209467b48Spatrick // Discard updates by inspecting the current state of successors of From.
3309467b48Spatrick // Since isUpdateValid() must be called *after* the Terminator of From is
3409467b48Spatrick // altered we can determine if the update is unnecessary for batch updates
3509467b48Spatrick // or invalid for a single update.
3673471bf0Spatrick const bool HasEdge = llvm::is_contained(successors(From), To);
3709467b48Spatrick
3809467b48Spatrick // If the IR does not match the update,
3909467b48Spatrick // 1. In batch updates, this update is unnecessary.
4009467b48Spatrick // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
4109467b48Spatrick // Edge does not exist in IR.
4209467b48Spatrick if (Kind == DominatorTree::Insert && !HasEdge)
4309467b48Spatrick return false;
4409467b48Spatrick
4509467b48Spatrick // Edge exists in IR.
4609467b48Spatrick if (Kind == DominatorTree::Delete && HasEdge)
4709467b48Spatrick return false;
4809467b48Spatrick
4909467b48Spatrick return true;
5009467b48Spatrick }
5109467b48Spatrick
isSelfDominance(const DominatorTree::UpdateType Update) const5209467b48Spatrick bool DomTreeUpdater::isSelfDominance(
5309467b48Spatrick const DominatorTree::UpdateType Update) const {
5409467b48Spatrick // Won't affect DomTree and PostDomTree.
5509467b48Spatrick return Update.getFrom() == Update.getTo();
5609467b48Spatrick }
5709467b48Spatrick
applyDomTreeUpdates()5809467b48Spatrick void DomTreeUpdater::applyDomTreeUpdates() {
5909467b48Spatrick // No pending DomTreeUpdates.
6009467b48Spatrick if (Strategy != UpdateStrategy::Lazy || !DT)
6109467b48Spatrick return;
6209467b48Spatrick
6309467b48Spatrick // Only apply updates not are applied by DomTree.
6409467b48Spatrick if (hasPendingDomTreeUpdates()) {
6509467b48Spatrick const auto I = PendUpdates.begin() + PendDTUpdateIndex;
6609467b48Spatrick const auto E = PendUpdates.end();
6709467b48Spatrick assert(I < E && "Iterator range invalid; there should be DomTree updates.");
6809467b48Spatrick DT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
6909467b48Spatrick PendDTUpdateIndex = PendUpdates.size();
7009467b48Spatrick }
7109467b48Spatrick }
7209467b48Spatrick
flush()7309467b48Spatrick void DomTreeUpdater::flush() {
7409467b48Spatrick applyDomTreeUpdates();
7509467b48Spatrick applyPostDomTreeUpdates();
7609467b48Spatrick dropOutOfDateUpdates();
7709467b48Spatrick }
7809467b48Spatrick
applyPostDomTreeUpdates()7909467b48Spatrick void DomTreeUpdater::applyPostDomTreeUpdates() {
8009467b48Spatrick // No pending PostDomTreeUpdates.
8109467b48Spatrick if (Strategy != UpdateStrategy::Lazy || !PDT)
8209467b48Spatrick return;
8309467b48Spatrick
8409467b48Spatrick // Only apply updates not are applied by PostDomTree.
8509467b48Spatrick if (hasPendingPostDomTreeUpdates()) {
8609467b48Spatrick const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
8709467b48Spatrick const auto E = PendUpdates.end();
8809467b48Spatrick assert(I < E &&
8909467b48Spatrick "Iterator range invalid; there should be PostDomTree updates.");
9009467b48Spatrick PDT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
9109467b48Spatrick PendPDTUpdateIndex = PendUpdates.size();
9209467b48Spatrick }
9309467b48Spatrick }
9409467b48Spatrick
tryFlushDeletedBB()9509467b48Spatrick void DomTreeUpdater::tryFlushDeletedBB() {
9609467b48Spatrick if (!hasPendingUpdates())
9709467b48Spatrick forceFlushDeletedBB();
9809467b48Spatrick }
9909467b48Spatrick
forceFlushDeletedBB()10009467b48Spatrick bool DomTreeUpdater::forceFlushDeletedBB() {
10109467b48Spatrick if (DeletedBBs.empty())
10209467b48Spatrick return false;
10309467b48Spatrick
10409467b48Spatrick for (auto *BB : DeletedBBs) {
10509467b48Spatrick // After calling deleteBB or callbackDeleteBB under Lazy UpdateStrategy,
10609467b48Spatrick // validateDeleteBB() removes all instructions of DelBB and adds an
10709467b48Spatrick // UnreachableInst as its terminator. So we check whether the BasicBlock to
10809467b48Spatrick // delete only has an UnreachableInst inside.
109*d415bd75Srobert assert(BB->size() == 1 && isa<UnreachableInst>(BB->getTerminator()) &&
11009467b48Spatrick "DelBB has been modified while awaiting deletion.");
11109467b48Spatrick BB->removeFromParent();
11209467b48Spatrick eraseDelBBNode(BB);
11309467b48Spatrick delete BB;
11409467b48Spatrick }
11509467b48Spatrick DeletedBBs.clear();
11609467b48Spatrick Callbacks.clear();
11709467b48Spatrick return true;
11809467b48Spatrick }
11909467b48Spatrick
recalculate(Function & F)12009467b48Spatrick void DomTreeUpdater::recalculate(Function &F) {
12109467b48Spatrick
12209467b48Spatrick if (Strategy == UpdateStrategy::Eager) {
12309467b48Spatrick if (DT)
12409467b48Spatrick DT->recalculate(F);
12509467b48Spatrick if (PDT)
12609467b48Spatrick PDT->recalculate(F);
12709467b48Spatrick return;
12809467b48Spatrick }
12909467b48Spatrick
13009467b48Spatrick // There is little performance gain if we pend the recalculation under
13109467b48Spatrick // Lazy UpdateStrategy so we recalculate available trees immediately.
13209467b48Spatrick
13309467b48Spatrick // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
13409467b48Spatrick IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
13509467b48Spatrick
13609467b48Spatrick // Because all trees are going to be up-to-date after recalculation,
13709467b48Spatrick // flush awaiting deleted BasicBlocks.
13809467b48Spatrick forceFlushDeletedBB();
13909467b48Spatrick if (DT)
14009467b48Spatrick DT->recalculate(F);
14109467b48Spatrick if (PDT)
14209467b48Spatrick PDT->recalculate(F);
14309467b48Spatrick
14409467b48Spatrick // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
14509467b48Spatrick IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
14609467b48Spatrick PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
14709467b48Spatrick dropOutOfDateUpdates();
14809467b48Spatrick }
14909467b48Spatrick
hasPendingUpdates() const15009467b48Spatrick bool DomTreeUpdater::hasPendingUpdates() const {
15109467b48Spatrick return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
15209467b48Spatrick }
15309467b48Spatrick
hasPendingDomTreeUpdates() const15409467b48Spatrick bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
15509467b48Spatrick if (!DT)
15609467b48Spatrick return false;
15709467b48Spatrick return PendUpdates.size() != PendDTUpdateIndex;
15809467b48Spatrick }
15909467b48Spatrick
hasPendingPostDomTreeUpdates() const16009467b48Spatrick bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
16109467b48Spatrick if (!PDT)
16209467b48Spatrick return false;
16309467b48Spatrick return PendUpdates.size() != PendPDTUpdateIndex;
16409467b48Spatrick }
16509467b48Spatrick
isBBPendingDeletion(llvm::BasicBlock * DelBB) const16609467b48Spatrick bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
16709467b48Spatrick if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
16809467b48Spatrick return false;
16973471bf0Spatrick return DeletedBBs.contains(DelBB);
17009467b48Spatrick }
17109467b48Spatrick
17209467b48Spatrick // The DT and PDT require the nodes related to updates
17309467b48Spatrick // are not deleted when update functions are called.
17409467b48Spatrick // So BasicBlock deletions must be pended when the
17509467b48Spatrick // UpdateStrategy is Lazy. When the UpdateStrategy is
17609467b48Spatrick // Eager, the BasicBlock will be deleted immediately.
deleteBB(BasicBlock * DelBB)17709467b48Spatrick void DomTreeUpdater::deleteBB(BasicBlock *DelBB) {
17809467b48Spatrick validateDeleteBB(DelBB);
17909467b48Spatrick if (Strategy == UpdateStrategy::Lazy) {
18009467b48Spatrick DeletedBBs.insert(DelBB);
18109467b48Spatrick return;
18209467b48Spatrick }
18309467b48Spatrick
18409467b48Spatrick DelBB->removeFromParent();
18509467b48Spatrick eraseDelBBNode(DelBB);
18609467b48Spatrick delete DelBB;
18709467b48Spatrick }
18809467b48Spatrick
callbackDeleteBB(BasicBlock * DelBB,std::function<void (BasicBlock *)> Callback)18909467b48Spatrick void DomTreeUpdater::callbackDeleteBB(
19009467b48Spatrick BasicBlock *DelBB, std::function<void(BasicBlock *)> Callback) {
19109467b48Spatrick validateDeleteBB(DelBB);
19209467b48Spatrick if (Strategy == UpdateStrategy::Lazy) {
19309467b48Spatrick Callbacks.push_back(CallBackOnDeletion(DelBB, Callback));
19409467b48Spatrick DeletedBBs.insert(DelBB);
19509467b48Spatrick return;
19609467b48Spatrick }
19709467b48Spatrick
19809467b48Spatrick DelBB->removeFromParent();
19909467b48Spatrick eraseDelBBNode(DelBB);
20009467b48Spatrick Callback(DelBB);
20109467b48Spatrick delete DelBB;
20209467b48Spatrick }
20309467b48Spatrick
eraseDelBBNode(BasicBlock * DelBB)20409467b48Spatrick void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
20509467b48Spatrick if (DT && !IsRecalculatingDomTree)
20609467b48Spatrick if (DT->getNode(DelBB))
20709467b48Spatrick DT->eraseNode(DelBB);
20809467b48Spatrick
20909467b48Spatrick if (PDT && !IsRecalculatingPostDomTree)
21009467b48Spatrick if (PDT->getNode(DelBB))
21109467b48Spatrick PDT->eraseNode(DelBB);
21209467b48Spatrick }
21309467b48Spatrick
validateDeleteBB(BasicBlock * DelBB)21409467b48Spatrick void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
21509467b48Spatrick assert(DelBB && "Invalid push_back of nullptr DelBB.");
21609467b48Spatrick assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
21709467b48Spatrick // DelBB is unreachable and all its instructions are dead.
21809467b48Spatrick while (!DelBB->empty()) {
21909467b48Spatrick Instruction &I = DelBB->back();
220*d415bd75Srobert // Replace used instructions with an arbitrary value (poison).
22109467b48Spatrick if (!I.use_empty())
222*d415bd75Srobert I.replaceAllUsesWith(PoisonValue::get(I.getType()));
223*d415bd75Srobert DelBB->back().eraseFromParent();
22409467b48Spatrick }
22509467b48Spatrick // Make sure DelBB has a valid terminator instruction. As long as DelBB is a
22609467b48Spatrick // Child of Function F it must contain valid IR.
22709467b48Spatrick new UnreachableInst(DelBB->getContext(), DelBB);
22809467b48Spatrick }
22909467b48Spatrick
applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates)23009467b48Spatrick void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) {
23109467b48Spatrick if (!DT && !PDT)
23209467b48Spatrick return;
23309467b48Spatrick
23409467b48Spatrick if (Strategy == UpdateStrategy::Lazy) {
23573471bf0Spatrick PendUpdates.reserve(PendUpdates.size() + Updates.size());
23609467b48Spatrick for (const auto &U : Updates)
23709467b48Spatrick if (!isSelfDominance(U))
23809467b48Spatrick PendUpdates.push_back(U);
23909467b48Spatrick
24009467b48Spatrick return;
24109467b48Spatrick }
24209467b48Spatrick
24309467b48Spatrick if (DT)
24409467b48Spatrick DT->applyUpdates(Updates);
24509467b48Spatrick if (PDT)
24609467b48Spatrick PDT->applyUpdates(Updates);
24709467b48Spatrick }
24809467b48Spatrick
applyUpdatesPermissive(ArrayRef<DominatorTree::UpdateType> Updates)24909467b48Spatrick void DomTreeUpdater::applyUpdatesPermissive(
25009467b48Spatrick ArrayRef<DominatorTree::UpdateType> Updates) {
25109467b48Spatrick if (!DT && !PDT)
25209467b48Spatrick return;
25309467b48Spatrick
25409467b48Spatrick SmallSet<std::pair<BasicBlock *, BasicBlock *>, 8> Seen;
25509467b48Spatrick SmallVector<DominatorTree::UpdateType, 8> DeduplicatedUpdates;
25609467b48Spatrick for (const auto &U : Updates) {
25709467b48Spatrick auto Edge = std::make_pair(U.getFrom(), U.getTo());
25809467b48Spatrick // Because it is illegal to submit updates that have already been applied
25909467b48Spatrick // and updates to an edge need to be strictly ordered,
26009467b48Spatrick // it is safe to infer the existence of an edge from the first update
26109467b48Spatrick // to this edge.
26209467b48Spatrick // If the first update to an edge is "Delete", it means that the edge
26309467b48Spatrick // existed before. If the first update to an edge is "Insert", it means
26409467b48Spatrick // that the edge didn't exist before.
26509467b48Spatrick //
26609467b48Spatrick // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
26709467b48Spatrick // because
26809467b48Spatrick // 1. it is illegal to submit updates that have already been applied,
26909467b48Spatrick // i.e., user cannot delete an nonexistent edge,
27009467b48Spatrick // 2. updates to an edge need to be strictly ordered,
27109467b48Spatrick // So, initially edge A -> B existed.
27209467b48Spatrick // We can then safely ignore future updates to this edge and directly
27309467b48Spatrick // inspect the current CFG:
27409467b48Spatrick // a. If the edge still exists, because the user cannot insert an existent
27509467b48Spatrick // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
27609467b48Spatrick // resulted in a no-op. DTU won't submit any update in this case.
27709467b48Spatrick // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
27809467b48Spatrick // actually happened but {Insert, A, B} was an invalid update which never
27909467b48Spatrick // happened. DTU will submit {Delete, A, B} in this case.
28009467b48Spatrick if (!isSelfDominance(U) && Seen.count(Edge) == 0) {
28109467b48Spatrick Seen.insert(Edge);
28209467b48Spatrick // If the update doesn't appear in the CFG, it means that
28309467b48Spatrick // either the change isn't made or relevant operations
28409467b48Spatrick // result in a no-op.
28509467b48Spatrick if (isUpdateValid(U)) {
28609467b48Spatrick if (isLazy())
28709467b48Spatrick PendUpdates.push_back(U);
28809467b48Spatrick else
28909467b48Spatrick DeduplicatedUpdates.push_back(U);
29009467b48Spatrick }
29109467b48Spatrick }
29209467b48Spatrick }
29309467b48Spatrick
29409467b48Spatrick if (Strategy == UpdateStrategy::Lazy)
29509467b48Spatrick return;
29609467b48Spatrick
29709467b48Spatrick if (DT)
29809467b48Spatrick DT->applyUpdates(DeduplicatedUpdates);
29909467b48Spatrick if (PDT)
30009467b48Spatrick PDT->applyUpdates(DeduplicatedUpdates);
30109467b48Spatrick }
30209467b48Spatrick
getDomTree()30309467b48Spatrick DominatorTree &DomTreeUpdater::getDomTree() {
30409467b48Spatrick assert(DT && "Invalid acquisition of a null DomTree");
30509467b48Spatrick applyDomTreeUpdates();
30609467b48Spatrick dropOutOfDateUpdates();
30709467b48Spatrick return *DT;
30809467b48Spatrick }
30909467b48Spatrick
getPostDomTree()31009467b48Spatrick PostDominatorTree &DomTreeUpdater::getPostDomTree() {
31109467b48Spatrick assert(PDT && "Invalid acquisition of a null PostDomTree");
31209467b48Spatrick applyPostDomTreeUpdates();
31309467b48Spatrick dropOutOfDateUpdates();
31409467b48Spatrick return *PDT;
31509467b48Spatrick }
31609467b48Spatrick
dropOutOfDateUpdates()31709467b48Spatrick void DomTreeUpdater::dropOutOfDateUpdates() {
31809467b48Spatrick if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
31909467b48Spatrick return;
32009467b48Spatrick
32109467b48Spatrick tryFlushDeletedBB();
32209467b48Spatrick
32309467b48Spatrick // Drop all updates applied by both trees.
32409467b48Spatrick if (!DT)
32509467b48Spatrick PendDTUpdateIndex = PendUpdates.size();
32609467b48Spatrick if (!PDT)
32709467b48Spatrick PendPDTUpdateIndex = PendUpdates.size();
32809467b48Spatrick
32909467b48Spatrick const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
33009467b48Spatrick const auto B = PendUpdates.begin();
33109467b48Spatrick const auto E = PendUpdates.begin() + dropIndex;
33209467b48Spatrick assert(B <= E && "Iterator out of range.");
33309467b48Spatrick PendUpdates.erase(B, E);
33409467b48Spatrick // Calculate current index.
33509467b48Spatrick PendDTUpdateIndex -= dropIndex;
33609467b48Spatrick PendPDTUpdateIndex -= dropIndex;
33709467b48Spatrick }
33809467b48Spatrick
33909467b48Spatrick #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const34009467b48Spatrick LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
34109467b48Spatrick raw_ostream &OS = llvm::dbgs();
34209467b48Spatrick
34309467b48Spatrick OS << "Available Trees: ";
34409467b48Spatrick if (DT || PDT) {
34509467b48Spatrick if (DT)
34609467b48Spatrick OS << "DomTree ";
34709467b48Spatrick if (PDT)
34809467b48Spatrick OS << "PostDomTree ";
34909467b48Spatrick OS << "\n";
35009467b48Spatrick } else
35109467b48Spatrick OS << "None\n";
35209467b48Spatrick
35309467b48Spatrick OS << "UpdateStrategy: ";
35409467b48Spatrick if (Strategy == UpdateStrategy::Eager) {
35509467b48Spatrick OS << "Eager\n";
35609467b48Spatrick return;
35709467b48Spatrick } else
35809467b48Spatrick OS << "Lazy\n";
35909467b48Spatrick int Index = 0;
36009467b48Spatrick
36109467b48Spatrick auto printUpdates =
36209467b48Spatrick [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
36309467b48Spatrick ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
36409467b48Spatrick if (begin == end)
36509467b48Spatrick OS << " None\n";
36609467b48Spatrick Index = 0;
36709467b48Spatrick for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
36809467b48Spatrick auto U = *It;
36909467b48Spatrick OS << " " << Index << " : ";
37009467b48Spatrick ++Index;
37109467b48Spatrick if (U.getKind() == DominatorTree::Insert)
37209467b48Spatrick OS << "Insert, ";
37309467b48Spatrick else
37409467b48Spatrick OS << "Delete, ";
37509467b48Spatrick BasicBlock *From = U.getFrom();
37609467b48Spatrick if (From) {
37709467b48Spatrick auto S = From->getName();
37809467b48Spatrick if (!From->hasName())
37909467b48Spatrick S = "(no name)";
38009467b48Spatrick OS << S << "(" << From << "), ";
38109467b48Spatrick } else {
38209467b48Spatrick OS << "(badref), ";
38309467b48Spatrick }
38409467b48Spatrick BasicBlock *To = U.getTo();
38509467b48Spatrick if (To) {
38609467b48Spatrick auto S = To->getName();
38709467b48Spatrick if (!To->hasName())
38809467b48Spatrick S = "(no_name)";
38909467b48Spatrick OS << S << "(" << To << ")\n";
39009467b48Spatrick } else {
39109467b48Spatrick OS << "(badref)\n";
39209467b48Spatrick }
39309467b48Spatrick }
39409467b48Spatrick };
39509467b48Spatrick
39609467b48Spatrick if (DT) {
39709467b48Spatrick const auto I = PendUpdates.begin() + PendDTUpdateIndex;
39809467b48Spatrick assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
39909467b48Spatrick "Iterator out of range.");
40009467b48Spatrick OS << "Applied but not cleared DomTreeUpdates:\n";
40109467b48Spatrick printUpdates(PendUpdates.begin(), I);
40209467b48Spatrick OS << "Pending DomTreeUpdates:\n";
40309467b48Spatrick printUpdates(I, PendUpdates.end());
40409467b48Spatrick }
40509467b48Spatrick
40609467b48Spatrick if (PDT) {
40709467b48Spatrick const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
40809467b48Spatrick assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
40909467b48Spatrick "Iterator out of range.");
41009467b48Spatrick OS << "Applied but not cleared PostDomTreeUpdates:\n";
41109467b48Spatrick printUpdates(PendUpdates.begin(), I);
41209467b48Spatrick OS << "Pending PostDomTreeUpdates:\n";
41309467b48Spatrick printUpdates(I, PendUpdates.end());
41409467b48Spatrick }
41509467b48Spatrick
41609467b48Spatrick OS << "Pending DeletedBBs:\n";
41709467b48Spatrick Index = 0;
418097a140dSpatrick for (const auto *BB : DeletedBBs) {
41909467b48Spatrick OS << " " << Index << " : ";
42009467b48Spatrick ++Index;
42109467b48Spatrick if (BB->hasName())
42209467b48Spatrick OS << BB->getName() << "(";
42309467b48Spatrick else
42409467b48Spatrick OS << "(no_name)(";
42509467b48Spatrick OS << BB << ")\n";
42609467b48Spatrick }
42709467b48Spatrick
42809467b48Spatrick OS << "Pending Callbacks:\n";
42909467b48Spatrick Index = 0;
430097a140dSpatrick for (const auto &BB : Callbacks) {
43109467b48Spatrick OS << " " << Index << " : ";
43209467b48Spatrick ++Index;
43309467b48Spatrick if (BB->hasName())
43409467b48Spatrick OS << BB->getName() << "(";
43509467b48Spatrick else
43609467b48Spatrick OS << "(no_name)(";
43709467b48Spatrick OS << BB << ")\n";
43809467b48Spatrick }
43909467b48Spatrick }
44009467b48Spatrick #endif
44109467b48Spatrick } // namespace llvm
442