Skip to content

Commit 13e9ef1

Browse files
committed
[Dominators] Implement incremental insertions
Summary: This patch introduces incremental edge insertions based on the Depth Based Search algorithm. Insertions should work for both dominators and postdominators. Reviewers: dberlin, grosser, davide, sanjoy, brzycki Reviewed By: dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D35341 llvm-svn: 308054
1 parent df18cbb commit 13e9ef1

File tree

5 files changed

+373
-5
lines changed

5 files changed

+373
-5
lines changed

llvm/include/llvm/IR/Dominators.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ extern template void Calculate<BBDomTree, Function>(BBDomTree &DT, Function &F);
4545
extern template void Calculate<BBPostDomTree, Function>(BBPostDomTree &DT,
4646
Function &F);
4747

48+
extern template void InsertEdge<BBDomTree>(BBDomTree &DT, BasicBlock *From,
49+
BasicBlock *To);
50+
extern template void InsertEdge<BBPostDomTree>(BBPostDomTree &DT,
51+
BasicBlock *From,
52+
BasicBlock *To);
53+
4854
extern template bool Verify<BBDomTree>(const BBDomTree &DT);
4955
extern template bool Verify<BBPostDomTree>(const BBPostDomTree &DT);
5056
} // namespace DomTreeBuilder

llvm/include/llvm/Support/GenericDomTree.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,18 @@ namespace llvm {
4444
template <typename NodeT, bool IsPostDom>
4545
class DominatorTreeBase;
4646

47+
namespace DomTreeBuilder {
48+
template <class DomTreeT>
49+
struct SemiNCAInfo;
50+
} // namespace DomTreeBuilder
51+
4752
/// \brief Base class for the actual dominator tree node.
4853
template <class NodeT> class DomTreeNodeBase {
4954
friend struct PostDominatorTree;
5055
friend class DominatorTreeBase<NodeT, false>;
5156
friend class DominatorTreeBase<NodeT, true>;
57+
friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase<NodeT, false>>;
58+
friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase<NodeT, true>>;
5259

5360
NodeT *TheBB;
5461
DomTreeNodeBase *IDom;
@@ -179,14 +186,14 @@ void PrintDomTree(const DomTreeNodeBase<NodeT> *N, raw_ostream &O,
179186
}
180187

181188
namespace DomTreeBuilder {
182-
template <typename DomTreeT>
183-
struct SemiNCAInfo;
184-
185-
// The calculate routine is provided in a separate header but referenced here.
189+
// The routines below are provided in a separate header but referenced here.
186190
template <typename DomTreeT, typename FuncT>
187191
void Calculate(DomTreeT &DT, FuncT &F);
188192

189-
// The verify function is provided in a separate header but referenced here.
193+
template <class DomTreeT>
194+
void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
195+
typename DomTreeT::NodePtr To);
196+
190197
template <typename DomTreeT>
191198
bool Verify(const DomTreeT &DT);
192199
} // namespace DomTreeBuilder
@@ -441,6 +448,20 @@ class DominatorTreeBase {
441448
// API to update (Post)DominatorTree information based on modifications to
442449
// the CFG...
443450

451+
/// Inform the dominator tree about a CFG edge insertion and update the tree.
452+
///
453+
/// This function has to be called just before or just after making the update
454+
/// on the actual CFG. There cannot be any other updates that the dominator
455+
/// tree doesn't know about.
456+
/// Note that for postdominators it automatically takes care of inserting
457+
/// a reverse edge internally (so there's no need to swap the parameters).
458+
///
459+
void insertEdge(NodeT *From, NodeT *To) {
460+
assert(From);
461+
assert(To);
462+
DomTreeBuilder::InsertEdge(*this, From, To);
463+
}
464+
444465
/// Add a new node to the dominator tree information.
445466
///
446467
/// This creates a new node as a child of DomBB dominator node, linking it

llvm/include/llvm/Support/GenericDomTreeConstruction.h

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,20 @@
2020
/// out that the theoretically slower O(n*log(n)) implementation is actually
2121
/// faster than the almost-linear O(n*alpha(n)) version, even for large CFGs.
2222
///
23+
/// The file uses the Depth Based Search algorithm to perform incremental
24+
/// upates (insertion and deletions). The implemented algorithm is based on this
25+
/// publication:
26+
///
27+
/// An Experimental Study of Dynamic Dominators
28+
/// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10:
29+
/// https://arxiv.org/pdf/1604.02711.pdf
30+
///
2331
//===----------------------------------------------------------------------===//
2432

2533
#ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
2634
#define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
2735

36+
#include <queue>
2837
#include "llvm/ADT/DepthFirstIterator.h"
2938
#include "llvm/ADT/SmallPtrSet.h"
3039
#include "llvm/Support/Debug.h"
@@ -54,6 +63,7 @@ struct SemiNCAInfo {
5463
using NodePtr = typename DomTreeT::NodePtr;
5564
using NodeT = typename DomTreeT::NodeType;
5665
using TreeNodePtr = DomTreeNodeBase<NodeT> *;
66+
static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
5767

5868
// Information record used by Semi-NCA during tree construction.
5969
struct InfoRec {
@@ -198,6 +208,7 @@ struct SemiNCAInfo {
198208
return VInInfo.Label;
199209
}
200210

211+
// This function requires DFS to be run before calling it.
201212
void runSemiNCA(DomTreeT &DT, const unsigned MinLevel = 0) {
202213
const unsigned NextDFSNum(NumToNode.size());
203214
// Initialize IDoms to spanning tree parents.
@@ -315,6 +326,199 @@ struct SemiNCAInfo {
315326
}
316327
}
317328

329+
// Helper struct used during edge insertions.
330+
struct InsertionInfo {
331+
using BucketElementTy = std::pair<unsigned, TreeNodePtr>;
332+
struct DecreasingLevel {
333+
bool operator()(const BucketElementTy &First,
334+
const BucketElementTy &Second) const {
335+
return First.first > Second.first;
336+
}
337+
};
338+
339+
std::priority_queue<BucketElementTy, SmallVector<BucketElementTy, 8>,
340+
DecreasingLevel>
341+
Bucket; // Queue of tree nodes sorted by level in descending order.
342+
SmallDenseSet<TreeNodePtr, 8> Affected;
343+
SmallDenseSet<TreeNodePtr, 8> Visited;
344+
SmallVector<TreeNodePtr, 8> AffectedQueue;
345+
SmallVector<TreeNodePtr, 8> VisitedNotAffectedQueue;
346+
};
347+
348+
static void InsertEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
349+
assert(From && To && "Cannot connect nullptrs");
350+
DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
351+
<< BlockNamePrinter(To) << "\n");
352+
const TreeNodePtr FromTN = DT.getNode(From);
353+
354+
// Ignore edges from unreachable nodes.
355+
if (!FromTN) return;
356+
357+
DT.DFSInfoValid = false;
358+
359+
const TreeNodePtr ToTN = DT.getNode(To);
360+
if (!ToTN)
361+
InsertUnreachable(DT, FromTN, To);
362+
else
363+
InsertReachable(DT, FromTN, ToTN);
364+
}
365+
366+
// Handles insertion to a node already in the dominator tree.
367+
static void InsertReachable(DomTreeT &DT, const TreeNodePtr From,
368+
const TreeNodePtr To) {
369+
DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
370+
<< " -> " << BlockNamePrinter(To->getBlock()) << "\n");
371+
const NodePtr NCDBlock =
372+
DT.findNearestCommonDominator(From->getBlock(), To->getBlock());
373+
assert(NCDBlock || DT.isPostDominator());
374+
const TreeNodePtr NCD = DT.getNode(NCDBlock);
375+
assert(NCD);
376+
377+
DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
378+
const TreeNodePtr ToIDom = To->getIDom();
379+
380+
// Nothing affected -- NCA property holds.
381+
// (Based on the lemma 2.5 from the second paper.)
382+
if (NCD == To || NCD == ToIDom) return;
383+
384+
// Identify and collect affected nodes.
385+
InsertionInfo II;
386+
DEBUG(dbgs() << "Marking " << BlockNamePrinter(To) << " as affected\n");
387+
II.Affected.insert(To);
388+
const unsigned ToLevel = To->getLevel();
389+
DEBUG(dbgs() << "Putting " << BlockNamePrinter(To) << " into a Bucket\n");
390+
II.Bucket.push({ToLevel, To});
391+
392+
while (!II.Bucket.empty()) {
393+
const TreeNodePtr CurrentNode = II.Bucket.top().second;
394+
II.Bucket.pop();
395+
DEBUG(dbgs() << "\tAdding to Visited and AffectedQueue: "
396+
<< BlockNamePrinter(CurrentNode) << "\n");
397+
II.Visited.insert(CurrentNode);
398+
II.AffectedQueue.push_back(CurrentNode);
399+
400+
// Discover and collect affected successors of the current node.
401+
VisitInsertion(DT, CurrentNode, ToLevel, NCD, II);
402+
}
403+
404+
// Finish by updating immediate dominators and levels.
405+
UpdateInsertion(DT, NCD, II);
406+
}
407+
408+
// Visits an affected node and collect its affected successors.
409+
static void VisitInsertion(DomTreeT &DT, const TreeNodePtr TN,
410+
const unsigned RootLevel, const TreeNodePtr NCD,
411+
InsertionInfo &II) {
412+
const unsigned NCDLevel = NCD->getLevel();
413+
DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << "\n");
414+
415+
assert(TN->getBlock());
416+
for (const NodePtr Succ :
417+
ChildrenGetter<NodePtr, IsPostDom>::Get(TN->getBlock())) {
418+
const TreeNodePtr SuccTN = DT.getNode(Succ);
419+
assert(SuccTN && "Unreachable successor found at reachable insertion");
420+
const unsigned SuccLevel = SuccTN->getLevel();
421+
422+
DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
423+
<< ", level = " << SuccLevel << "\n");
424+
425+
// Succ dominated by subtree From -- not affected.
426+
// (Based on the lemma 2.5 from the second paper.)
427+
if (SuccLevel > RootLevel) {
428+
DEBUG(dbgs() << "\t\tDominated by subtree From\n");
429+
if (II.Visited.count(SuccTN) != 0) continue;
430+
431+
DEBUG(dbgs() << "\t\tMarking visited not affected "
432+
<< BlockNamePrinter(Succ) << "\n");
433+
II.Visited.insert(SuccTN);
434+
II.VisitedNotAffectedQueue.push_back(SuccTN);
435+
VisitInsertion(DT, SuccTN, RootLevel, NCD, II);
436+
} else if ((SuccLevel > NCDLevel + 1) && II.Affected.count(SuccTN) == 0) {
437+
DEBUG(dbgs() << "\t\tMarking affected and adding "
438+
<< BlockNamePrinter(Succ) << " to a Bucket\n");
439+
II.Affected.insert(SuccTN);
440+
II.Bucket.push({SuccLevel, SuccTN});
441+
}
442+
}
443+
}
444+
445+
// Updates immediate dominators and levels after insertion.
446+
static void UpdateInsertion(DomTreeT &DT, const TreeNodePtr NCD,
447+
InsertionInfo &II) {
448+
DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
449+
450+
for (const TreeNodePtr TN : II.AffectedQueue) {
451+
DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
452+
<< ") = " << BlockNamePrinter(NCD) << "\n");
453+
TN->setIDom(NCD);
454+
}
455+
456+
UpdateLevelsAfterInsertion(II);
457+
}
458+
459+
static void UpdateLevelsAfterInsertion(InsertionInfo &II) {
460+
DEBUG(dbgs() << "Updating levels for visited but not affected nodes\n");
461+
462+
for (const TreeNodePtr TN : II.VisitedNotAffectedQueue) {
463+
DEBUG(dbgs() << "\tlevel(" << BlockNamePrinter(TN) << ") = ("
464+
<< BlockNamePrinter(TN->getIDom()) << ") "
465+
<< TN->getIDom()->getLevel() << " + 1\n");
466+
TN->UpdateLevel();
467+
}
468+
}
469+
470+
// Handles insertion to previousely unreachable nodes.
471+
static void InsertUnreachable(DomTreeT &DT, const TreeNodePtr From,
472+
const NodePtr To) {
473+
DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
474+
<< " -> (unreachable) " << BlockNamePrinter(To) << "\n");
475+
476+
// Collect discovered edges to already reachable nodes.
477+
SmallVector<std::pair<NodePtr, TreeNodePtr>, 8> DiscoveredEdgesToReachable;
478+
// Discover and connect nodes that became reachable with the insertion.
479+
ComputeUnreachableDominators(DT, To, From, DiscoveredEdgesToReachable);
480+
481+
DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
482+
<< " -> (prev unreachable) " << BlockNamePrinter(To) << "\n");
483+
484+
DEBUG(DT.print(dbgs()));
485+
486+
// Used the discovered edges and inset discovered connecting (incoming)
487+
// edges.
488+
for (const auto &Edge : DiscoveredEdgesToReachable) {
489+
DEBUG(dbgs() << "\tInserting discovered connecting edge "
490+
<< BlockNamePrinter(Edge.first) << " -> "
491+
<< BlockNamePrinter(Edge.second) << "\n");
492+
InsertReachable(DT, DT.getNode(Edge.first), Edge.second);
493+
}
494+
}
495+
496+
// Connects nodes that become reachable with an insertion.
497+
static void ComputeUnreachableDominators(
498+
DomTreeT &DT, const NodePtr Root, const TreeNodePtr Incoming,
499+
SmallVectorImpl<std::pair<NodePtr, TreeNodePtr>>
500+
&DiscoveredConnectingEdges) {
501+
assert(!DT.getNode(Root) && "Root must not be reachable");
502+
503+
// Visit only previously unreachable nodes.
504+
auto UnreachableDescender = [&DT, &DiscoveredConnectingEdges](NodePtr From,
505+
NodePtr To) {
506+
const TreeNodePtr ToTN = DT.getNode(To);
507+
if (!ToTN) return true;
508+
509+
DiscoveredConnectingEdges.push_back({From, ToTN});
510+
return false;
511+
};
512+
513+
SemiNCAInfo SNCA;
514+
SNCA.runDFS<IsPostDom>(Root, 0, UnreachableDescender, 0);
515+
SNCA.runSemiNCA(DT);
516+
SNCA.attachNewSubtree(DT, Incoming);
517+
518+
DEBUG(dbgs() << "After adding unreachable nodes\n");
519+
DEBUG(DT.print(dbgs()));
520+
}
521+
318522
// Checks if the tree contains all reachable nodes in the input graph.
319523
bool verifyReachability(const DomTreeT &DT) {
320524
clear();
@@ -527,6 +731,13 @@ void Calculate(DomTreeT &DT, FuncT &F) {
527731
SNCA.calculateFromScratch(DT, GraphTraits<FuncT *>::size(&F));
528732
}
529733

734+
template <class DomTreeT>
735+
void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
736+
typename DomTreeT::NodePtr To) {
737+
if (DT.isPostDominator()) std::swap(From, To);
738+
SemiNCAInfo<DomTreeT>::InsertEdge(DT, From, To);
739+
}
740+
530741
template <class DomTreeT>
531742
bool Verify(const DomTreeT &DT) {
532743
SemiNCAInfo<DomTreeT> SNCA;

llvm/lib/IR/Dominators.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ template void
7171
llvm::DomTreeBuilder::Calculate<DomTreeBuilder::BBPostDomTree, Function>(
7272
DomTreeBuilder::BBPostDomTree &DT, Function &F);
7373

74+
template void llvm::DomTreeBuilder::InsertEdge<DomTreeBuilder::BBDomTree>(
75+
DomTreeBuilder::BBDomTree &DT, BasicBlock *From, BasicBlock *To);
76+
template void llvm::DomTreeBuilder::InsertEdge<DomTreeBuilder::BBPostDomTree>(
77+
DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To);
78+
7479
template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>(
7580
const DomTreeBuilder::BBDomTree &DT);
7681
template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBPostDomTree>(

0 commit comments

Comments
 (0)