llvm.org GIT mirror llvm / 79eefe9
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@308054 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 2 years ago
5 changed file(s) with 373 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
4343 extern template void Calculate(BBDomTree &DT, Function &F);
4444 extern template void Calculate(BBPostDomTree &DT,
4545 Function &F);
46
47 extern template void InsertEdge(BBDomTree &DT, BasicBlock *From,
48 BasicBlock *To);
49 extern template void InsertEdge(BBPostDomTree &DT,
50 BasicBlock *From,
51 BasicBlock *To);
4652
4753 extern template bool Verify(const BBDomTree &DT);
4854 extern template bool Verify(const BBPostDomTree &DT);
4343 template
4444 class DominatorTreeBase;
4545
46 namespace DomTreeBuilder {
47 template
48 struct SemiNCAInfo;
49 } // namespace DomTreeBuilder
50
4651 /// \brief Base class for the actual dominator tree node.
4752 template class DomTreeNodeBase {
4853 friend struct PostDominatorTree;
4954 friend class DominatorTreeBase;
5055 friend class DominatorTreeBase;
56 friend struct DomTreeBuilder::SemiNCAInfo>;
57 friend struct DomTreeBuilder::SemiNCAInfo>;
5158
5259 NodeT *TheBB;
5360 DomTreeNodeBase *IDom;
178185 }
179186
180187 namespace DomTreeBuilder {
181 template
182 struct SemiNCAInfo;
183
184 // The calculate routine is provided in a separate header but referenced here.
188 // The routines below are provided in a separate header but referenced here.
185189 template
186190 void Calculate(DomTreeT &DT, FuncT &F);
187191
188 // The verify function is provided in a separate header but referenced here.
192 template
193 void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
194 typename DomTreeT::NodePtr To);
195
189196 template
190197 bool Verify(const DomTreeT &DT);
191198 } // namespace DomTreeBuilder
439446 //===--------------------------------------------------------------------===//
440447 // API to update (Post)DominatorTree information based on modifications to
441448 // the CFG...
449
450 /// Inform the dominator tree about a CFG edge insertion and update the tree.
451 ///
452 /// This function has to be called just before or just after making the update
453 /// on the actual CFG. There cannot be any other updates that the dominator
454 /// tree doesn't know about.
455 /// Note that for postdominators it automatically takes care of inserting
456 /// a reverse edge internally (so there's no need to swap the parameters).
457 ///
458 void insertEdge(NodeT *From, NodeT *To) {
459 assert(From);
460 assert(To);
461 DomTreeBuilder::InsertEdge(*this, From, To);
462 }
442463
443464 /// Add a new node to the dominator tree information.
444465 ///
1919 /// out that the theoretically slower O(n*log(n)) implementation is actually
2020 /// faster than the almost-linear O(n*alpha(n)) version, even for large CFGs.
2121 ///
22 /// The file uses the Depth Based Search algorithm to perform incremental
23 /// upates (insertion and deletions). The implemented algorithm is based on this
24 /// publication:
25 ///
26 /// An Experimental Study of Dynamic Dominators
27 /// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10:
28 /// https://arxiv.org/pdf/1604.02711.pdf
29 ///
2230 //===----------------------------------------------------------------------===//
2331
2432 #ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
2533 #define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
2634
35 #include
2736 #include "llvm/ADT/DepthFirstIterator.h"
2837 #include "llvm/ADT/SmallPtrSet.h"
2938 #include "llvm/Support/Debug.h"
5362 using NodePtr = typename DomTreeT::NodePtr;
5463 using NodeT = typename DomTreeT::NodeType;
5564 using TreeNodePtr = DomTreeNodeBase *;
65 static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
5666
5767 // Information record used by Semi-NCA during tree construction.
5868 struct InfoRec {
197207 return VInInfo.Label;
198208 }
199209
210 // This function requires DFS to be run before calling it.
200211 void runSemiNCA(DomTreeT &DT, const unsigned MinLevel = 0) {
201212 const unsigned NextDFSNum(NumToNode.size());
202213 // Initialize IDoms to spanning tree parents.
314325 }
315326 }
316327
328 // Helper struct used during edge insertions.
329 struct InsertionInfo {
330 using BucketElementTy = std::pair;
331 struct DecreasingLevel {
332 bool operator()(const BucketElementTy &First,
333 const BucketElementTy &Second) const {
334 return First.first > Second.first;
335 }
336 };
337
338 std::priority_queue,
339 DecreasingLevel>
340 Bucket; // Queue of tree nodes sorted by level in descending order.
341 SmallDenseSet Affected;
342 SmallDenseSet Visited;
343 SmallVector AffectedQueue;
344 SmallVector VisitedNotAffectedQueue;
345 };
346
347 static void InsertEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
348 assert(From && To && "Cannot connect nullptrs");
349 DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
350 << BlockNamePrinter(To) << "\n");
351 const TreeNodePtr FromTN = DT.getNode(From);
352
353 // Ignore edges from unreachable nodes.
354 if (!FromTN) return;
355
356 DT.DFSInfoValid = false;
357
358 const TreeNodePtr ToTN = DT.getNode(To);
359 if (!ToTN)
360 InsertUnreachable(DT, FromTN, To);
361 else
362 InsertReachable(DT, FromTN, ToTN);
363 }
364
365 // Handles insertion to a node already in the dominator tree.
366 static void InsertReachable(DomTreeT &DT, const TreeNodePtr From,
367 const TreeNodePtr To) {
368 DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
369 << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
370 const NodePtr NCDBlock =
371 DT.findNearestCommonDominator(From->getBlock(), To->getBlock());
372 assert(NCDBlock || DT.isPostDominator());
373 const TreeNodePtr NCD = DT.getNode(NCDBlock);
374 assert(NCD);
375
376 DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
377 const TreeNodePtr ToIDom = To->getIDom();
378
379 // Nothing affected -- NCA property holds.
380 // (Based on the lemma 2.5 from the second paper.)
381 if (NCD == To || NCD == ToIDom) return;
382
383 // Identify and collect affected nodes.
384 InsertionInfo II;
385 DEBUG(dbgs() << "Marking " << BlockNamePrinter(To) << " as affected\n");
386 II.Affected.insert(To);
387 const unsigned ToLevel = To->getLevel();
388 DEBUG(dbgs() << "Putting " << BlockNamePrinter(To) << " into a Bucket\n");
389 II.Bucket.push({ToLevel, To});
390
391 while (!II.Bucket.empty()) {
392 const TreeNodePtr CurrentNode = II.Bucket.top().second;
393 II.Bucket.pop();
394 DEBUG(dbgs() << "\tAdding to Visited and AffectedQueue: "
395 << BlockNamePrinter(CurrentNode) << "\n");
396 II.Visited.insert(CurrentNode);
397 II.AffectedQueue.push_back(CurrentNode);
398
399 // Discover and collect affected successors of the current node.
400 VisitInsertion(DT, CurrentNode, ToLevel, NCD, II);
401 }
402
403 // Finish by updating immediate dominators and levels.
404 UpdateInsertion(DT, NCD, II);
405 }
406
407 // Visits an affected node and collect its affected successors.
408 static void VisitInsertion(DomTreeT &DT, const TreeNodePtr TN,
409 const unsigned RootLevel, const TreeNodePtr NCD,
410 InsertionInfo &II) {
411 const unsigned NCDLevel = NCD->getLevel();
412 DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << "\n");
413
414 assert(TN->getBlock());
415 for (const NodePtr Succ :
416 ChildrenGetter::Get(TN->getBlock())) {
417 const TreeNodePtr SuccTN = DT.getNode(Succ);
418 assert(SuccTN && "Unreachable successor found at reachable insertion");
419 const unsigned SuccLevel = SuccTN->getLevel();
420
421 DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
422 << ", level = " << SuccLevel << "\n");
423
424 // Succ dominated by subtree From -- not affected.
425 // (Based on the lemma 2.5 from the second paper.)
426 if (SuccLevel > RootLevel) {
427 DEBUG(dbgs() << "\t\tDominated by subtree From\n");
428 if (II.Visited.count(SuccTN) != 0) continue;
429
430 DEBUG(dbgs() << "\t\tMarking visited not affected "
431 << BlockNamePrinter(Succ) << "\n");
432 II.Visited.insert(SuccTN);
433 II.VisitedNotAffectedQueue.push_back(SuccTN);
434 VisitInsertion(DT, SuccTN, RootLevel, NCD, II);
435 } else if ((SuccLevel > NCDLevel + 1) && II.Affected.count(SuccTN) == 0) {
436 DEBUG(dbgs() << "\t\tMarking affected and adding "
437 << BlockNamePrinter(Succ) << " to a Bucket\n");
438 II.Affected.insert(SuccTN);
439 II.Bucket.push({SuccLevel, SuccTN});
440 }
441 }
442 }
443
444 // Updates immediate dominators and levels after insertion.
445 static void UpdateInsertion(DomTreeT &DT, const TreeNodePtr NCD,
446 InsertionInfo &II) {
447 DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
448
449 for (const TreeNodePtr TN : II.AffectedQueue) {
450 DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
451 << ") = " << BlockNamePrinter(NCD) << "\n");
452 TN->setIDom(NCD);
453 }
454
455 UpdateLevelsAfterInsertion(II);
456 }
457
458 static void UpdateLevelsAfterInsertion(InsertionInfo &II) {
459 DEBUG(dbgs() << "Updating levels for visited but not affected nodes\n");
460
461 for (const TreeNodePtr TN : II.VisitedNotAffectedQueue) {
462 DEBUG(dbgs() << "\tlevel(" << BlockNamePrinter(TN) << ") = ("
463 << BlockNamePrinter(TN->getIDom()) << ") "
464 << TN->getIDom()->getLevel() << " + 1\n");
465 TN->UpdateLevel();
466 }
467 }
468
469 // Handles insertion to previousely unreachable nodes.
470 static void InsertUnreachable(DomTreeT &DT, const TreeNodePtr From,
471 const NodePtr To) {
472 DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
473 << " -> (unreachable) " << BlockNamePrinter(To) << "\n");
474
475 // Collect discovered edges to already reachable nodes.
476 SmallVector, 8> DiscoveredEdgesToReachable;
477 // Discover and connect nodes that became reachable with the insertion.
478 ComputeUnreachableDominators(DT, To, From, DiscoveredEdgesToReachable);
479
480 DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
481 << " -> (prev unreachable) " << BlockNamePrinter(To) << "\n");
482
483 DEBUG(DT.print(dbgs()));
484
485 // Used the discovered edges and inset discovered connecting (incoming)
486 // edges.
487 for (const auto &Edge : DiscoveredEdgesToReachable) {
488 DEBUG(dbgs() << "\tInserting discovered connecting edge "
489 << BlockNamePrinter(Edge.first) << " -> "
490 << BlockNamePrinter(Edge.second) << "\n");
491 InsertReachable(DT, DT.getNode(Edge.first), Edge.second);
492 }
493 }
494
495 // Connects nodes that become reachable with an insertion.
496 static void ComputeUnreachableDominators(
497 DomTreeT &DT, const NodePtr Root, const TreeNodePtr Incoming,
498 SmallVectorImpl>
499 &DiscoveredConnectingEdges) {
500 assert(!DT.getNode(Root) && "Root must not be reachable");
501
502 // Visit only previously unreachable nodes.
503 auto UnreachableDescender = [&DT, &DiscoveredConnectingEdges](NodePtr From,
504 NodePtr To) {
505 const TreeNodePtr ToTN = DT.getNode(To);
506 if (!ToTN) return true;
507
508 DiscoveredConnectingEdges.push_back({From, ToTN});
509 return false;
510 };
511
512 SemiNCAInfo SNCA;
513 SNCA.runDFS(Root, 0, UnreachableDescender, 0);
514 SNCA.runSemiNCA(DT);
515 SNCA.attachNewSubtree(DT, Incoming);
516
517 DEBUG(dbgs() << "After adding unreachable nodes\n");
518 DEBUG(DT.print(dbgs()));
519 }
520
317521 // Checks if the tree contains all reachable nodes in the input graph.
318522 bool verifyReachability(const DomTreeT &DT) {
319523 clear();
527731 }
528732
529733 template
734 void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
735 typename DomTreeT::NodePtr To) {
736 if (DT.isPostDominator()) std::swap(From, To);
737 SemiNCAInfo::InsertEdge(DT, From, To);
738 }
739
740 template
530741 bool Verify(const DomTreeT &DT) {
531742 SemiNCAInfo SNCA;
532743 return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&
6969 template void
7070 llvm::DomTreeBuilder::Calculate(
7171 DomTreeBuilder::BBPostDomTree &DT, Function &F);
72
73 template void llvm::DomTreeBuilder::InsertEdge(
74 DomTreeBuilder::BBDomTree &DT, BasicBlock *From, BasicBlock *To);
75 template void llvm::DomTreeBuilder::InsertEdge(
76 DomTreeBuilder::BBPostDomTree &DT, BasicBlock *From, BasicBlock *To);
7277
7378 template bool llvm::DomTreeBuilder::Verify(
7479 const DomTreeBuilder::BBDomTree &DT);
1414 #include "llvm/IR/LLVMContext.h"
1515 #include "llvm/IR/Module.h"
1616 #include "llvm/Support/SourceMgr.h"
17 #include "CFGBuilder.h"
1718 #include "gtest/gtest.h"
1819
1920 using namespace llvm;
322323 EXPECT_FALSE(DT->dominates(Edge_BB0_BB1_b, BB2));
323324 });
324325 }
326
327 namespace {
328 const auto Insert = CFGBuilder::ActionKind::Insert;
329
330 bool CompUpdates(const CFGBuilder::Update &A, const CFGBuilder::Update &B) {
331 return std::tie(A.Action, A.Edge.From, A.Edge.To) <
332 std::tie(B.Action, B.Edge.From, B.Edge.To);
333 };
334 } // namespace
335
336 TEST(DominatorTree, InsertReachable) {
337 CFGHolder Holder;
338 std::vector Arcs = {
339 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"},
340 {"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}};
341
342 std::vector Updates = {{Insert, {"12", "10"}},
343 {Insert, {"10", "9"}},
344 {Insert, {"7", "6"}},
345 {Insert, {"7", "5"}}};
346 CFGBuilder B(Holder.F, Arcs, Updates);
347 DominatorTree DT(*Holder.F);
348 EXPECT_TRUE(DT.verify());
349 PostDomTree PDT(*Holder.F);
350 EXPECT_TRUE(PDT.verify());
351
352 Optional LastUpdate;
353 while ((LastUpdate = B.applyUpdate())) {
354 EXPECT_EQ(LastUpdate->Action, Insert);
355 BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
356 BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
357 DT.insertEdge(From, To);
358 EXPECT_TRUE(DT.verify());
359 PDT.insertEdge(From, To);
360 EXPECT_TRUE(PDT.verify());
361 }
362 }
363
364 TEST(DominatorTree, InsertUnreachable) {
365 CFGHolder Holder;
366 std::vector Arcs = {{"1", "2"}, {"2", "3"}, {"3", "4"},
367 {"5", "6"}, {"5", "7"}, {"3", "8"},
368 {"9", "10"}, {"11", "12"}};
369
370 std::vector Updates = {{Insert, {"4", "5"}},
371 {Insert, {"8", "9"}},
372 {Insert, {"10", "12"}},
373 {Insert, {"10", "11"}}};
374 CFGBuilder B(Holder.F, Arcs, Updates);
375 DominatorTree DT(*Holder.F);
376 EXPECT_TRUE(DT.verify());
377 PostDomTree PDT(*Holder.F);
378 EXPECT_TRUE(PDT.verify());
379
380 Optional LastUpdate;
381 while ((LastUpdate = B.applyUpdate())) {
382 EXPECT_EQ(LastUpdate->Action, Insert);
383 BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
384 BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
385 DT.insertEdge(From, To);
386 EXPECT_TRUE(DT.verify());
387 PDT.insertEdge(From, To);
388 EXPECT_TRUE(PDT.verify());
389 }
390 }
391
392 TEST(DominatorTree, InsertMixed) {
393 CFGHolder Holder;
394 std::vector Arcs = {
395 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"5", "6"}, {"5", "7"},
396 {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}, {"7", "3"}};
397
398 std::vector Updates = {
399 {Insert, {"4", "5"}}, {Insert, {"2", "5"}}, {Insert, {"10", "9"}},
400 {Insert, {"12", "10"}}, {Insert, {"12", "10"}}, {Insert, {"7", "8"}},
401 {Insert, {"7", "5"}}};
402 CFGBuilder B(Holder.F, Arcs, Updates);
403 DominatorTree DT(*Holder.F);
404 EXPECT_TRUE(DT.verify());
405 PostDomTree PDT(*Holder.F);
406 EXPECT_TRUE(PDT.verify());
407
408 Optional LastUpdate;
409 while ((LastUpdate = B.applyUpdate())) {
410 EXPECT_EQ(LastUpdate->Action, Insert);
411 BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
412 BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
413 DT.insertEdge(From, To);
414 EXPECT_TRUE(DT.verify());
415 PDT.insertEdge(From, To);
416 EXPECT_TRUE(PDT.verify());
417 }
418 }
419
420 TEST(DominatorTree, InsertPermut) {
421 std::vector Arcs = {
422 {"1", "2"}, {"2", "3"}, {"3", "4"}, {"5", "6"}, {"5", "7"},
423 {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}, {"7", "3"}};
424
425 std::vector Updates = {{Insert, {"4", "5"}},
426 {Insert, {"2", "5"}},
427 {Insert, {"10", "9"}},
428 {Insert, {"12", "10"}}};
429
430 while (std::next_permutation(Updates.begin(), Updates.end(), CompUpdates)) {
431 CFGHolder Holder;
432 CFGBuilder B(Holder.F, Arcs, Updates);
433 DominatorTree DT(*Holder.F);
434 EXPECT_TRUE(DT.verify());
435 PostDomTree PDT(*Holder.F);
436 EXPECT_TRUE(PDT.verify());
437
438 Optional LastUpdate;
439 while ((LastUpdate = B.applyUpdate())) {
440 EXPECT_EQ(LastUpdate->Action, Insert);
441 BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
442 BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
443 DT.insertEdge(From, To);
444 EXPECT_TRUE(DT.verify());
445 PDT.insertEdge(From, To);
446 EXPECT_TRUE(PDT.verify());
447 }
448 }
449 }