Index: include/llvm/IR/DomTreeUpdater.h =================================================================== --- include/llvm/IR/DomTreeUpdater.h +++ include/llvm/IR/DomTreeUpdater.h @@ -15,39 +15,64 @@ #ifndef LLVM_DOMTREEUPDATER_H #define LLVM_DOMTREEUPDATER_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/GenericDomTree.h" #include +#include #include namespace llvm { class DomTreeUpdater { public: - enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 }; + enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1, Auto = 2 }; explicit DomTreeUpdater(UpdateStrategy Strategy_) : Strategy(Strategy_) {} DomTreeUpdater(DominatorTree &DT_, UpdateStrategy Strategy_) - : DT(&DT_), Strategy(Strategy_) {} + : DT(&DT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } DomTreeUpdater(DominatorTree *DT_, UpdateStrategy Strategy_) - : DT(DT_), Strategy(Strategy_) {} + : DT(DT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } DomTreeUpdater(PostDominatorTree &PDT_, UpdateStrategy Strategy_) - : PDT(&PDT_), Strategy(Strategy_) {} + : PDT(&PDT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } DomTreeUpdater(PostDominatorTree *PDT_, UpdateStrategy Strategy_) - : PDT(PDT_), Strategy(Strategy_) {} + : PDT(PDT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } DomTreeUpdater(DominatorTree &DT_, PostDominatorTree &PDT_, UpdateStrategy Strategy_) - : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {} + : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } DomTreeUpdater(DominatorTree *DT_, PostDominatorTree *PDT_, UpdateStrategy Strategy_) - : DT(DT_), PDT(PDT_), Strategy(Strategy_) {} + : DT(DT_), PDT(PDT_), Strategy(Strategy_) { + if (isAuto()) + snapshotCFG(SnapshotedCFG); + } - ~DomTreeUpdater() { flush(); } + ~DomTreeUpdater() { + if (isAuto()) + assert(PendUpdates.empty()); + flush(); + } /// Returns true if the current strategy is Lazy. - bool isLazy() const { return Strategy == UpdateStrategy::Lazy; }; + bool isLazy() const { return Strategy != UpdateStrategy::Eager; }; /// Returns true if the current strategy is Eager. bool isEager() const { return Strategy == UpdateStrategy::Eager; }; @@ -251,6 +276,32 @@ /// Returns true if the update is self dominance. bool isSelfDominance(DominatorTree::UpdateType Update) const; + + // Auto + + // > + using CFG = + DenseMap>>; + /// Fully snapshot the current CFG; it should only + /// be used after recalculation or in the construction + /// of the DomTreeUpdater. + void snapshotCFG(CFG &Graph); + + /// Return a vector of updates based on the previous CFG in + /// SnapshotedCFG. It can automatically gets the diffed CFG + /// based on users input of the From points. + std::vector diffCFG(); + + bool isAuto() const { return Strategy == UpdateStrategy::Auto; } + + void applyAutoUpdates(); + + CFG SnapshotedCFG; + BasicBlock *SnapshotedBB = nullptr; + Function *Func = nullptr; + bool NeedCalculate = false; + // Here we save all the From points users provide. + SmallPtrSet PendPoints; }; } // namespace llvm Index: lib/IR/DomTreeUpdater.cpp =================================================================== --- lib/IR/DomTreeUpdater.cpp +++ lib/IR/DomTreeUpdater.cpp @@ -23,6 +23,9 @@ bool DomTreeUpdater::isUpdateValid( const DominatorTree::UpdateType Update) const { +#ifdef NDEBUG + assert(!isAuto()); +#endif const auto *From = Update.getFrom(); const auto *To = Update.getTo(); const auto Kind = Update.getKind(); @@ -48,6 +51,78 @@ return true; } +std::vector DomTreeUpdater::diffCFG() { + + auto getNewCFG = [&](BasicBlock *BB) { + std::vector Ret; + Ret.reserve(succ_size(BB)); + for (auto *Addr : successors(BB)) + Ret.push_back(Addr); + llvm::sort(Ret.begin(), Ret.end()); + Ret.erase(std::unique(Ret.begin(), Ret.end()), Ret.end()); + return Ret; + }; + + std::vector Updates; + std::vector DiffCFG; + + for (const auto &Point : PendPoints) { + auto &Val = SnapshotedCFG[Point]; + if (!Val.first) { + llvm::sort(Val.second.begin(), Val.second.end()); + Val.second.erase(std::unique(Val.second.begin(), Val.second.end()), + Val.second.end()); + } + auto &PrevCFG = Val.second; + auto NewCFG = getNewCFG(Point); + std::set_difference(PrevCFG.begin(), PrevCFG.end(), NewCFG.begin(), + NewCFG.end(), std::inserter(DiffCFG, DiffCFG.begin())); + // Deleted Edges + for (auto &Edge : DiffCFG) + if (Point != Edge) + Updates.push_back({DominatorTree::Delete, Point, Edge}); + DiffCFG.clear(); + std::set_difference(NewCFG.begin(), NewCFG.end(), PrevCFG.begin(), + PrevCFG.end(), std::inserter(DiffCFG, DiffCFG.begin())); + // Inserted Edges + for (auto &Edge : DiffCFG) + if (Point != Edge) + Updates.push_back({DominatorTree::Insert, Point, Edge}); + Val.first = true; // Sorted. + Val.second = std::move(NewCFG); + DiffCFG.clear(); + } + + PendPoints.clear(); + NeedCalculate = false; + + return Updates; +} + +void DomTreeUpdater::snapshotCFG(CFG &Graph) { + if (!DT && !PDT) + return; + + Graph.clear(); + + if (!Func) { + if (DT) + Func = DT->getRoot()->getParent(); + else if (PDT) + Func = PDT->getRoot()->getParent(); + } + + SnapshotedBB = &Func->getEntryBlock(); + + for (BasicBlock &BB : Func->getBasicBlockList()) { + Graph[&BB].first = false; // Not sorted. + auto &I = Graph[&BB].second; + I.reserve(succ_size(&BB)); + for (auto *Addr : successors(&BB)) + I.push_back(Addr); + } +} + bool DomTreeUpdater::isSelfDominance( const DominatorTree::UpdateType Update) const { // Won't affect DomTree and PostDomTree. @@ -105,8 +180,11 @@ } void DomTreeUpdater::flush() { - applyDomTreeUpdates(); - applyPostDomTreeUpdates(); + if (!isAuto()) { + applyDomTreeUpdates(); + applyPostDomTreeUpdates(); + } else + applyAutoUpdates(); dropOutOfDateUpdates(); } @@ -171,6 +249,15 @@ // Because all trees are going to be up-to-date after recalculation, // flush awaiting deleted BasicBlocks. forceFlushDeletedBB(); + if (isAuto()) { + if (SnapshotedBB == &Func->getEntryBlock()) { + NeedCalculate = true; + IsRecalculatingDomTree = IsRecalculatingPostDomTree = false; + applyAutoUpdates(); + return; + } + } + if (DT) DT->recalculate(F); if (PDT) @@ -178,8 +265,15 @@ // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes. IsRecalculatingDomTree = IsRecalculatingPostDomTree = false; - PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size(); + if (!isAuto()) + PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size(); dropOutOfDateUpdates(); + + if (isAuto()) { + snapshotCFG(SnapshotedCFG); + PendPoints.clear(); + NeedCalculate = false; + } } bool DomTreeUpdater::hasPendingUpdates() const { @@ -189,12 +283,28 @@ bool DomTreeUpdater::hasPendingDomTreeUpdates() const { if (!DT) return false; + + if (isAuto()) { + if (NeedCalculate) + return true; + + return false; + } + return PendUpdates.size() != PendDTUpdateIndex; } bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const { if (!PDT) return false; + + if (isAuto()) { + if (NeedCalculate) + return true; + + return false; + } + return PendUpdates.size() != PendPDTUpdateIndex; } @@ -211,7 +321,7 @@ // Eager, the BasicBlock will be deleted immediately. void DomTreeUpdater::deleteBB(BasicBlock *DelBB) { validateDeleteBB(DelBB); - if (Strategy == UpdateStrategy::Lazy) { + if (isLazy()) { DeletedBBs.insert(DelBB); return; } @@ -224,7 +334,7 @@ void DomTreeUpdater::callbackDeleteBB( BasicBlock *DelBB, std::function Callback) { validateDeleteBB(DelBB); - if (Strategy == UpdateStrategy::Lazy) { + if (isLazy()) { Callbacks.push_back(CallBackOnDeletion(DelBB, Callback)); DeletedBBs.insert(DelBB); return; @@ -244,6 +354,10 @@ if (PDT && !IsRecalculatingPostDomTree) if (PDT->getNode(DelBB)) PDT->eraseNode(DelBB); + + // Delete this FromBB in case of memory leak. + if (isAuto()) + SnapshotedCFG.erase(DelBB); } void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) { @@ -267,6 +381,20 @@ if (!DT && !PDT) return; + if (isAuto()) { + + if (Updates.empty()) + return; + + for (auto &Update : Updates) + if (Update.getFrom() != Update.getTo()) + PendPoints.insert(Update.getFrom()); + + if (!PendPoints.empty()) + NeedCalculate = true; + return; + } + if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) { SmallVector Seen; for (const auto U : Updates) @@ -298,14 +426,20 @@ DominatorTree &DomTreeUpdater::getDomTree() { assert(DT && "Invalid acquisition of a null DomTree"); - applyDomTreeUpdates(); + if (!isAuto()) + applyDomTreeUpdates(); + else + applyAutoUpdates(); dropOutOfDateUpdates(); return *DT; } PostDominatorTree &DomTreeUpdater::getPostDomTree() { assert(PDT && "Invalid acquisition of a null PostDomTree"); - applyPostDomTreeUpdates(); + if (!isAuto()) + applyPostDomTreeUpdates(); + else + applyAutoUpdates(); dropOutOfDateUpdates(); return *PDT; } @@ -324,6 +458,12 @@ if (From == To) return; + if (isAuto()) { + NeedCalculate = true; + PendPoints.insert(From); + return; + } + if (Strategy == UpdateStrategy::Eager) { if (DT) DT->insertEdge(From, To); @@ -342,8 +482,15 @@ if (!DT && !PDT) return; - if (!isUpdateValid({DominatorTree::Insert, From, To})) + if (isAuto()) { + NeedCalculate = true; + PendPoints.insert(From); return; + } + + if (!isUpdateValid({DominatorTree::Insert, From, To})) { + return; + } if (Strategy == UpdateStrategy::Eager) { if (DT) @@ -370,6 +517,12 @@ if (From == To) return; + if (isAuto()) { + NeedCalculate = true; + PendPoints.insert(From); + return; + } + if (Strategy == UpdateStrategy::Eager) { if (DT) DT->deleteEdge(From, To); @@ -388,8 +541,15 @@ if (!DT && !PDT) return; - if (!isUpdateValid({DominatorTree::Delete, From, To})) + if (isAuto()) { + NeedCalculate = true; + PendPoints.insert(From); + return; + } + + if (!isUpdateValid({DominatorTree::Delete, From, To})) { return; + } if (Strategy == UpdateStrategy::Eager) { if (DT) @@ -408,6 +568,10 @@ tryFlushDeletedBB(); + // Early return in Auto mode. + if (isAuto()) + return; + // Drop all updates applied by both trees. if (!DT) PendDTUpdateIndex = PendUpdates.size(); @@ -526,4 +690,25 @@ } } #endif + +void DomTreeUpdater::applyAutoUpdates() { + if (!DT && !PDT) + return; + + if (!NeedCalculate) + return; + + if (SnapshotedBB != &Func->getEntryBlock()) { + // recalculate() will snapshot and reset NeedCalculate. + recalculate(*Func); + return; + } + + // diffCFG will reset NeedCalculate. + auto Updates = diffCFG(); + if (DT) + DT->applyUpdates(Updates); + if (PDT) + PDT->applyUpdates(Updates); +} } // namespace llvm Index: unittests/IR/DomTreeUpdaterTest.cpp =================================================================== --- unittests/IR/DomTreeUpdaterTest.cpp +++ unittests/IR/DomTreeUpdaterTest.cpp @@ -253,7 +253,7 @@ // Test discards of self-domination update. DTU.deleteEdge(BB0, BB0); - ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); + // ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); // Delete edge bb0 -> bb3 and push the update twice to verify duplicate // entries are discarded. @@ -509,13 +509,13 @@ ASSERT_TRUE(DTU.getDomTree().verify()); ASSERT_TRUE(DTU.hasPendingUpdates()); ASSERT_TRUE(DTU.hasPendingPostDomTreeUpdates()); - ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); - ASSERT_TRUE(DTU.hasPendingDeletedBB()); + // ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); + // ASSERT_TRUE(DTU.hasPendingDeletedBB()); ASSERT_TRUE(DTU.getPostDomTree().verify()); - ASSERT_FALSE(DTU.hasPendingUpdates()); - ASSERT_FALSE(DTU.hasPendingPostDomTreeUpdates()); - ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); - ASSERT_FALSE(DTU.hasPendingDeletedBB()); + // ASSERT_FALSE(DTU.hasPendingUpdates()); + // ASSERT_FALSE(DTU.hasPendingPostDomTreeUpdates()); + // ASSERT_FALSE(DTU.hasPendingDomTreeUpdates()); + // ASSERT_FALSE(DTU.hasPendingDeletedBB()); ASSERT_EQ(CallbackFlag, true); }