From e6393eeb145f8310dfc1e5fae0e712235273dc30 Mon Sep 17 00:00:00 2001 From: PaperChalice Date: Fri, 28 Jun 2024 17:25:12 +0800 Subject: [PATCH 1/2] [DomTreeUpdater] Split implementations Move implementations of `GenericDomTreeUpdater` to GenericDomTreeUpdaterImpl.h --- llvm/include/llvm/Analysis/DomTreeUpdater.h | 25 +- .../llvm/Analysis/GenericDomTreeUpdater.h | 377 ++------------ .../llvm/Analysis/GenericDomTreeUpdaterImpl.h | 477 ++++++++++++++++++ .../llvm/CodeGen/MachineDomTreeUpdater.h | 14 +- llvm/lib/Analysis/DomTreeUpdater.cpp | 24 + llvm/lib/CodeGen/MachineDomTreeUpdater.cpp | 8 +- 6 files changed, 555 insertions(+), 370 deletions(-) create mode 100644 llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h diff --git a/llvm/include/llvm/Analysis/DomTreeUpdater.h b/llvm/include/llvm/Analysis/DomTreeUpdater.h index 2b838a311440e..9ffd4948c1750 100644 --- a/llvm/include/llvm/Analysis/DomTreeUpdater.h +++ b/llvm/include/llvm/Analysis/DomTreeUpdater.h @@ -16,7 +16,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/GenericDomTreeUpdater.h" -#include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Compiler.h" @@ -26,6 +25,8 @@ namespace llvm { +class PostDominatorTree; + class DomTreeUpdater : public GenericDomTreeUpdater { @@ -110,27 +111,15 @@ class DomTreeUpdater bool forceFlushDeletedBB(); /// Debug method to help view the internal state of this class. - LLVM_DUMP_METHOD void dump() const { - Base::dump(); -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - raw_ostream &OS = dbgs(); - OS << "Pending Callbacks:\n"; - int Index = 0; - for (const auto &BB : Callbacks) { - OS << " " << Index << " : "; - ++Index; - if (BB->hasName()) - OS << BB->getName() << "("; - else - OS << "(no_name)("; - OS << BB << ")\n"; - } -#endif - } + LLVM_DUMP_METHOD void dump() const; }; extern template class GenericDomTreeUpdater; + +extern template void +GenericDomTreeUpdater::recalculate(Function &F); } // namespace llvm #endif // LLVM_ANALYSIS_DOMTREEUPDATER_H diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h index 7092c67083a67..1a86398e4fc68 100644 --- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h +++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h @@ -16,91 +16,67 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Compiler.h" namespace llvm { template class GenericDomTreeUpdater { - DerivedT &derived() { return *static_cast(this); } - const DerivedT &derived() const { - return *static_cast(this); - } + DerivedT &derived(); + const DerivedT &derived() const; public: enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 }; using BasicBlockT = typename DomTreeT::NodeType; - explicit GenericDomTreeUpdater(UpdateStrategy Strategy_) - : Strategy(Strategy_) {} - GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_) - : DT(&DT_), Strategy(Strategy_) {} - GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_) - : DT(DT_), Strategy(Strategy_) {} - GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_) - : PDT(&PDT_), Strategy(Strategy_) {} - GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_) - : PDT(PDT_), Strategy(Strategy_) {} + explicit GenericDomTreeUpdater(UpdateStrategy Strategy_); + GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_); + GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_); + GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_); + GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_); GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_, - UpdateStrategy Strategy_) - : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {} + UpdateStrategy Strategy_); GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_, - UpdateStrategy Strategy_) - : DT(DT_), PDT(PDT_), Strategy(Strategy_) {} + UpdateStrategy Strategy_); - ~GenericDomTreeUpdater() { flush(); } + ~GenericDomTreeUpdater(); /// Returns true if the current strategy is Lazy. - bool isLazy() const { return Strategy == UpdateStrategy::Lazy; }; + bool isLazy() const; /// Returns true if the current strategy is Eager. - bool isEager() const { return Strategy == UpdateStrategy::Eager; }; + bool isEager() const; /// Returns true if it holds a DomTreeT. - bool hasDomTree() const { return DT != nullptr; } + bool hasDomTree() const; /// Returns true if it holds a PostDomTreeT. - bool hasPostDomTree() const { return PDT != nullptr; } + bool hasPostDomTree() const; /// Returns true if there is BasicBlockT awaiting deletion. /// The deletion will only happen until a flush event and /// all available trees are up-to-date. /// Returns false under Eager UpdateStrategy. - bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); } + bool hasPendingDeletedBB() const; /// Returns true if DelBB is awaiting deletion. /// Returns false under Eager UpdateStrategy. - bool isBBPendingDeletion(BasicBlockT *DelBB) const { - if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty()) - return false; - return DeletedBBs.contains(DelBB); - } + bool isBBPendingDeletion(BasicBlockT *DelBB) const; /// Returns true if either of DT or PDT is valid and the tree has at /// least one update pending. If DT or PDT is nullptr it is treated /// as having no pending updates. This function does not check /// whether there is MachineBasicBlock awaiting deletion. /// Returns false under Eager UpdateStrategy. - bool hasPendingUpdates() const { - return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates(); - } + bool hasPendingUpdates() const; /// Returns true if there are DomTreeT updates queued. /// Returns false under Eager UpdateStrategy or DT is nullptr. - bool hasPendingDomTreeUpdates() const { - if (!DT) - return false; - return PendUpdates.size() != PendDTUpdateIndex; - } + bool hasPendingDomTreeUpdates() const; /// Returns true if there are PostDomTreeT updates queued. /// Returns false under Eager UpdateStrategy or PDT is nullptr. - bool hasPendingPostDomTreeUpdates() const { - if (!PDT) - return false; - return PendUpdates.size() != PendPDTUpdateIndex; - } + bool hasPendingPostDomTreeUpdates() const; ///@{ /// \name Mutation APIs @@ -126,34 +102,7 @@ class GenericDomTreeUpdater { /// Notify DTU that the entry block was replaced. /// Recalculate all available trees and flush all BasicBlocks /// awaiting deletion immediately. - template void recalculate(FuncT &F) { - if (Strategy == UpdateStrategy::Eager) { - if (DT) - DT->recalculate(F); - if (PDT) - PDT->recalculate(F); - return; - } - - // There is little performance gain if we pend the recalculation under - // Lazy UpdateStrategy so we recalculate available trees immediately. - - // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes. - IsRecalculatingDomTree = IsRecalculatingPostDomTree = true; - - // Because all trees are going to be up-to-date after recalculation, - // flush awaiting deleted BasicBlocks. - derived().forceFlushDeletedBB(); - if (DT) - DT->recalculate(F); - if (PDT) - PDT->recalculate(F); - - // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes. - IsRecalculatingDomTree = IsRecalculatingPostDomTree = false; - PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size(); - dropOutOfDateUpdates(); - } + template void recalculate(FuncT &F); /// Submit updates to all available trees. /// The Eager Strategy flushes updates immediately while the Lazy Strategy @@ -170,24 +119,7 @@ class GenericDomTreeUpdater { /// 2. It is illegal to submit any update that has already been submitted, /// i.e., you are supposed not to insert an existent edge or delete a /// nonexistent edge. - void applyUpdates(ArrayRef Updates) { - if (!DT && !PDT) - return; - - if (Strategy == UpdateStrategy::Lazy) { - PendUpdates.reserve(PendUpdates.size() + Updates.size()); - for (const auto &U : Updates) - if (!isSelfDominance(U)) - PendUpdates.push_back(U); - - return; - } - - if (DT) - DT->applyUpdates(Updates); - if (PDT) - PDT->applyUpdates(Updates); - } + void applyUpdates(ArrayRef Updates); /// Submit updates to all available trees. It will also /// 1. discard duplicated updates, @@ -210,58 +142,7 @@ class GenericDomTreeUpdater { /// 3. It is only legal to submit updates to an edge in the order CFG changes /// are made. The order you submit updates on different edges is not /// restricted. - void applyUpdatesPermissive(ArrayRef Updates) { - if (!DT && !PDT) - return; - - SmallSet, 8> Seen; - SmallVector DeduplicatedUpdates; - for (const auto &U : Updates) { - auto Edge = std::make_pair(U.getFrom(), U.getTo()); - // Because it is illegal to submit updates that have already been applied - // and updates to an edge need to be strictly ordered, - // it is safe to infer the existence of an edge from the first update - // to this edge. - // If the first update to an edge is "Delete", it means that the edge - // existed before. If the first update to an edge is "Insert", it means - // that the edge didn't exist before. - // - // For example, if the user submits {{Delete, A, B}, {Insert, A, B}}, - // because - // 1. it is illegal to submit updates that have already been applied, - // i.e., user cannot delete an nonexistent edge, - // 2. updates to an edge need to be strictly ordered, - // So, initially edge A -> B existed. - // We can then safely ignore future updates to this edge and directly - // inspect the current CFG: - // a. If the edge still exists, because the user cannot insert an existent - // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and - // resulted in a no-op. DTU won't submit any update in this case. - // b. If the edge doesn't exist, we can then infer that {Delete, A, B} - // actually happened but {Insert, A, B} was an invalid update which never - // happened. DTU will submit {Delete, A, B} in this case. - if (!isSelfDominance(U) && Seen.count(Edge) == 0) { - Seen.insert(Edge); - // If the update doesn't appear in the CFG, it means that - // either the change isn't made or relevant operations - // result in a no-op. - if (isUpdateValid(U)) { - if (isLazy()) - PendUpdates.push_back(U); - else - DeduplicatedUpdates.push_back(U); - } - } - } - - if (Strategy == UpdateStrategy::Lazy) - return; - - if (DT) - DT->applyUpdates(DeduplicatedUpdates); - if (PDT) - PDT->applyUpdates(DeduplicatedUpdates); - } + void applyUpdatesPermissive(ArrayRef Updates); ///@} @@ -275,127 +156,22 @@ class GenericDomTreeUpdater { /// Flush DomTree updates and return DomTree. /// It flushes Deleted BBs if both trees are up-to-date. /// It must only be called when it has a DomTree. - DomTreeT &getDomTree() { - assert(DT && "Invalid acquisition of a null DomTree"); - applyDomTreeUpdates(); - dropOutOfDateUpdates(); - return *DT; - } + DomTreeT &getDomTree(); /// Flush PostDomTree updates and return PostDomTree. /// It flushes Deleted BBs if both trees are up-to-date. /// It must only be called when it has a PostDomTree. - PostDomTreeT &getPostDomTree() { - assert(PDT && "Invalid acquisition of a null PostDomTree"); - applyPostDomTreeUpdates(); - dropOutOfDateUpdates(); - return *PDT; - } + PostDomTreeT &getPostDomTree(); /// Apply all pending updates to available trees and flush all BasicBlocks /// awaiting deletion. - void flush() { - applyDomTreeUpdates(); - applyPostDomTreeUpdates(); - dropOutOfDateUpdates(); - } + void flush(); ///@} /// Debug method to help view the internal state of this class. - LLVM_DUMP_METHOD void dump() const { -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - raw_ostream &OS = llvm::dbgs(); - - OS << "Available Trees: "; - if (DT || PDT) { - if (DT) - OS << "DomTree "; - if (PDT) - OS << "PostDomTree "; - OS << "\n"; - } else - OS << "None\n"; - - OS << "UpdateStrategy: "; - if (Strategy == UpdateStrategy::Eager) { - OS << "Eager\n"; - return; - } else - OS << "Lazy\n"; - int Index = 0; - - auto printUpdates = - [&](typename ArrayRef::const_iterator - begin, - typename ArrayRef::const_iterator - end) { - if (begin == end) - OS << " None\n"; - Index = 0; - for (auto It = begin, ItEnd = end; It != ItEnd; ++It) { - auto U = *It; - OS << " " << Index << " : "; - ++Index; - if (U.getKind() == DomTreeT::Insert) - OS << "Insert, "; - else - OS << "Delete, "; - BasicBlockT *From = U.getFrom(); - if (From) { - auto S = From->getName(); - if (!From->hasName()) - S = "(no name)"; - OS << S << "(" << From << "), "; - } else { - OS << "(badref), "; - } - BasicBlockT *To = U.getTo(); - if (To) { - auto S = To->getName(); - if (!To->hasName()) - S = "(no_name)"; - OS << S << "(" << To << ")\n"; - } else { - OS << "(badref)\n"; - } - } - }; - - if (DT) { - const auto I = PendUpdates.begin() + PendDTUpdateIndex; - assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && - "Iterator out of range."); - OS << "Applied but not cleared DomTreeUpdates:\n"; - printUpdates(PendUpdates.begin(), I); - OS << "Pending DomTreeUpdates:\n"; - printUpdates(I, PendUpdates.end()); - } - - if (PDT) { - const auto I = PendUpdates.begin() + PendPDTUpdateIndex; - assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && - "Iterator out of range."); - OS << "Applied but not cleared PostDomTreeUpdates:\n"; - printUpdates(PendUpdates.begin(), I); - OS << "Pending PostDomTreeUpdates:\n"; - printUpdates(I, PendUpdates.end()); - } - - OS << "Pending DeletedBBs:\n"; - Index = 0; - for (const auto *BB : DeletedBBs) { - OS << " " << Index << " : "; - ++Index; - if (BB->hasName()) - OS << BB->getName() << "("; - else - OS << "(no_name)("; - OS << BB << ")\n"; - } -#endif - } + LLVM_DUMP_METHOD void dump() const; protected: SmallVector PendUpdates; @@ -409,115 +185,30 @@ class GenericDomTreeUpdater { bool IsRecalculatingPostDomTree = false; /// Returns true if the update is self dominance. - bool isSelfDominance(typename DomTreeT::UpdateType Update) const { - // Won't affect DomTree and PostDomTree. - return Update.getFrom() == Update.getTo(); - } + bool isSelfDominance(typename DomTreeT::UpdateType Update) const; /// Helper function to apply all pending DomTree updates. - void applyDomTreeUpdates() { - // No pending DomTreeUpdates. - if (Strategy != UpdateStrategy::Lazy || !DT) - return; - - // Only apply updates not are applied by DomTree. - if (hasPendingDomTreeUpdates()) { - const auto I = PendUpdates.begin() + PendDTUpdateIndex; - const auto E = PendUpdates.end(); - assert(I < E && - "Iterator range invalid; there should be DomTree updates."); - DT->applyUpdates(ArrayRef(I, E)); - PendDTUpdateIndex = PendUpdates.size(); - } - } + void applyDomTreeUpdates(); /// Helper function to apply all pending PostDomTree updates. - void applyPostDomTreeUpdates() { - // No pending PostDomTreeUpdates. - if (Strategy != UpdateStrategy::Lazy || !PDT) - return; - - // Only apply updates not are applied by PostDomTree. - if (hasPendingPostDomTreeUpdates()) { - const auto I = PendUpdates.begin() + PendPDTUpdateIndex; - const auto E = PendUpdates.end(); - assert(I < E && - "Iterator range invalid; there should be PostDomTree updates."); - PDT->applyUpdates(ArrayRef(I, E)); - PendPDTUpdateIndex = PendUpdates.size(); - } - } + void applyPostDomTreeUpdates(); /// Returns true if the update appears in the LLVM IR. /// It is used to check whether an update is valid in /// insertEdge/deleteEdge or is unnecessary in the batch update. - bool isUpdateValid(typename DomTreeT::UpdateType Update) const { - const auto *From = Update.getFrom(); - const auto *To = Update.getTo(); - const auto Kind = Update.getKind(); - - // Discard updates by inspecting the current state of successors of From. - // Since isUpdateValid() must be called *after* the Terminator of From is - // altered we can determine if the update is unnecessary for batch updates - // or invalid for a single update. - const bool HasEdge = llvm::is_contained(successors(From), To); - - // If the IR does not match the update, - // 1. In batch updates, this update is unnecessary. - // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid. - // Edge does not exist in IR. - if (Kind == DomTreeT::Insert && !HasEdge) - return false; - - // Edge exists in IR. - if (Kind == DomTreeT::Delete && HasEdge) - return false; - - return true; - } + bool isUpdateValid(typename DomTreeT::UpdateType Update) const; /// Erase Basic Block node that has been unlinked from Function /// in the DomTree and PostDomTree. - void eraseDelBBNode(BasicBlockT *DelBB) { - if (DT && !IsRecalculatingDomTree) - if (DT->getNode(DelBB)) - DT->eraseNode(DelBB); - - if (PDT && !IsRecalculatingPostDomTree) - if (PDT->getNode(DelBB)) - PDT->eraseNode(DelBB); - } + void eraseDelBBNode(BasicBlockT *DelBB); /// Helper function to flush deleted BasicBlocks if all available /// trees are up-to-date. - void tryFlushDeletedBB() { - if (!hasPendingUpdates()) - derived().forceFlushDeletedBB(); - } + void tryFlushDeletedBB(); /// Drop all updates applied by all available trees and delete BasicBlocks if /// all available trees are up-to-date. - void dropOutOfDateUpdates() { - if (Strategy == UpdateStrategy::Eager) - return; - - tryFlushDeletedBB(); - - // Drop all updates applied by both trees. - if (!DT) - PendDTUpdateIndex = PendUpdates.size(); - if (!PDT) - PendPDTUpdateIndex = PendUpdates.size(); - - const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex); - const auto B = PendUpdates.begin(); - const auto E = PendUpdates.begin() + dropIndex; - assert(B <= E && "Iterator out of range."); - PendUpdates.erase(B, E); - // Calculate current index. - PendDTUpdateIndex -= dropIndex; - PendPDTUpdateIndex -= dropIndex; - } + void dropOutOfDateUpdates(); }; } // namespace llvm diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h new file mode 100644 index 0000000000000..ec6c345b994ac --- /dev/null +++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h @@ -0,0 +1,477 @@ +//===- GenericDomTreeUpdaterImpl.h ------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the GenericDomTreeUpdater class. This file should only +// be included by files that implement a specialization of the relevant +// templates. Currently these are: +// - llvm/lib/Analysis/DomTreeUpdater.cpp +// - llvm/lib/CodeGen/MachineDomTreeUpdater.cpp +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H +#define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H + +#include "llvm/Analysis/GenericDomTreeUpdater.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +template +DerivedT &GenericDomTreeUpdater::derived() { + return *static_cast(this); +} + +template +const DerivedT & +GenericDomTreeUpdater::derived() const { + return *static_cast(this); +} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + UpdateStrategy Strategy_) + : Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + DomTreeT &DT_, UpdateStrategy Strategy_) + : DT(&DT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + DomTreeT *DT_, UpdateStrategy Strategy_) + : DT(DT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + PostDomTreeT &PDT_, UpdateStrategy Strategy_) + : PDT(&PDT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + PostDomTreeT *PDT_, UpdateStrategy Strategy_) + : PDT(PDT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + DomTreeT &DT_, PostDomTreeT &PDT_, UpdateStrategy Strategy_) + : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::GenericDomTreeUpdater( + DomTreeT *DT_, PostDomTreeT *PDT_, UpdateStrategy Strategy_) + : DT(DT_), PDT(PDT_), Strategy(Strategy_) {} + +template +GenericDomTreeUpdater::~GenericDomTreeUpdater() { + flush(); +} + +template +bool GenericDomTreeUpdater::isLazy() const { + return Strategy == UpdateStrategy::Lazy; +} + +template +bool GenericDomTreeUpdater::isEager() const { + return Strategy == UpdateStrategy::Eager; +} + +template +bool GenericDomTreeUpdater::hasDomTree() + const { + return DT != nullptr; +} + +template +bool GenericDomTreeUpdater::hasPostDomTree() + const { + return DT != nullptr; +} + +template +bool GenericDomTreeUpdater::hasPendingDeletedBB() const { + return !DeletedBBs.empty(); +} + +template +bool GenericDomTreeUpdater:: + isBBPendingDeletion(BasicBlockT *DelBB) const { + if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty()) + return false; + return DeletedBBs.contains(DelBB); +} + +template +bool GenericDomTreeUpdater::hasPendingUpdates() const { + return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates(); +} + +template +bool GenericDomTreeUpdater::hasPendingDomTreeUpdates() const { + if (!DT) + return false; + return PendUpdates.size() != PendDTUpdateIndex; +} + +template +bool GenericDomTreeUpdater::hasPendingPostDomTreeUpdates() const { + if (!PDT) + return false; + return PendUpdates.size() != PendPDTUpdateIndex; +} + +template +template +void GenericDomTreeUpdater::recalculate( + FuncT &F) { + if (Strategy == UpdateStrategy::Eager) { + if (DT) + DT->recalculate(F); + if (PDT) + PDT->recalculate(F); + return; + } + + // There is little performance gain if we pend the recalculation under + // Lazy UpdateStrategy so we recalculate available trees immediately. + + // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes. + IsRecalculatingDomTree = IsRecalculatingPostDomTree = true; + + // Because all trees are going to be up-to-date after recalculation, + // flush awaiting deleted BasicBlocks. + derived().forceFlushDeletedBB(); + if (DT) + DT->recalculate(F); + if (PDT) + PDT->recalculate(F); + + // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes. + IsRecalculatingDomTree = IsRecalculatingPostDomTree = false; + PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size(); + dropOutOfDateUpdates(); +} + +template +void GenericDomTreeUpdater::applyUpdates( + ArrayRef Updates) { + if (!DT && !PDT) + return; + + if (Strategy == UpdateStrategy::Lazy) { + PendUpdates.reserve(PendUpdates.size() + Updates.size()); + for (const auto &U : Updates) + if (!isSelfDominance(U)) + PendUpdates.push_back(U); + + return; + } + + if (DT) + DT->applyUpdates(Updates); + if (PDT) + PDT->applyUpdates(Updates); +} + +template +void GenericDomTreeUpdater:: + applyUpdatesPermissive(ArrayRef Updates) { + if (!DT && !PDT) + return; + + SmallSet, 8> Seen; + SmallVector DeduplicatedUpdates; + for (const auto &U : Updates) { + auto Edge = std::make_pair(U.getFrom(), U.getTo()); + // Because it is illegal to submit updates that have already been applied + // and updates to an edge need to be strictly ordered, + // it is safe to infer the existence of an edge from the first update + // to this edge. + // If the first update to an edge is "Delete", it means that the edge + // existed before. If the first update to an edge is "Insert", it means + // that the edge didn't exist before. + // + // For example, if the user submits {{Delete, A, B}, {Insert, A, B}}, + // because + // 1. it is illegal to submit updates that have already been applied, + // i.e., user cannot delete an nonexistent edge, + // 2. updates to an edge need to be strictly ordered, + // So, initially edge A -> B existed. + // We can then safely ignore future updates to this edge and directly + // inspect the current CFG: + // a. If the edge still exists, because the user cannot insert an existent + // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and + // resulted in a no-op. DTU won't submit any update in this case. + // b. If the edge doesn't exist, we can then infer that {Delete, A, B} + // actually happened but {Insert, A, B} was an invalid update which never + // happened. DTU will submit {Delete, A, B} in this case. + if (!isSelfDominance(U) && Seen.count(Edge) == 0) { + Seen.insert(Edge); + // If the update doesn't appear in the CFG, it means that + // either the change isn't made or relevant operations + // result in a no-op. + if (isUpdateValid(U)) { + if (isLazy()) + PendUpdates.push_back(U); + else + DeduplicatedUpdates.push_back(U); + } + } + } + + if (Strategy == UpdateStrategy::Lazy) + return; + + if (DT) + DT->applyUpdates(DeduplicatedUpdates); + if (PDT) + PDT->applyUpdates(DeduplicatedUpdates); +} + +template +DomTreeT & +GenericDomTreeUpdater::getDomTree() { + assert(DT && "Invalid acquisition of a null DomTree"); + applyDomTreeUpdates(); + dropOutOfDateUpdates(); + return *DT; +} + +template +PostDomTreeT & +GenericDomTreeUpdater::getPostDomTree() { + assert(PDT && "Invalid acquisition of a null PostDomTree"); + applyPostDomTreeUpdates(); + dropOutOfDateUpdates(); + return *PDT; +} + +template +void GenericDomTreeUpdater::flush() { + applyDomTreeUpdates(); + applyPostDomTreeUpdates(); + dropOutOfDateUpdates(); +} + +template +LLVM_DUMP_METHOD void +GenericDomTreeUpdater::dump() const { +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + raw_ostream &OS = llvm::dbgs(); + + OS << "Available Trees: "; + if (DT || PDT) { + if (DT) + OS << "DomTree "; + if (PDT) + OS << "PostDomTree "; + OS << "\n"; + } else + OS << "None\n"; + + OS << "UpdateStrategy: "; + if (Strategy == UpdateStrategy::Eager) { + OS << "Eager\n"; + return; + } else + OS << "Lazy\n"; + int Index = 0; + + auto printUpdates = + [&](typename ArrayRef::const_iterator + begin, + typename ArrayRef::const_iterator + end) { + if (begin == end) + OS << " None\n"; + Index = 0; + for (auto It = begin, ItEnd = end; It != ItEnd; ++It) { + auto U = *It; + OS << " " << Index << " : "; + ++Index; + if (U.getKind() == DomTreeT::Insert) + OS << "Insert, "; + else + OS << "Delete, "; + BasicBlockT *From = U.getFrom(); + if (From) { + auto S = From->getName(); + if (!From->hasName()) + S = "(no name)"; + OS << S << "(" << From << "), "; + } else { + OS << "(badref), "; + } + BasicBlockT *To = U.getTo(); + if (To) { + auto S = To->getName(); + if (!To->hasName()) + S = "(no_name)"; + OS << S << "(" << To << ")\n"; + } else { + OS << "(badref)\n"; + } + } + }; + + if (DT) { + const auto I = PendUpdates.begin() + PendDTUpdateIndex; + assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && + "Iterator out of range."); + OS << "Applied but not cleared DomTreeUpdates:\n"; + printUpdates(PendUpdates.begin(), I); + OS << "Pending DomTreeUpdates:\n"; + printUpdates(I, PendUpdates.end()); + } + + if (PDT) { + const auto I = PendUpdates.begin() + PendPDTUpdateIndex; + assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && + "Iterator out of range."); + OS << "Applied but not cleared PostDomTreeUpdates:\n"; + printUpdates(PendUpdates.begin(), I); + OS << "Pending PostDomTreeUpdates:\n"; + printUpdates(I, PendUpdates.end()); + } + + OS << "Pending DeletedBBs:\n"; + Index = 0; + for (const auto *BB : DeletedBBs) { + OS << " " << Index << " : "; + ++Index; + if (BB->hasName()) + OS << BB->getName() << "("; + else + OS << "(no_name)("; + OS << BB << ")\n"; + } +#endif +} + +template +bool GenericDomTreeUpdater::isSelfDominance( + typename DomTreeT::UpdateType Update) const { + // Won't affect DomTree and PostDomTree. + return Update.getFrom() == Update.getTo(); +} + +template +void GenericDomTreeUpdater::applyDomTreeUpdates() { + // No pending DomTreeUpdates. + if (Strategy != UpdateStrategy::Lazy || !DT) + return; + + // Only apply updates not are applied by DomTree. + if (hasPendingDomTreeUpdates()) { + const auto I = PendUpdates.begin() + PendDTUpdateIndex; + const auto E = PendUpdates.end(); + assert(I < E && "Iterator range invalid; there should be DomTree updates."); + DT->applyUpdates(ArrayRef(I, E)); + PendDTUpdateIndex = PendUpdates.size(); + } +} + +template +void GenericDomTreeUpdater::applyPostDomTreeUpdates() { + // No pending PostDomTreeUpdates. + if (Strategy != UpdateStrategy::Lazy || !PDT) + return; + + // Only apply updates not are applied by PostDomTree. + if (hasPendingPostDomTreeUpdates()) { + const auto I = PendUpdates.begin() + PendPDTUpdateIndex; + const auto E = PendUpdates.end(); + assert(I < E && + "Iterator range invalid; there should be PostDomTree updates."); + PDT->applyUpdates(ArrayRef(I, E)); + PendPDTUpdateIndex = PendUpdates.size(); + } +} + +template +bool GenericDomTreeUpdater::isUpdateValid( + typename DomTreeT::UpdateType Update) const { + const auto *From = Update.getFrom(); + const auto *To = Update.getTo(); + const auto Kind = Update.getKind(); + + // Discard updates by inspecting the current state of successors of From. + // Since isUpdateValid() must be called *after* the Terminator of From is + // altered we can determine if the update is unnecessary for batch updates + // or invalid for a single update. + const bool HasEdge = llvm::is_contained(successors(From), To); + + // If the IR does not match the update, + // 1. In batch updates, this update is unnecessary. + // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid. + // Edge does not exist in IR. + if (Kind == DomTreeT::Insert && !HasEdge) + return false; + + // Edge exists in IR. + if (Kind == DomTreeT::Delete && HasEdge) + return false; + + return true; +} + +template +void GenericDomTreeUpdater::eraseDelBBNode( + BasicBlockT *DelBB) { + if (DT && !IsRecalculatingDomTree) + if (DT->getNode(DelBB)) + DT->eraseNode(DelBB); + + if (PDT && !IsRecalculatingPostDomTree) + if (PDT->getNode(DelBB)) + PDT->eraseNode(DelBB); +} + +template +void GenericDomTreeUpdater::tryFlushDeletedBB() { + if (!hasPendingUpdates()) + derived().forceFlushDeletedBB(); +} + +template +void GenericDomTreeUpdater::dropOutOfDateUpdates() { + if (Strategy == UpdateStrategy::Eager) + return; + + tryFlushDeletedBB(); + + // Drop all updates applied by both trees. + if (!DT) + PendDTUpdateIndex = PendUpdates.size(); + if (!PDT) + PendPDTUpdateIndex = PendUpdates.size(); + + const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex); + const auto B = PendUpdates.begin(); + const auto E = PendUpdates.begin() + dropIndex; + assert(B <= E && "Iterator out of range."); + PendUpdates.erase(B, E); + // Calculate current index. + PendDTUpdateIndex -= dropIndex; + PendPDTUpdateIndex -= dropIndex; +} + +} // namespace llvm + +#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H diff --git a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h index 9e59ba5f01ab7..e08b6b54c8e70 100644 --- a/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h +++ b/llvm/include/llvm/CodeGen/MachineDomTreeUpdater.h @@ -14,18 +14,13 @@ #ifndef LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H #define LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/GenericDomTreeUpdater.h" #include "llvm/CodeGen/MachineDominators.h" -#include "llvm/CodeGen/MachinePostDominators.h" -#include "llvm/IR/ValueHandle.h" -#include "llvm/Support/Compiler.h" -#include -#include -#include namespace llvm { +class MachinePostDominatorTree; + class MachineDomTreeUpdater : public GenericDomTreeUpdater { @@ -67,5 +62,10 @@ class MachineDomTreeUpdater extern template class GenericDomTreeUpdater< MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>; + +extern template void +GenericDomTreeUpdater::recalculate(MachineFunction + &MF); } // namespace llvm #endif // LLVM_CODEGEN_MACHINEDOMTREEUPDATER_H diff --git a/llvm/lib/Analysis/DomTreeUpdater.cpp b/llvm/lib/Analysis/DomTreeUpdater.cpp index 676cb87210176..6895317c1d03a 100644 --- a/llvm/lib/Analysis/DomTreeUpdater.cpp +++ b/llvm/lib/Analysis/DomTreeUpdater.cpp @@ -13,6 +13,7 @@ #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/GenericDomTreeUpdaterImpl.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" @@ -26,6 +27,10 @@ namespace llvm { template class GenericDomTreeUpdater; +template void +GenericDomTreeUpdater::recalculate(Function &F); + bool DomTreeUpdater::forceFlushDeletedBB() { if (DeletedBBs.empty()) return false; @@ -94,4 +99,23 @@ void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) { new UnreachableInst(DelBB->getContext(), DelBB); } +LLVM_DUMP_METHOD +void DomTreeUpdater::dump() const { + Base::dump(); +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + raw_ostream &OS = dbgs(); + OS << "Pending Callbacks:\n"; + int Index = 0; + for (const auto &BB : Callbacks) { + OS << " " << Index << " : "; + ++Index; + if (BB->hasName()) + OS << BB->getName() << "("; + else + OS << "(no_name)("; + OS << BB << ")\n"; + } +#endif +} + } // namespace llvm diff --git a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp index 86b3185ca90a3..afffafb245e67 100644 --- a/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp +++ b/llvm/lib/CodeGen/MachineDomTreeUpdater.cpp @@ -13,9 +13,8 @@ #include "llvm/CodeGen/MachineDomTreeUpdater.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/Analysis/GenericDomTreeUpdaterImpl.h" #include "llvm/CodeGen/MachinePostDominators.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Instructions.h" #include "llvm/Support/GenericDomTree.h" #include #include @@ -26,6 +25,11 @@ namespace llvm { template class GenericDomTreeUpdater< MachineDomTreeUpdater, MachineDominatorTree, MachinePostDominatorTree>; +template void +GenericDomTreeUpdater::recalculate(MachineFunction + &MF); + bool MachineDomTreeUpdater::forceFlushDeletedBB() { if (DeletedBBs.empty()) return false; From e96e6624c2adbbd650f074891d3580f36b80acfc Mon Sep 17 00:00:00 2001 From: PaperChalice Date: Fri, 28 Jun 2024 18:06:10 +0800 Subject: [PATCH 2/2] Move trivial functions to header --- .../llvm/Analysis/GenericDomTreeUpdater.h | 72 +++++++--- .../llvm/Analysis/GenericDomTreeUpdaterImpl.h | 124 ------------------ 2 files changed, 51 insertions(+), 145 deletions(-) diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h index 1a86398e4fc68..644230264bfe0 100644 --- a/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h +++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdater.h @@ -22,61 +22,84 @@ namespace llvm { template class GenericDomTreeUpdater { - DerivedT &derived(); - const DerivedT &derived() const; + DerivedT &derived() { return *static_cast(this); } + const DerivedT &derived() const { + return *static_cast(this); + } public: enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 }; using BasicBlockT = typename DomTreeT::NodeType; - explicit GenericDomTreeUpdater(UpdateStrategy Strategy_); - GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_); - GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_); - GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_); - GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_); + explicit GenericDomTreeUpdater(UpdateStrategy Strategy_) + : Strategy(Strategy_) {} + GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_) + : DT(&DT_), Strategy(Strategy_) {} + GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_) + : DT(DT_), Strategy(Strategy_) {} + GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_) + : PDT(&PDT_), Strategy(Strategy_) {} + GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_) + : PDT(PDT_), Strategy(Strategy_) {} GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_, - UpdateStrategy Strategy_); + UpdateStrategy Strategy_) + : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {} GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_, - UpdateStrategy Strategy_); + UpdateStrategy Strategy_) + : DT(DT_), PDT(PDT_), Strategy(Strategy_) {} - ~GenericDomTreeUpdater(); + ~GenericDomTreeUpdater() { flush(); } /// Returns true if the current strategy is Lazy. - bool isLazy() const; + bool isLazy() const { return Strategy == UpdateStrategy::Lazy; } /// Returns true if the current strategy is Eager. - bool isEager() const; + bool isEager() const { return Strategy == UpdateStrategy::Eager; } /// Returns true if it holds a DomTreeT. - bool hasDomTree() const; + bool hasDomTree() const { return DT != nullptr; } /// Returns true if it holds a PostDomTreeT. - bool hasPostDomTree() const; + bool hasPostDomTree() const { return PDT != nullptr; } /// Returns true if there is BasicBlockT awaiting deletion. /// The deletion will only happen until a flush event and /// all available trees are up-to-date. /// Returns false under Eager UpdateStrategy. - bool hasPendingDeletedBB() const; + bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); } /// Returns true if DelBB is awaiting deletion. /// Returns false under Eager UpdateStrategy. - bool isBBPendingDeletion(BasicBlockT *DelBB) const; + bool isBBPendingDeletion(BasicBlockT *DelBB) const { + if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty()) + return false; + return DeletedBBs.contains(DelBB); + } /// Returns true if either of DT or PDT is valid and the tree has at /// least one update pending. If DT or PDT is nullptr it is treated /// as having no pending updates. This function does not check /// whether there is MachineBasicBlock awaiting deletion. /// Returns false under Eager UpdateStrategy. - bool hasPendingUpdates() const; + bool hasPendingUpdates() const { + return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates(); + } /// Returns true if there are DomTreeT updates queued. /// Returns false under Eager UpdateStrategy or DT is nullptr. - bool hasPendingDomTreeUpdates() const; + bool hasPendingDomTreeUpdates() const { + if (!DT) + return false; + return PendUpdates.size() != PendDTUpdateIndex; + } /// Returns true if there are PostDomTreeT updates queued. /// Returns false under Eager UpdateStrategy or PDT is nullptr. - bool hasPendingPostDomTreeUpdates() const; + bool hasPendingPostDomTreeUpdates() const { + if (!PDT) + return false; + return PendUpdates.size() != PendPDTUpdateIndex; + } ///@{ /// \name Mutation APIs @@ -166,7 +189,11 @@ class GenericDomTreeUpdater { /// Apply all pending updates to available trees and flush all BasicBlocks /// awaiting deletion. - void flush(); + void flush() { + applyDomTreeUpdates(); + applyPostDomTreeUpdates(); + dropOutOfDateUpdates(); + } ///@} @@ -185,7 +212,10 @@ class GenericDomTreeUpdater { bool IsRecalculatingPostDomTree = false; /// Returns true if the update is self dominance. - bool isSelfDominance(typename DomTreeT::UpdateType Update) const; + bool isSelfDominance(typename DomTreeT::UpdateType Update) const { + // Won't affect DomTree and PostDomTree. + return Update.getFrom() == Update.getTo(); + } /// Helper function to apply all pending DomTree updates. void applyDomTreeUpdates(); diff --git a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h index ec6c345b994ac..35c54a6062bfd 100644 --- a/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h +++ b/llvm/include/llvm/Analysis/GenericDomTreeUpdaterImpl.h @@ -22,116 +22,6 @@ namespace llvm { -template -DerivedT &GenericDomTreeUpdater::derived() { - return *static_cast(this); -} - -template -const DerivedT & -GenericDomTreeUpdater::derived() const { - return *static_cast(this); -} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - UpdateStrategy Strategy_) - : Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - DomTreeT &DT_, UpdateStrategy Strategy_) - : DT(&DT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - DomTreeT *DT_, UpdateStrategy Strategy_) - : DT(DT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - PostDomTreeT &PDT_, UpdateStrategy Strategy_) - : PDT(&PDT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - PostDomTreeT *PDT_, UpdateStrategy Strategy_) - : PDT(PDT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - DomTreeT &DT_, PostDomTreeT &PDT_, UpdateStrategy Strategy_) - : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::GenericDomTreeUpdater( - DomTreeT *DT_, PostDomTreeT *PDT_, UpdateStrategy Strategy_) - : DT(DT_), PDT(PDT_), Strategy(Strategy_) {} - -template -GenericDomTreeUpdater::~GenericDomTreeUpdater() { - flush(); -} - -template -bool GenericDomTreeUpdater::isLazy() const { - return Strategy == UpdateStrategy::Lazy; -} - -template -bool GenericDomTreeUpdater::isEager() const { - return Strategy == UpdateStrategy::Eager; -} - -template -bool GenericDomTreeUpdater::hasDomTree() - const { - return DT != nullptr; -} - -template -bool GenericDomTreeUpdater::hasPostDomTree() - const { - return DT != nullptr; -} - -template -bool GenericDomTreeUpdater::hasPendingDeletedBB() const { - return !DeletedBBs.empty(); -} - -template -bool GenericDomTreeUpdater:: - isBBPendingDeletion(BasicBlockT *DelBB) const { - if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty()) - return false; - return DeletedBBs.contains(DelBB); -} - -template -bool GenericDomTreeUpdater::hasPendingUpdates() const { - return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates(); -} - -template -bool GenericDomTreeUpdater::hasPendingDomTreeUpdates() const { - if (!DT) - return false; - return PendUpdates.size() != PendDTUpdateIndex; -} - -template -bool GenericDomTreeUpdater::hasPendingPostDomTreeUpdates() const { - if (!PDT) - return false; - return PendUpdates.size() != PendPDTUpdateIndex; -} - template template void GenericDomTreeUpdater::recalculate( @@ -258,13 +148,6 @@ GenericDomTreeUpdater::getPostDomTree() { return *PDT; } -template -void GenericDomTreeUpdater::flush() { - applyDomTreeUpdates(); - applyPostDomTreeUpdates(); - dropOutOfDateUpdates(); -} - template LLVM_DUMP_METHOD void GenericDomTreeUpdater::dump() const { @@ -360,13 +243,6 @@ GenericDomTreeUpdater::dump() const { #endif } -template -bool GenericDomTreeUpdater::isSelfDominance( - typename DomTreeT::UpdateType Update) const { - // Won't affect DomTree and PostDomTree. - return Update.getFrom() == Update.getTo(); -} - template void GenericDomTreeUpdater::applyDomTreeUpdates() {