Reapply "[DomTree] Replace ChildrenGetter with GraphTraits over GraphDiff."

This is the part of the patch that's moving the Updates to a CFGDiff
object. Splitting off from the clean-up work merging the two branches when BUI is null.

Differential Revision: https://reviews.llvm.org/D77341
This commit is contained in:
Alina Sbirlea 2020-04-09 18:29:40 -07:00
parent 3554cf4f38
commit 8bf4c1f4fb
5 changed files with 97 additions and 138 deletions

View File

@ -44,6 +44,9 @@ using BBPostDomTree = PostDomTreeBase<BasicBlock>;
using BBUpdates = ArrayRef<llvm::cfg::Update<BasicBlock *>>; using BBUpdates = ArrayRef<llvm::cfg::Update<BasicBlock *>>;
using BBDomTreeGraphDiff = GraphDiff<BasicBlock *, false>;
using BBPostDomTreeGraphDiff = GraphDiff<BasicBlock *, true>;
extern template void Calculate<BBDomTree>(BBDomTree &DT); extern template void Calculate<BBDomTree>(BBDomTree &DT);
extern template void CalculateWithUpdates<BBDomTree>(BBDomTree &DT, extern template void CalculateWithUpdates<BBDomTree>(BBDomTree &DT,
BBUpdates U); BBUpdates U);
@ -62,8 +65,10 @@ extern template void DeleteEdge<BBPostDomTree>(BBPostDomTree &DT,
BasicBlock *From, BasicBlock *From,
BasicBlock *To); BasicBlock *To);
extern template void ApplyUpdates<BBDomTree>(BBDomTree &DT, BBUpdates); extern template void ApplyUpdates<BBDomTree>(BBDomTree &DT,
extern template void ApplyUpdates<BBPostDomTree>(BBPostDomTree &DT, BBUpdates); BBDomTreeGraphDiff &);
extern template void ApplyUpdates<BBPostDomTree>(BBPostDomTree &DT,
BBPostDomTreeGraphDiff &);
extern template bool Verify<BBDomTree>(const BBDomTree &DT, extern template bool Verify<BBDomTree>(const BBDomTree &DT,
BBDomTree::VerificationLevel VL); BBDomTree::VerificationLevel VL);

View File

@ -70,6 +70,23 @@
namespace llvm { namespace llvm {
namespace detail {
template <typename Range>
auto reverse_if_helper(Range &&R, std::integral_constant<bool, false>) {
return std::forward<Range>(R);
}
template <typename Range>
auto reverse_if_helper(Range &&R, std::integral_constant<bool, true>) {
return llvm::reverse(std::forward<Range>(R));
}
template <bool B, typename Range> auto reverse_if(Range &&R) {
return reverse_if_helper(std::forward<Range>(R),
std::integral_constant<bool, B>{});
}
} // namespace detail
// GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, provide // GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, provide
// utilities to skip edges marked as deleted and return a set of edges marked as // utilities to skip edges marked as deleted and return a set of edges marked as
// newly inserted. The current diff treats the CFG as a graph rather than a // newly inserted. The current diff treats the CFG as a graph rather than a
@ -113,8 +130,7 @@ public:
GraphDiff() : UpdatedAreReverseApplied(false) {} GraphDiff() : UpdatedAreReverseApplied(false) {}
GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates, GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates,
bool ReverseApplyUpdates = false) { bool ReverseApplyUpdates = false) {
cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph, cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph);
/*ReverseResultOrder=*/true);
// The legalized updates are stored in reverse so we can pop_back when doing // The legalized updates are stored in reverse so we can pop_back when doing
// incremental updates. // incremental updates.
for (auto U : LegalizedUpdates) { for (auto U : LegalizedUpdates) {
@ -174,6 +190,25 @@ public:
return make_range(It->second.begin(), It->second.end()); return make_range(It->second.begin(), It->second.end());
} }
using VectRet = SmallVector<NodePtr, 8>;
template <bool InverseEdge> VectRet getChildren(NodePtr N) const {
using DirectedNodeT =
std::conditional_t<InverseEdge, Inverse<NodePtr>, NodePtr>;
auto R = children<DirectedNodeT>(N);
auto CurrentCFGChildren = detail::reverse_if<!InverseEdge>(R);
VectRet UpdatedCFGChildren;
for (auto Child : CurrentCFGChildren)
if (Child && !ignoreChild(N, Child, InverseEdge))
UpdatedCFGChildren.push_back(Child);
auto AddedCFGChildren = getAddedChildren(N, InverseEdge);
UpdatedCFGChildren.insert(UpdatedCFGChildren.end(),
AddedCFGChildren.begin(), AddedCFGChildren.end());
return UpdatedCFGChildren;
}
void print(raw_ostream &OS) const { void print(raw_ostream &OS) const {
OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n" OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n"
"===== (Note: notion of children/inverse_children depends on " "===== (Note: notion of children/inverse_children depends on "
@ -210,9 +245,10 @@ struct CFGViewChildren {
// filter iterator init: // filter iterator init:
auto R = make_range(GT::child_begin(N.second), GT::child_end(N.second)); auto R = make_range(GT::child_begin(N.second), GT::child_end(N.second));
auto RR = detail::reverse_if<!InverseEdge>(R);
// This lambda is copied into the iterators and persists to callers, ensure // This lambda is copied into the iterators and persists to callers, ensure
// captures are by value or otherwise have sufficient lifetime. // captures are by value or otherwise have sufficient lifetime.
auto First = make_filter_range(makeChildRange(R, N.first), [N](NodeRef C) { auto First = make_filter_range(makeChildRange(RR, N.first), [N](NodeRef C) {
return !C.first->ignoreChild(N.second, C.second, InverseEdge); return !C.first->ignoreChild(N.second, C.second, InverseEdge);
}); });

View File

@ -28,6 +28,7 @@
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CFGDiff.h"
#include "llvm/Support/CFGUpdate.h" #include "llvm/Support/CFGUpdate.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include <algorithm> #include <algorithm>
@ -211,7 +212,8 @@ void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
template <typename DomTreeT> template <typename DomTreeT>
void ApplyUpdates(DomTreeT &DT, void ApplyUpdates(DomTreeT &DT,
ArrayRef<typename DomTreeT::UpdateType> Updates); GraphDiff<typename DomTreeT::NodePtr,
DomTreeT::IsPostDominator> &PreViewCFG);
template <typename DomTreeT> template <typename DomTreeT>
bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL); bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL);
@ -535,10 +537,13 @@ protected:
/// The type of updates is the same for DomTreeBase<T> and PostDomTreeBase<T> /// The type of updates is the same for DomTreeBase<T> and PostDomTreeBase<T>
/// with the same template parameter T. /// with the same template parameter T.
/// ///
/// \param Updates An unordered sequence of updates to perform. /// \param Updates An unordered sequence of updates to perform. The current
/// CFG and the reverse of these updates provides the pre-view of the CFG.
/// ///
void applyUpdates(ArrayRef<UpdateType> Updates) { void applyUpdates(ArrayRef<UpdateType> Updates) {
DomTreeBuilder::ApplyUpdates(*this, Updates); GraphDiff<NodePtr, IsPostDominator> PreViewCFG(
Updates, /*ReverseApplyUpdates=*/true);
DomTreeBuilder::ApplyUpdates(*this, PreViewCFG);
} }
/// Inform the dominator tree about a CFG edge insertion and update the tree. /// Inform the dominator tree about a CFG edge insertion and update the tree.

View File

@ -58,6 +58,7 @@ struct SemiNCAInfo {
using TreeNodePtr = DomTreeNodeBase<NodeT> *; using TreeNodePtr = DomTreeNodeBase<NodeT> *;
using RootsT = decltype(DomTreeT::Roots); using RootsT = decltype(DomTreeT::Roots);
static constexpr bool IsPostDom = DomTreeT::IsPostDominator; static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
// Information record used by Semi-NCA during tree construction. // Information record used by Semi-NCA during tree construction.
struct InfoRec { struct InfoRec {
@ -77,28 +78,27 @@ struct SemiNCAInfo {
using UpdateT = typename DomTreeT::UpdateType; using UpdateT = typename DomTreeT::UpdateType;
using UpdateKind = typename DomTreeT::UpdateKind; using UpdateKind = typename DomTreeT::UpdateKind;
struct BatchUpdateInfo { struct BatchUpdateInfo {
SmallVector<UpdateT, 4> Updates; // Note: Updates inside PreViewCFG are aleady legalized.
using NodePtrAndKind = PointerIntPair<NodePtr, 1, UpdateKind>; BatchUpdateInfo(GraphDiffT &PreViewCFG)
: PreViewCFG(PreViewCFG),
NumLegalized(PreViewCFG.getNumLegalizedUpdates()) {}
// In order to be able to walk a CFG that is out of sync with the CFG
// DominatorTree last knew about, use the list of updates to reconstruct
// previous CFG versions of the current CFG. For each node, we store a set
// of its virtually added/deleted future successors and predecessors.
// Note that these children are from the future relative to what the
// DominatorTree knows about -- using them to gets us some snapshot of the
// CFG from the past (relative to the state of the CFG).
DenseMap<NodePtr, SmallVector<NodePtrAndKind, 4>> FutureSuccessors;
DenseMap<NodePtr, SmallVector<NodePtrAndKind, 4>> FuturePredecessors;
// Remembers if the whole tree was recalculated at some point during the // Remembers if the whole tree was recalculated at some point during the
// current batch update. // current batch update.
bool IsRecalculated = false; bool IsRecalculated = false;
GraphDiffT &PreViewCFG;
const size_t NumLegalized;
}; };
BatchUpdateInfo *BatchUpdates; BatchUpdateInfo *BatchUpdates;
using BatchUpdatePtr = BatchUpdateInfo *; using BatchUpdatePtr = BatchUpdateInfo *;
std::unique_ptr<GraphDiffT> EmptyGD;
// If BUI is a nullptr, then there's no batch update in progress. // If BUI is a nullptr, then there's no batch update in progress.
SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {} SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {
if (!BatchUpdates)
EmptyGD = std::make_unique<GraphDiffT>();
}
void clear() { void clear() {
NumToNode = {nullptr}; // Restore to initial state with a dummy start node. NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
@ -107,8 +107,7 @@ struct SemiNCAInfo {
// in progress, we need this information to continue it. // in progress, we need this information to continue it.
} }
template <bool Inverse> template <bool Inversed> struct ChildrenGetter {
struct ChildrenGetter {
using ResultTy = SmallVector<NodePtr, 8>; using ResultTy = SmallVector<NodePtr, 8>;
static ResultTy Get(NodePtr N, std::integral_constant<bool, false>) { static ResultTy Get(NodePtr N, std::integral_constant<bool, false>) {
@ -121,50 +120,16 @@ struct SemiNCAInfo {
return ResultTy(IChildren.begin(), IChildren.end()); return ResultTy(IChildren.begin(), IChildren.end());
} }
using Tag = std::integral_constant<bool, Inverse>; using Tag = std::integral_constant<bool, Inversed>;
// The function below is the core part of the batch updater. It allows the // The function below is the core part of the batch updater. It allows the
// Depth Based Search algorithm to perform incremental updates in lockstep // Depth Based Search algorithm to perform incremental updates in lockstep
// with updates to the CFG. We emulated lockstep CFG updates by getting its // with updates to the CFG. We emulated lockstep CFG updates by getting its
// next snapshots by reverse-applying future updates. // next snapshots by reverse-applying future updates.
static ResultTy Get(NodePtr N, BatchUpdatePtr BUI) { static ResultTy Get(NodePtr N, BatchUpdatePtr BUI) {
ResultTy Res = Get(N, Tag()); if (!BUI)
// If there's no batch update in progress, simply return node's children. return Get(N, Tag());
if (!BUI) return Res; return BUI->PreViewCFG.template getChildren<Inversed>(N);
// CFG children are actually its *most current* children, and we have to
// reverse-apply the future updates to get the node's children at the
// point in time the update was performed.
auto &FutureChildren = (Inverse != IsPostDom) ? BUI->FuturePredecessors
: BUI->FutureSuccessors;
auto FCIt = FutureChildren.find(N);
if (FCIt == FutureChildren.end()) return Res;
for (auto ChildAndKind : FCIt->second) {
const NodePtr Child = ChildAndKind.getPointer();
const UpdateKind UK = ChildAndKind.getInt();
// Reverse-apply the future update.
if (UK == UpdateKind::Insert) {
// If there's an insertion in the future, it means that the edge must
// exist in the current CFG, but was not present in it before.
assert(llvm::find(Res, Child) != Res.end()
&& "Expected child not found in the CFG");
Res.erase(std::remove(Res.begin(), Res.end(), Child), Res.end());
LLVM_DEBUG(dbgs() << "\tHiding edge " << BlockNamePrinter(N) << " -> "
<< BlockNamePrinter(Child) << "\n");
} else {
// If there's an deletion in the future, it means that the edge cannot
// exist in the current CFG, but existed in it before.
assert(llvm::find(Res, Child) == Res.end() &&
"Unexpected child found in the CFG");
LLVM_DEBUG(dbgs() << "\tShowing virtual edge " << BlockNamePrinter(N)
<< " -> " << BlockNamePrinter(Child) << "\n");
Res.push_back(Child);
}
}
return Res;
} }
}; };
@ -1005,15 +970,14 @@ struct SemiNCAInfo {
const TreeNodePtr TN) { const TreeNodePtr TN) {
LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN) LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN)
<< "\n"); << "\n");
for (const NodePtr Pred : auto TNB = TN->getBlock();
ChildrenGetter<!IsPostDom>::Get(TN->getBlock(), BUI)) { for (const NodePtr Pred : ChildrenGetter<!IsPostDom>::Get(TNB, BUI)) {
LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n"); LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
if (!DT.getNode(Pred)) continue; if (!DT.getNode(Pred)) continue;
const NodePtr Support = const NodePtr Support = DT.findNearestCommonDominator(TNB, Pred);
DT.findNearestCommonDominator(TN->getBlock(), Pred);
LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n"); LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
if (Support != TN->getBlock()) { if (Support != TNB) {
LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN) LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
<< " is reachable from support " << " is reachable from support "
<< BlockNamePrinter(Support) << "\n"); << BlockNamePrinter(Support) << "\n");
@ -1144,53 +1108,23 @@ struct SemiNCAInfo {
//===--------------------- DomTree Batch Updater --------------------------=== //===--------------------- DomTree Batch Updater --------------------------===
//~~ //~~
static void ApplyUpdates(DomTreeT &DT, ArrayRef<UpdateT> Updates) { static void ApplyUpdates(DomTreeT &DT, GraphDiffT &PreViewCFG) {
const size_t NumUpdates = Updates.size(); const size_t NumUpdates = PreViewCFG.getNumLegalizedUpdates();
if (NumUpdates == 0) if (NumUpdates == 0)
return; return;
// Take the fast path for a single update and avoid running the batch update // Take the fast path for a single update and avoid running the batch update
// machinery. // machinery.
if (NumUpdates == 1) { if (NumUpdates == 1) {
const auto &Update = Updates.front(); UpdateT Update = PreViewCFG.popUpdateForIncrementalUpdates();
if (Update.getKind() == UpdateKind::Insert) if (Update.getKind() == UpdateKind::Insert)
DT.insertEdge(Update.getFrom(), Update.getTo()); InsertEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
else else
DT.deleteEdge(Update.getFrom(), Update.getTo()); DeleteEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
return; return;
} }
BatchUpdateInfo BUI; BatchUpdateInfo BUI(PreViewCFG);
LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n");
cfg::LegalizeUpdates<NodePtr>(Updates, BUI.Updates, IsPostDom);
const size_t NumLegalized = BUI.Updates.size();
BUI.FutureSuccessors.reserve(NumLegalized);
BUI.FuturePredecessors.reserve(NumLegalized);
// Use the legalized future updates to initialize future successors and
// predecessors. Note that these sets will only decrease size over time, as
// the next CFG snapshots slowly approach the actual (current) CFG.
for (UpdateT &U : BUI.Updates) {
BUI.FutureSuccessors[U.getFrom()].push_back({U.getTo(), U.getKind()});
BUI.FuturePredecessors[U.getTo()].push_back({U.getFrom(), U.getKind()});
}
#if 0
// FIXME: The LLVM_DEBUG macro only plays well with a modular
// build of LLVM when the header is marked as textual, but doing
// so causes redefinition errors.
LLVM_DEBUG(dbgs() << "About to apply " << NumLegalized << " updates\n");
LLVM_DEBUG(if (NumLegalized < 32) for (const auto &U
: reverse(BUI.Updates)) {
dbgs() << "\t";
U.dump();
dbgs() << "\n";
});
LLVM_DEBUG(dbgs() << "\n");
#endif
// Recalculate the DominatorTree when the number of updates // Recalculate the DominatorTree when the number of updates
// exceeds a threshold, which usually makes direct updating slower than // exceeds a threshold, which usually makes direct updating slower than
// recalculation. We select this threshold proportional to the // recalculation. We select this threshold proportional to the
@ -1200,21 +1134,21 @@ struct SemiNCAInfo {
// Make unittests of the incremental algorithm work // Make unittests of the incremental algorithm work
if (DT.DomTreeNodes.size() <= 100) { if (DT.DomTreeNodes.size() <= 100) {
if (NumLegalized > DT.DomTreeNodes.size()) if (BUI.NumLegalized > DT.DomTreeNodes.size())
CalculateFromScratch(DT, &BUI); CalculateFromScratch(DT, &BUI);
} else if (NumLegalized > DT.DomTreeNodes.size() / 40) } else if (BUI.NumLegalized > DT.DomTreeNodes.size() / 40)
CalculateFromScratch(DT, &BUI); CalculateFromScratch(DT, &BUI);
// If the DominatorTree was recalculated at some point, stop the batch // If the DominatorTree was recalculated at some point, stop the batch
// updates. Full recalculations ignore batch updates and look at the actual // updates. Full recalculations ignore batch updates and look at the actual
// CFG. // CFG.
for (size_t i = 0; i < NumLegalized && !BUI.IsRecalculated; ++i) for (size_t i = 0; i < BUI.NumLegalized && !BUI.IsRecalculated; ++i)
ApplyNextUpdate(DT, BUI); ApplyNextUpdate(DT, BUI);
} }
static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) { static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
assert(!BUI.Updates.empty() && "No updates to apply!"); // Popping the next update, will move the PreViewCFG to the next snapshot.
UpdateT CurrentUpdate = BUI.Updates.pop_back_val(); UpdateT CurrentUpdate = BUI.PreViewCFG.popUpdateForIncrementalUpdates();
#if 0 #if 0
// FIXME: The LLVM_DEBUG macro only plays well with a modular // FIXME: The LLVM_DEBUG macro only plays well with a modular
// build of LLVM when the header is marked as textual, but doing // build of LLVM when the header is marked as textual, but doing
@ -1223,21 +1157,6 @@ struct SemiNCAInfo {
LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n"); LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n");
#endif #endif
// Move to the next snapshot of the CFG by removing the reverse-applied
// current update. Since updates are performed in the same order they are
// legalized it's sufficient to pop the last item here.
auto &FS = BUI.FutureSuccessors[CurrentUpdate.getFrom()];
assert(FS.back().getPointer() == CurrentUpdate.getTo() &&
FS.back().getInt() == CurrentUpdate.getKind());
FS.pop_back();
if (FS.empty()) BUI.FutureSuccessors.erase(CurrentUpdate.getFrom());
auto &FP = BUI.FuturePredecessors[CurrentUpdate.getTo()];
assert(FP.back().getPointer() == CurrentUpdate.getFrom() &&
FP.back().getInt() == CurrentUpdate.getKind());
FP.pop_back();
if (FP.empty()) BUI.FuturePredecessors.erase(CurrentUpdate.getTo());
if (CurrentUpdate.getKind() == UpdateKind::Insert) if (CurrentUpdate.getKind() == UpdateKind::Insert)
InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo()); InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
else else
@ -1596,19 +1515,11 @@ void Calculate(DomTreeT &DT) {
template <typename DomTreeT> template <typename DomTreeT>
void CalculateWithUpdates(DomTreeT &DT, void CalculateWithUpdates(DomTreeT &DT,
ArrayRef<typename DomTreeT::UpdateType> Updates) { ArrayRef<typename DomTreeT::UpdateType> Updates) {
// TODO: Move BUI creation in common method, reuse in ApplyUpdates. // FIXME: Updated to use the PreViewCFG and behave the same as until now.
typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI; // This behavior is however incorrect; this actually needs the PostViewCFG.
LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n"); GraphDiff<typename DomTreeT::NodePtr, DomTreeT::IsPostDominator> PreViewCFG(
cfg::LegalizeUpdates<typename DomTreeT::NodePtr>(Updates, BUI.Updates, Updates, /*ReverseApplyUpdates=*/true);
DomTreeT::IsPostDominator); typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI(PreViewCFG);
const size_t NumLegalized = BUI.Updates.size();
BUI.FutureSuccessors.reserve(NumLegalized);
BUI.FuturePredecessors.reserve(NumLegalized);
for (auto &U : BUI.Updates) {
BUI.FutureSuccessors[U.getFrom()].push_back({U.getTo(), U.getKind()});
BUI.FuturePredecessors[U.getTo()].push_back({U.getFrom(), U.getKind()});
}
SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI); SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI);
} }
@ -1628,8 +1539,9 @@ void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
template <class DomTreeT> template <class DomTreeT>
void ApplyUpdates(DomTreeT &DT, void ApplyUpdates(DomTreeT &DT,
ArrayRef<typename DomTreeT::UpdateType> Updates) { GraphDiff<typename DomTreeT::NodePtr,
SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, Updates); DomTreeT::IsPostDominator> &PreViewCFG) {
SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, PreViewCFG);
} }
template <class DomTreeT> template <class DomTreeT>

View File

@ -90,9 +90,10 @@ template void llvm::DomTreeBuilder::DeleteEdge<DomTreeBuilder::BBPostDomTree>(
DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To); DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To);
template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBDomTree>( template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBDomTree>(
DomTreeBuilder::BBDomTree &DT, DomTreeBuilder::BBUpdates); DomTreeBuilder::BBDomTree &DT, DomTreeBuilder::BBDomTreeGraphDiff &);
template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBPostDomTree>( template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBPostDomTree>(
DomTreeBuilder::BBPostDomTree &DT, DomTreeBuilder::BBUpdates); DomTreeBuilder::BBPostDomTree &DT,
DomTreeBuilder::BBPostDomTreeGraphDiff &);
template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>( template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>(
const DomTreeBuilder::BBDomTree &DT, const DomTreeBuilder::BBDomTree &DT,