aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h')
-rw-r--r--contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h293
1 files changed, 129 insertions, 164 deletions
diff --git a/contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h
index 464de4e2b3ba..4b59ad1f017f 100644
--- a/contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h
+++ b/contrib/llvm-project/llvm/include/llvm/Support/GenericDomTreeConstruction.h
@@ -58,6 +58,7 @@ struct SemiNCAInfo {
using TreeNodePtr = DomTreeNodeBase<NodeT> *;
using RootsT = decltype(DomTreeT::Roots);
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
+ using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
// Information record used by Semi-NCA during tree construction.
struct InfoRec {
@@ -77,21 +78,17 @@ struct SemiNCAInfo {
using UpdateT = typename DomTreeT::UpdateType;
using UpdateKind = typename DomTreeT::UpdateKind;
struct BatchUpdateInfo {
- SmallVector<UpdateT, 4> Updates;
- using NodePtrAndKind = PointerIntPair<NodePtr, 1, UpdateKind>;
-
- // 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;
+ // Note: Updates inside PreViewCFG are aleady legalized.
+ BatchUpdateInfo(GraphDiffT &PreViewCFG, GraphDiffT *PostViewCFG = nullptr)
+ : PreViewCFG(PreViewCFG), PostViewCFG(PostViewCFG),
+ NumLegalized(PreViewCFG.getNumLegalizedUpdates()) {}
+
// Remembers if the whole tree was recalculated at some point during the
// current batch update.
bool IsRecalculated = false;
+ GraphDiffT &PreViewCFG;
+ GraphDiffT *PostViewCFG;
+ const size_t NumLegalized;
};
BatchUpdateInfo *BatchUpdates;
@@ -107,66 +104,24 @@ struct SemiNCAInfo {
// in progress, we need this information to continue it.
}
- template <bool Inverse>
- struct ChildrenGetter {
- using ResultTy = SmallVector<NodePtr, 8>;
-
- static ResultTy Get(NodePtr N, std::integral_constant<bool, false>) {
- auto RChildren = reverse(children<NodePtr>(N));
- return ResultTy(RChildren.begin(), RChildren.end());
- }
-
- static ResultTy Get(NodePtr N, std::integral_constant<bool, true>) {
- auto IChildren = inverse_children<NodePtr>(N);
- return ResultTy(IChildren.begin(), IChildren.end());
- }
+ template <bool Inversed>
+ static SmallVector<NodePtr, 8> getChildren(NodePtr N, BatchUpdatePtr BUI) {
+ if (BUI)
+ return BUI->PreViewCFG.template getChildren<Inversed>(N);
+ return getChildren<Inversed>(N);
+ }
- using Tag = std::integral_constant<bool, Inverse>;
-
- // The function below is the core part of the batch updater. It allows the
- // Depth Based Search algorithm to perform incremental updates in lockstep
- // with updates to the CFG. We emulated lockstep CFG updates by getting its
- // next snapshots by reverse-applying future updates.
- static ResultTy Get(NodePtr N, BatchUpdatePtr BUI) {
- ResultTy Res = Get(N, Tag());
- // If there's no batch update in progress, simply return node's children.
- if (!BUI) return Res;
-
- // 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);
- }
- }
+ template <bool Inversed>
+ static SmallVector<NodePtr, 8> getChildren(NodePtr N) {
+ using DirectedNodeT =
+ std::conditional_t<Inversed, Inverse<NodePtr>, NodePtr>;
+ auto R = children<DirectedNodeT>(N);
+ SmallVector<NodePtr, 8> Res(detail::reverse_if<!Inversed>(R));
- return Res;
- }
- };
+ // Remove nullptr children for clang.
+ llvm::erase_value(Res, nullptr);
+ return Res;
+ }
NodePtr getIDom(NodePtr BB) const {
auto InfoIt = NodeToInfo.find(BB);
@@ -208,6 +163,8 @@ struct SemiNCAInfo {
}
};
+ using NodeOrderMap = DenseMap<NodePtr, unsigned>;
+
// Custom DFS implementation which can skip nodes based on a provided
// predicate. It also collects ReverseChildren so that we don't have to spend
// time getting predecessors in SemiNCA.
@@ -215,9 +172,13 @@ struct SemiNCAInfo {
// If IsReverse is set to true, the DFS walk will be performed backwards
// relative to IsPostDom -- using reverse edges for dominators and forward
// edges for postdominators.
+ //
+ // If SuccOrder is specified then in this order the DFS traverses the children
+ // otherwise the order is implied by the results of getChildren().
template <bool IsReverse = false, typename DescendCondition>
unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
- unsigned AttachToNum) {
+ unsigned AttachToNum,
+ const NodeOrderMap *SuccOrder = nullptr) {
assert(V);
SmallVector<NodePtr, 64> WorkList = {V};
if (NodeToInfo.count(V) != 0) NodeToInfo[V].Parent = AttachToNum;
@@ -233,8 +194,14 @@ struct SemiNCAInfo {
NumToNode.push_back(BB);
constexpr bool Direction = IsReverse != IsPostDom; // XOR.
- for (const NodePtr Succ :
- ChildrenGetter<Direction>::Get(BB, BatchUpdates)) {
+ auto Successors = getChildren<Direction>(BB, BatchUpdates);
+ if (SuccOrder && Successors.size() > 1)
+ llvm::sort(
+ Successors.begin(), Successors.end(), [=](NodePtr A, NodePtr B) {
+ return SuccOrder->find(A)->second < SuccOrder->find(B)->second;
+ });
+
+ for (const NodePtr Succ : Successors) {
const auto SIT = NodeToInfo.find(Succ);
// Don't visit nodes more than once but remember to collect
// ReverseChildren.
@@ -369,7 +336,7 @@ struct SemiNCAInfo {
// to CFG nodes within infinite loops.
static bool HasForwardSuccessors(const NodePtr N, BatchUpdatePtr BUI) {
assert(N && "N must be a valid node");
- return !ChildrenGetter<false>::Get(N, BUI).empty();
+ return !getChildren<false>(N, BUI).empty();
}
static NodePtr GetEntryNode(const DomTreeT &DT) {
@@ -430,6 +397,32 @@ struct SemiNCAInfo {
// nodes.
if (Total + 1 != Num) {
HasNonTrivialRoots = true;
+
+ // SuccOrder is the order of blocks in the function. It is needed to make
+ // the calculation of the FurthestAway node and the whole PostDomTree
+ // immune to swap successors transformation (e.g. canonicalizing branch
+ // predicates). SuccOrder is initialized lazily only for successors of
+ // reverse unreachable nodes.
+ Optional<NodeOrderMap> SuccOrder;
+ auto InitSuccOrderOnce = [&]() {
+ SuccOrder = NodeOrderMap();
+ for (const auto Node : nodes(DT.Parent))
+ if (SNCA.NodeToInfo.count(Node) == 0)
+ for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
+ SuccOrder->try_emplace(Succ, 0);
+
+ // Add mapping for all entries of SuccOrder.
+ unsigned NodeNum = 0;
+ for (const auto Node : nodes(DT.Parent)) {
+ ++NodeNum;
+ auto Order = SuccOrder->find(Node);
+ if (Order != SuccOrder->end()) {
+ assert(Order->second == 0);
+ Order->second = NodeNum;
+ }
+ }
+ };
+
// Make another DFS pass over all other nodes to find the
// reverse-unreachable blocks, and find the furthest paths we'll be able
// to make.
@@ -454,7 +447,12 @@ struct SemiNCAInfo {
// expensive and does not always lead to a minimal set of roots.
LLVM_DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
- const unsigned NewNum = SNCA.runDFS<true>(I, Num, AlwaysDescend, Num);
+ if (!SuccOrder)
+ InitSuccOrderOnce();
+ assert(SuccOrder);
+
+ const unsigned NewNum =
+ SNCA.runDFS<true>(I, Num, AlwaysDescend, Num, &*SuccOrder);
const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
LLVM_DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
<< "(non-trivial root): "
@@ -530,7 +528,7 @@ struct SemiNCAInfo {
// If we wound another root in a (forward) DFS walk, remove the current
// root from the set of roots, as it is reverse-reachable from the other
// one.
- if (llvm::find(Roots, N) != Roots.end()) {
+ if (llvm::is_contained(Roots, N)) {
LLVM_DEBUG(dbgs() << "\tForward DFS walk found another root "
<< BlockNamePrinter(N) << "\n\tRemoving root "
<< BlockNamePrinter(Root) << "\n");
@@ -563,12 +561,21 @@ struct SemiNCAInfo {
auto *Parent = DT.Parent;
DT.reset();
DT.Parent = Parent;
- SemiNCAInfo SNCA(nullptr); // Since we are rebuilding the whole tree,
- // there's no point doing it incrementally.
+ // If the update is using the actual CFG, BUI is null. If it's using a view,
+ // BUI is non-null and the PreCFGView is used. When calculating from
+ // scratch, make the PreViewCFG equal to the PostCFGView, so Post is used.
+ BatchUpdatePtr PostViewBUI = nullptr;
+ if (BUI && BUI->PostViewCFG) {
+ BUI->PreViewCFG = *BUI->PostViewCFG;
+ PostViewBUI = BUI;
+ }
+ // This is rebuilding the whole tree, not incrementally, but PostViewBUI is
+ // used in case the caller needs a DT update with a CFGView.
+ SemiNCAInfo SNCA(PostViewBUI);
// Step #0: Number blocks in depth-first order and initialize variables used
// in later stages of the algorithm.
- DT.Roots = FindRoots(DT, nullptr);
+ DT.Roots = FindRoots(DT, PostViewBUI);
SNCA.doFullDFSWalk(DT, AlwaysDescend);
SNCA.runSemiNCA(DT);
@@ -679,8 +686,7 @@ struct SemiNCAInfo {
// root.
if (!DT.isVirtualRoot(To->getIDom())) return false;
- auto RIt = llvm::find(DT.Roots, To->getBlock());
- if (RIt == DT.Roots.end())
+ if (!llvm::is_contained(DT.Roots, To->getBlock()))
return false; // To is not a root, nothing to update.
LLVM_DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
@@ -787,8 +793,7 @@ struct SemiNCAInfo {
//
// Invariant: there is an optimal path from `To` to TN with the minimum
// depth being CurrentLevel.
- for (const NodePtr Succ :
- ChildrenGetter<IsPostDom>::Get(TN->getBlock(), BUI)) {
+ for (const NodePtr Succ : getChildren<IsPostDom>(TN->getBlock(), BUI)) {
const TreeNodePtr SuccTN = DT.getNode(Succ);
assert(SuccTN &&
"Unreachable successor found at reachable insertion");
@@ -918,8 +923,8 @@ struct SemiNCAInfo {
// the DomTree about it.
// The check is O(N), so run it only in debug configuration.
auto IsSuccessor = [BUI](const NodePtr SuccCandidate, const NodePtr Of) {
- auto Successors = ChildrenGetter<IsPostDom>::Get(Of, BUI);
- return llvm::find(Successors, SuccCandidate) != Successors.end();
+ auto Successors = getChildren<IsPostDom>(Of, BUI);
+ return llvm::is_contained(Successors, SuccCandidate);
};
(void)IsSuccessor;
assert(!IsSuccessor(To, From) && "Deleted edge still exists in the CFG!");
@@ -1005,15 +1010,14 @@ struct SemiNCAInfo {
const TreeNodePtr TN) {
LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN)
<< "\n");
- for (const NodePtr Pred :
- ChildrenGetter<!IsPostDom>::Get(TN->getBlock(), BUI)) {
+ auto TNB = TN->getBlock();
+ for (const NodePtr Pred : getChildren<!IsPostDom>(TNB, BUI)) {
LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
if (!DT.getNode(Pred)) continue;
- const NodePtr Support =
- DT.findNearestCommonDominator(TN->getBlock(), Pred);
+ const NodePtr Support = DT.findNearestCommonDominator(TNB, Pred);
LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
- if (Support != TN->getBlock()) {
+ if (Support != TNB) {
LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
<< " is reachable from support "
<< BlockNamePrinter(Support) << "\n");
@@ -1054,7 +1058,7 @@ struct SemiNCAInfo {
const TreeNodePtr TN = DT.getNode(To);
assert(TN);
if (TN->getLevel() > Level) return true;
- if (llvm::find(AffectedQueue, To) == AffectedQueue.end())
+ if (!llvm::is_contained(AffectedQueue, To))
AffectedQueue.push_back(To);
return false;
@@ -1144,53 +1148,34 @@ struct SemiNCAInfo {
//===--------------------- DomTree Batch Updater --------------------------===
//~~
- static void ApplyUpdates(DomTreeT &DT, ArrayRef<UpdateT> Updates) {
- const size_t NumUpdates = Updates.size();
+ static void ApplyUpdates(DomTreeT &DT, GraphDiffT &PreViewCFG,
+ GraphDiffT *PostViewCFG) {
+ // Note: the PostViewCFG is only used when computing from scratch. It's data
+ // should already included in the PreViewCFG for incremental updates.
+ const size_t NumUpdates = PreViewCFG.getNumLegalizedUpdates();
if (NumUpdates == 0)
return;
// Take the fast path for a single update and avoid running the batch update
// machinery.
if (NumUpdates == 1) {
- const auto &Update = Updates.front();
- if (Update.getKind() == UpdateKind::Insert)
- DT.insertEdge(Update.getFrom(), Update.getTo());
- else
- DT.deleteEdge(Update.getFrom(), Update.getTo());
-
+ UpdateT Update = PreViewCFG.popUpdateForIncrementalUpdates();
+ if (!PostViewCFG) {
+ if (Update.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
+ else
+ DeleteEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
+ } else {
+ BatchUpdateInfo BUI(*PostViewCFG, PostViewCFG);
+ if (Update.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, &BUI, Update.getFrom(), Update.getTo());
+ else
+ DeleteEdge(DT, &BUI, Update.getFrom(), Update.getTo());
+ }
return;
}
- BatchUpdateInfo BUI;
- 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
-
+ BatchUpdateInfo BUI(PreViewCFG, PostViewCFG);
// Recalculate the DominatorTree when the number of updates
// exceeds a threshold, which usually makes direct updating slower than
// recalculation. We select this threshold proportional to the
@@ -1200,21 +1185,21 @@ struct SemiNCAInfo {
// Make unittests of the incremental algorithm work
if (DT.DomTreeNodes.size() <= 100) {
- if (NumLegalized > DT.DomTreeNodes.size())
+ if (BUI.NumLegalized > DT.DomTreeNodes.size())
CalculateFromScratch(DT, &BUI);
- } else if (NumLegalized > DT.DomTreeNodes.size() / 40)
+ } else if (BUI.NumLegalized > DT.DomTreeNodes.size() / 40)
CalculateFromScratch(DT, &BUI);
// If the DominatorTree was recalculated at some point, stop the batch
// updates. Full recalculations ignore batch updates and look at the actual
// 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);
}
static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
- assert(!BUI.Updates.empty() && "No updates to apply!");
- UpdateT CurrentUpdate = BUI.Updates.pop_back_val();
+ // Popping the next update, will move the PreViewCFG to the next snapshot.
+ UpdateT CurrentUpdate = BUI.PreViewCFG.popUpdateForIncrementalUpdates();
#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
@@ -1223,21 +1208,6 @@ struct SemiNCAInfo {
LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n");
#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)
InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
else
@@ -1596,19 +1566,11 @@ void Calculate(DomTreeT &DT) {
template <typename DomTreeT>
void CalculateWithUpdates(DomTreeT &DT,
ArrayRef<typename DomTreeT::UpdateType> Updates) {
- // TODO: Move BUI creation in common method, reuse in ApplyUpdates.
- typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI;
- LLVM_DEBUG(dbgs() << "Legalizing " << BUI.Updates.size() << " updates\n");
- cfg::LegalizeUpdates<typename DomTreeT::NodePtr>(Updates, BUI.Updates,
- DomTreeT::IsPostDominator);
- 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()});
- }
-
+ // FIXME: Updated to use the PreViewCFG and behave the same as until now.
+ // This behavior is however incorrect; this actually needs the PostViewCFG.
+ GraphDiff<typename DomTreeT::NodePtr, DomTreeT::IsPostDominator> PreViewCFG(
+ Updates, /*ReverseApplyUpdates=*/true);
+ typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI(PreViewCFG);
SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI);
}
@@ -1628,8 +1590,11 @@ void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
template <class DomTreeT>
void ApplyUpdates(DomTreeT &DT,
- ArrayRef<typename DomTreeT::UpdateType> Updates) {
- SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, Updates);
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> &PreViewCFG,
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> *PostViewCFG) {
+ SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, PreViewCFG, PostViewCFG);
}
template <class DomTreeT>