llvm.org GIT mirror llvm / c0f00a9
[Dominators] Include infinite loops in PostDominatorTree Summary: This patch teaches PostDominatorTree about infinite loops. It is built on top of D29705 by @dberlin which includes a very detailed motivation for this change. What's new is that the patch also teaches the incremental updater how to deal with reverse-unreachable regions and how to properly maintain and verify tree roots. Before that, the incremental algorithm sometimes ended up preserving reverse-unreachable regions after updates that wouldn't appear in the tree if it was constructed from scratch on the same CFG. This patch makes the following assumptions: - A sequence of updates should produce the same tree as a recalculating it. - Any sequence of the same updates should lead to the same tree. - Siblings and roots are unordered. The last two properties are essential to efficiently perform batch updates in the future. When it comes to the first one, we can decide later that the consistency between freshly built tree and an updated one doesn't matter match, as there are many correct ways to pick roots in infinite loops, and to relax this assumption. That should enable us to recalculate postdominators less frequently. This patch is pretty conservative when it comes to incremental updates on reverse-unreachable regions and ends up recalculating the whole tree in many cases. It should be possible to improve the performance in many cases, if we decide that it's important enough. That being said, my experiments showed that reverse-unreachable are very rare in the IR emitted by clang when bootstrapping clang. Here are the statistics I collected by analyzing IR between passes and after each removePredecessor call: ``` # functions: 52283 # samples: 337609 # reverse unreachable BBs: 216022 # BBs: 247840796 Percent reverse-unreachable: 0.08716159869015269 % Max(PercRevUnreachable) in a function: 87.58620689655172 % # > 25 % samples: 471 ( 0.1395104988314885 % samples ) ... in 145 ( 0.27733680163724345 % functions ) ``` Most of the reverse-unreachable regions come from invalid IR where it wouldn't be possible to construct a PostDomTree anyway. I would like to commit this patch in the next week in order to be able to complete the work that depends on it before the end of my internship, so please don't wait long to voice your concerns :). Reviewers: dberlin, sanjoy, grosser, brzycki, davide, chandlerc, hfinkel Reviewed By: dberlin Subscribers: nhaehnle, javed.absar, kparzysz, uabelho, jlebar, hiraditya, llvm-commits, dberlin, david2050 Differential Revision: https://reviews.llvm.org/D35851 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310940 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 2 years ago
23 changed file(s) with 751 addition(s) and 246 deletion(s). Raw diff Collapse all Expand all
416416 }
417417
418418 /// findNearestCommonDominator - Find nearest common dominator basic block
419 /// for basic block A and B. If there is no such block then return NULL.
419 /// for basic block A and B. If there is no such block then return nullptr.
420420 NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const {
421 assert(A && B && "Pointers are not valid");
421422 assert(A->getParent() == B->getParent() &&
422423 "Two blocks are not in same function");
423424
424425 // If either A or B is a entry block then it is nearest common dominator
425426 // (for forward-dominators).
426 if (!this->isPostDominator()) {
427 if (!isPostDominator()) {
427428 NodeT &Entry = A->getParent()->front();
428429 if (A == &Entry || B == &Entry)
429430 return &Entry;
579580 }
580581
581582 DomTreeNodes.erase(BB);
583
584 if (!IsPostDom) return;
585
586 // Remember to update PostDominatorTree roots.
587 auto RIt = llvm::find(Roots, BB);
588 if (RIt != Roots.end()) {
589 std::swap(*RIt, Roots.back());
590 Roots.pop_back();
591 }
582592 }
583593
584594 /// splitBlock - BB is split and now it has one successor. Update dominator
594604 ///
595605 void print(raw_ostream &O) const {
596606 O << "=============================--------------------------------\n";
597 if (this->isPostDominator())
607 if (IsPostDominator)
598608 O << "Inorder PostDominator Tree: ";
599609 else
600610 O << "Inorder Dominator Tree: ";
604614
605615 // The postdom tree can have a null root if there are no returns.
606616 if (getRootNode()) PrintDomTree(getRootNode(), O, 1);
617 if (IsPostDominator) {
618 O << "Roots: ";
619 for (const NodePtr Block : Roots) {
620 Block->printAsOperand(O, false);
621 O << " ";
622 }
623 O << "\n";
624 }
607625 }
608626
609627 public:
6363 using NodePtr = typename DomTreeT::NodePtr;
6464 using NodeT = typename DomTreeT::NodeType;
6565 using TreeNodePtr = DomTreeNodeBase *;
66 using RootsT = decltype(DomTreeT::Roots);
6667 static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
6768
6869 // Information record used by Semi-NCA during tree construction.
130131 // Custom DFS implementation which can skip nodes based on a provided
131132 // predicate. It also collects ReverseChildren so that we don't have to spend
132133 // time getting predecessors in SemiNCA.
133 template
134 //
135 // If IsReverse is set to true, the DFS walk will be performed backwards
136 // relative to IsPostDom -- using reverse edges for dominators and forward
137 // edges for postdominators.
138 template
134139 unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
135140 unsigned AttachToNum) {
136141 assert(V);
147152 BBInfo.Label = BB;
148153 NumToNode.push_back(BB);
149154
150 for (const NodePtr Succ : ChildrenGetter::Get(BB)) {
155 constexpr bool Direction = IsReverse != IsPostDom; // XOR.
156 for (const NodePtr Succ : ChildrenGetter::Get(BB)) {
151157 const auto SIT = NodeToInfo.find(Succ);
152158 // Don't visit nodes more than once but remember to collect
153159 // ReverseChildren.
255261 }
256262 }
257263
264 // PostDominatorTree always has a virtual root that represents a virtual CFG
265 // node that serves as a single exit from the function. All the other exits
266 // (CFG nodes with terminators and nodes in infinite loops are logically
267 // connected to this virtual CFG exit node).
268 // This functions maps a nullptr CFG node to the virtual root tree node.
269 void addVirtualRoot() {
270 assert(IsPostDom && "Only postdominators have a virtual root");
271 assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
272
273 auto &BBInfo = NodeToInfo[nullptr];
274 BBInfo.DFSNum = BBInfo.Semi = 1;
275 BBInfo.Label = nullptr;
276
277 NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
278 }
279
280 // For postdominators, nodes with no forward successors are trivial roots that
281 // are always selected as tree roots. Roots with forward successors correspond
282 // to CFG nodes within infinite loops.
283 static bool HasForwardSuccessors(const NodePtr N) {
284 assert(N && "N must be a valid node");
285 using TraitsTy = GraphTraits;
286 return TraitsTy::child_begin(N) != TraitsTy::child_end(N);
287 }
288
289 static NodePtr GetEntryNode(const DomTreeT &DT) {
290 assert(DT.Parent && "Parent not set");
291 return GraphTraits::getEntryNode(DT.Parent);
292 }
293
294 // Finds all roots without relaying on the set of roots already stored in the
295 // tree.
296 // We define roots to be some non-redundant set of the CFG nodes
297 static RootsT FindRoots(const DomTreeT &DT) {
298 assert(DT.Parent && "Parent pointer is not set");
299 RootsT Roots;
300
301 // For dominators, function entry CFG node is always a tree root node.
302 if (!IsPostDom) {
303 Roots.push_back(GetEntryNode(DT));
304 return Roots;
305 }
306
307 SemiNCAInfo SNCA;
308
309 // PostDominatorTree always has a virtual root.
310 SNCA.addVirtualRoot();
311 unsigned Num = 1;
312
313 DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
314
315 // Step #1: Find all the trivial roots that are going to will definitely
316 // remain tree roots.
317 unsigned Total = 0;
318 for (const NodePtr N : nodes(DT.Parent)) {
319 ++Total;
320 // If it has no *successors*, it is definitely a root.
321 if (!HasForwardSuccessors(N)) {
322 Roots.push_back(N);
323 // Run DFS not to walk this part of CFG later.
324 Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
325 DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
326 << "\n");
327 DEBUG(dbgs() << "Last visited node: "
328 << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
329 }
330 }
331
332 DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
333
334 // Step #2: Find all non-trivial root candidates. Those are CFG nodes that
335 // are reverse-unreachable were not visited by previous DFS walks (i.e. CFG
336 // nodes in infinite loops).
337 bool HasNonTrivialRoots = false;
338 // Accounting for the virtual exit, see if we had any reverse-unreachable
339 // nodes.
340 if (Total + 1 != Num) {
341 HasNonTrivialRoots = true;
342 // Make another DFS pass over all other nodes to find the
343 // reverse-unreachable blocks, and find the furthest paths we'll be able
344 // to make.
345 // Note that this looks N^2, but it's really 2N worst case, if every node
346 // is unreachable. This is because we are still going to only visit each
347 // unreachable node once, we may just visit it in two directions,
348 // depending on how lucky we get.
349 SmallPtrSet ConnectToExitBlock;
350 for (const NodePtr I : nodes(DT.Parent)) {
351 if (SNCA.NodeToInfo.count(I) == 0) {
352 DEBUG(dbgs() << "\t\t\tVisiting node " << BlockNamePrinter(I)
353 << "\n");
354 // Find the furthest away we can get by following successors, then
355 // follow them in reverse. This gives us some reasonable answer about
356 // the post-dom tree inside any infinite loop. In particular, it
357 // guarantees we get to the farthest away point along *some*
358 // path. This also matches the GCC's behavior.
359 // If we really wanted a totally complete picture of dominance inside
360 // this infinite loop, we could do it with SCC-like algorithms to find
361 // the lowest and highest points in the infinite loop. In theory, it
362 // would be nice to give the canonical backedge for the loop, but it's
363 // expensive and does not always lead to a minimal set of roots.
364 DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
365
366 const unsigned NewNum = SNCA.runDFS(I, Num, AlwaysDescend, Num);
367 const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
368 DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
369 << "(non-trivial root): "
370 << BlockNamePrinter(FurthestAway) << "\n");
371 ConnectToExitBlock.insert(FurthestAway);
372 Roots.push_back(FurthestAway);
373 DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
374 << NewNum << "\n\t\t\tRemoving DFS info\n");
375 for (unsigned i = NewNum; i > Num; --i) {
376 const NodePtr N = SNCA.NumToNode[i];
377 DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
378 << BlockNamePrinter(N) << "\n");
379 SNCA.NodeToInfo.erase(N);
380 SNCA.NumToNode.pop_back();
381 }
382 const unsigned PrevNum = Num;
383 DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
384 Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
385 for (unsigned i = PrevNum + 1; i <= Num; ++i)
386 DEBUG(dbgs() << "\t\t\t\tfound node "
387 << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
388 }
389 }
390 }
391
392 DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
393 DEBUG(dbgs() << "Discovered CFG nodes:\n");
394 DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
395 << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
396
397 assert((Total + 1 == Num) && "Everything should have been visited");
398
399 // Step #3: If we found some non-trivial roots, make them non-redundant.
400 if (HasNonTrivialRoots) RemoveRedundantRoots(DT, Roots);
401
402 DEBUG(dbgs() << "Found roots: ");
403 DEBUG(for (auto *Root : Roots) dbgs() << BlockNamePrinter(Root) << " ");
404 DEBUG(dbgs() << "\n");
405
406 return Roots;
407 }
408
409 // This function only makes sense for postdominators.
410 // We define roots to be some set of CFG nodes where (reverse) DFS walks have
411 // to start in order to visit all the CFG nodes (including the
412 // reverse-unreachable ones).
413 // When the search for non-trivial roots is done it may happen that some of
414 // the non-trivial roots are reverse-reachable from other non-trivial roots,
415 // which makes them redundant. This function removes them from the set of
416 // input roots.
417 static void RemoveRedundantRoots(const DomTreeT &DT, RootsT &Roots) {
418 assert(IsPostDom && "This function is for postdominators only");
419 DEBUG(dbgs() << "Removing redundant roots\n");
420
421 SemiNCAInfo SNCA;
422
423 for (unsigned i = 0; i < Roots.size(); ++i) {
424 auto &Root = Roots[i];
425 // Trivial roots are always non-redundant.
426 if (!HasForwardSuccessors(Root)) continue;
427 DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
428 << " remains a root\n");
429 SNCA.clear();
430 // Do a forward walk looking for the other roots.
431 const unsigned Num = SNCA.runDFS(Root, 0, AlwaysDescend, 0);
432 // Skip the start node and begin from the second one (note that DFS uses
433 // 1-based indexing).
434 for (unsigned x = 2; x <= Num; ++x) {
435 const NodePtr N = SNCA.NumToNode[x];
436 // If we wound another root in a (forward) DFS walk, remove the current
437 // root from the set of roots, as it is reverse-reachable from the other
438 // one.
439 if (llvm::find(Roots, N) != Roots.end()) {
440 DEBUG(dbgs() << "\tForward DFS walk found another root "
441 << BlockNamePrinter(N) << "\n\tRemoving root "
442 << BlockNamePrinter(Root) << "\n");
443 std::swap(Root, Roots.back());
444 Roots.pop_back();
445
446 // Root at the back takes the current root's place.
447 // Start the next loop iteration with the same index.
448 --i;
449 break;
450 }
451 }
452 }
453 }
454
258455 template
259 unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
260 unsigned Num = 0;
261
262 // If the DT is a PostDomTree, always add a virtual root.
263 if (IsPostDom) {
264 auto &BBInfo = NodeToInfo[nullptr];
265 BBInfo.DFSNum = BBInfo.Semi = ++Num;
266 BBInfo.Label = nullptr;
267
268 NumToNode.push_back(nullptr); // NumToNode[n] = V;
269 }
270
271 const unsigned InitialNum = Num;
272 for (auto *Root : DT.Roots) Num = runDFS(Root, Num, DC, InitialNum);
273
274 return Num;
275 }
276
277 static void FindAndAddRoots(DomTreeT &DT) {
278 assert(DT.Parent && "Parent pointer is not set");
279 using TraitsTy = GraphTraits;
280
456 void doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
281457 if (!IsPostDom) {
282 // Dominators have a single root that is the function's entry.
283 NodeT *entry = TraitsTy::getEntryNode(DT.Parent);
284 DT.addRoot(entry);
285 } else {
286 // Initialize the roots list for PostDominators.
287 for (auto *Node : nodes(DT.Parent))
288 if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node))
289 DT.addRoot(Node);
290 }
458 assert(DT.Roots.size() == 1 && "Dominators should have a singe root");
459 runDFS(DT.Roots[0], 0, DC, 0);
460 return;
461 }
462
463 addVirtualRoot();
464 unsigned Num = 1;
465 for (const NodePtr Root : DT.Roots) Num = runDFS(Root, Num, DC, 0);
291466 }
292467
293468 void calculateFromScratch(DomTreeT &DT) {
294469 // Step #0: Number blocks in depth-first order and initialize variables used
295470 // in later stages of the algorithm.
296 FindAndAddRoots(DT);
471 DT.Roots = FindRoots(DT);
297472 doFullDFSWalk(DT, AlwaysDescend);
298473
299474 runSemiNCA(DT);
325500
326501 NodePtr ImmDom = getIDom(W);
327502
328 // Get or calculate the node for the immediate dominator
503 // Get or calculate the node for the immediate dominator.
329504 TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT);
330505
331506 // Add a new tree node for this BasicBlock, and link it as a child of
332 // IDomNode
507 // IDomNode.
333508 DT.DomTreeNodes[W] = IDomNode->addChild(
334509 llvm::make_unique>(W, IDomNode));
335510 }
366541 };
367542
368543 static void InsertEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
369 assert(From && To && "Cannot connect nullptrs");
544 assert((From || IsPostDom) &&
545 "From has to be a valid CFG node or a virtual root");
546 assert(To && "Cannot be a nullptr");
370547 DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
371548 << BlockNamePrinter(To) << "\n");
372 const TreeNodePtr FromTN = DT.getNode(From);
373
374 // Ignore edges from unreachable nodes.
375 if (!FromTN) return;
549 TreeNodePtr FromTN = DT.getNode(From);
550
551 if (!FromTN) {
552 // Ignore edges from unreachable nodes for (forward) dominators.
553 if (!IsPostDom) return;
554
555 // The unreachable node becomes a new root -- a tree node for it.
556 TreeNodePtr VirtualRoot = DT.getNode(nullptr);
557 FromTN =
558 (DT.DomTreeNodes[From] = VirtualRoot->addChild(
559 llvm::make_unique>(From, VirtualRoot)))
560 .get();
561 DT.Roots.push_back(From);
562 }
376563
377564 DT.DFSInfoValid = false;
378565
383570 InsertReachable(DT, FromTN, ToTN);
384571 }
385572
573 // Determines if some existing root becomes reverse-reachable after the
574 // insertion. Rebuilds the whole tree if that situation happens.
575 static bool UpdateRootsBeforeInsertion(DomTreeT &DT, const TreeNodePtr From,
576 const TreeNodePtr To) {
577 assert(IsPostDom && "This function is only for postdominators");
578 // Destination node is not attached to the virtual root, so it cannot be a
579 // root.
580 if (!DT.isVirtualRoot(To->getIDom())) return false;
581
582 auto RIt = llvm::find(DT.Roots, To->getBlock());
583 if (RIt == DT.Roots.end())
584 return false; // To is not a root, nothing to update.
585
586 DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
587 << " is no longer a root\n\t\tRebuilding the tree!!!\n");
588
589 DT.recalculate(*DT.Parent);
590 return true;
591 }
592
593 // Updates the set of roots after insertion or deletion. This ensures that
594 // roots are the same when after a series of updates and when the tree would
595 // be built from scratch.
596 static void UpdateRootsAfterUpdate(DomTreeT &DT) {
597 assert(IsPostDom && "This function is only for postdominators");
598
599 // The tree has only trivial roots -- nothing to update.
600 if (std::none_of(DT.Roots.begin(), DT.Roots.end(), HasForwardSuccessors))
601 return;
602
603 // Recalculate the set of roots.
604 DT.Roots = FindRoots(DT);
605 for (const NodePtr R : DT.Roots) {
606 const TreeNodePtr TN = DT.getNode(R);
607 // A CFG node was selected as a tree root, but the corresponding tree node
608 // is not connected to the virtual root. This is because the incremental
609 // algorithm does not really know or use the set of roots and can make a
610 // different (implicit) decision about which nodes within an infinite loop
611 // becomes a root.
612 if (DT.isVirtualRoot(TN->getIDom())) {
613 DEBUG(dbgs() << "Root " << BlockNamePrinter(R)
614 << " is not virtual root's child\n"
615 << "The entire tree needs to be rebuilt\n");
616 // It should be possible to rotate the subtree instead of recalculating
617 // the whole tree, but this situation happens extremely rarely in
618 // practice.
619 DT.recalculate(*DT.Parent);
620 return;
621 }
622 }
623 }
624
386625 // Handles insertion to a node already in the dominator tree.
387626 static void InsertReachable(DomTreeT &DT, const TreeNodePtr From,
388627 const TreeNodePtr To) {
389628 DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
390629 << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
630 if (IsPostDom && UpdateRootsBeforeInsertion(DT, From, To)) return;
631 // DT.findNCD expects both pointers to be valid. When From is a virtual
632 // root, then its CFG block pointer is a nullptr, so we have to 'compute'
633 // the NCD manually.
391634 const NodePtr NCDBlock =
392 DT.findNearestCommonDominator(From->getBlock(), To->getBlock());
635 (From->getBlock() && To->getBlock())
636 ? DT.findNearestCommonDominator(From->getBlock(), To->getBlock())
637 : nullptr;
393638 assert(NCDBlock || DT.isPostDominator());
394639 const TreeNodePtr NCD = DT.getNode(NCDBlock);
395640 assert(NCD);
482727 }
483728
484729 UpdateLevelsAfterInsertion(II);
730 if (IsPostDom) UpdateRootsAfterUpdate(DT);
485731 }
486732
487733 static void UpdateLevelsAfterInsertion(InsertionInfo &II) {
545791
546792 DEBUG(dbgs() << "After adding unreachable nodes\n");
547793 DEBUG(DT.print(dbgs()));
548 }
549
550 // Checks if the tree contains all reachable nodes in the input graph.
551 bool verifyReachability(const DomTreeT &DT) {
552 clear();
553 doFullDFSWalk(DT, AlwaysDescend);
554
555 for (auto &NodeToTN : DT.DomTreeNodes) {
556 const TreeNodePtr TN = NodeToTN.second.get();
557 const NodePtr BB = TN->getBlock();
558
559 // Virtual root has a corresponding virtual CFG node.
560 if (DT.isVirtualRoot(TN)) continue;
561
562 if (NodeToInfo.count(BB) == 0) {
563 errs() << "DomTree node " << BlockNamePrinter(BB)
564 << " not found by DFS walk!\n";
565 errs().flush();
566
567 return false;
568 }
569 }
570
571 for (const NodePtr N : NumToNode) {
572 if (N && !DT.getNode(N)) {
573 errs() << "CFG node " << BlockNamePrinter(N)
574 << " not found in the DomTree!\n";
575 errs().flush();
576
577 return false;
578 }
579 }
580
581 return true;
582794 }
583795
584796 static void DeleteEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) {
620832 DeleteReachable(DT, FromTN, ToTN);
621833 else
622834 DeleteUnreachable(DT, ToTN);
835
836 if (IsPostDom) UpdateRootsAfterUpdate(DT);
623837 }
624838
625839 // Handles deletions that leave destination nodes reachable.
691905 assert(ToTN);
692906 assert(ToTN->getBlock());
693907
908 if (IsPostDom) {
909 // Deletion makes a region reverse-unreachable and creates a new root.
910 // Simulate that by inserting an edge from the virtual root to ToTN and
911 // adding it as a new root.
912 DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
913 DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN) << "\n");
914 DT.Roots.push_back(ToTN->getBlock());
915 InsertReachable(DT, DT.getNode(nullptr), ToTN);
916 return;
917 }
918
694919 SmallVector AffectedQueue;
695920 const unsigned Level = ToTN->getLevel();
696921
7891014 //~~
7901015 //===--------------- DomTree correctness verification ---------------------===
7911016 //~~
1017
1018 // Check if the tree has correct roots. A DominatorTree always has a single
1019 // root which is the function's entry node. A PostDominatorTree can have
1020 // multiple roots - one for each node with no successors and for infinite
1021 // loops.
1022 bool verifyRoots(const DomTreeT &DT) {
1023 if (!DT.Parent && !DT.Roots.empty()) {
1024 errs() << "Tree has no parent but has roots!\n";
1025 errs().flush();
1026 return false;
1027 }
1028
1029 if (!IsPostDom) {
1030 if (DT.Roots.empty()) {
1031 errs() << "Tree doesn't have a root!\n";
1032 errs().flush();
1033 return false;
1034 }
1035
1036 if (DT.getRoot() != GetEntryNode(DT)) {
1037 errs() << "Tree's root is not its parent's entry node!\n";
1038 errs().flush();
1039 return false;
1040 }
1041 }
1042
1043 RootsT ComputedRoots = FindRoots(DT);
1044 if (DT.Roots.size() != ComputedRoots.size() ||
1045 !std::is_permutation(DT.Roots.begin(), DT.Roots.end(),
1046 ComputedRoots.begin())) {
1047 errs() << "Tree has different roots than freshly computed ones!\n";
1048 errs() << "\tPDT roots: ";
1049 for (const NodePtr N : DT.Roots) errs() << BlockNamePrinter(N) << ", ";
1050 errs() << "\n\tComputed roots: ";
1051 for (const NodePtr N : ComputedRoots)
1052 errs() << BlockNamePrinter(N) << ", ";
1053 errs() << "\n";
1054 errs().flush();
1055 return false;
1056 }
1057
1058 return true;
1059 }
1060
1061 // Checks if the tree contains all reachable nodes in the input graph.
1062 bool verifyReachability(const DomTreeT &DT) {
1063 clear();
1064 doFullDFSWalk(DT, AlwaysDescend);
1065
1066 for (auto &NodeToTN : DT.DomTreeNodes) {
1067 const TreeNodePtr TN = NodeToTN.second.get();
1068 const NodePtr BB = TN->getBlock();
1069
1070 // Virtual root has a corresponding virtual CFG node.
1071 if (DT.isVirtualRoot(TN)) continue;
1072
1073 if (NodeToInfo.count(BB) == 0) {
1074 errs() << "DomTree node " << BlockNamePrinter(BB)
1075 << " not found by DFS walk!\n";
1076 errs().flush();
1077
1078 return false;
1079 }
1080 }
1081
1082 for (const NodePtr N : NumToNode) {
1083 if (N && !DT.getNode(N)) {
1084 errs() << "CFG node " << BlockNamePrinter(N)
1085 << " not found in the DomTree!\n";
1086 errs().flush();
1087
1088 return false;
1089 }
1090 }
1091
1092 return true;
1093 }
7921094
7931095 // Check if for every parent with a level L in the tree all of its children
7941096 // have level L + 1.
9041206 const NodePtr BB = TN->getBlock();
9051207 if (!BB || TN->getChildren().empty()) continue;
9061208
1209 DEBUG(dbgs() << "Verifying parent property of node "
1210 << BlockNamePrinter(TN) << "\n");
9071211 clear();
9081212 doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
9091213 return From != BB && To != BB;
9841288 template
9851289 bool Verify(const DomTreeT &DT) {
9861290 SemiNCAInfo SNCA;
987 return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&
988 SNCA.verifyNCD(DT) && SNCA.verifyParentProperty(DT) &&
989 SNCA.verifySiblingProperty(DT);
1291 return SNCA.verifyRoots(DT) && SNCA.verifyReachability(DT) &&
1292 SNCA.VerifyLevels(DT) && SNCA.verifyNCD(DT) &&
1293 SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT);
9901294 }
9911295
9921296 } // namespace DomTreeBuilder
252252 }
253253 }
254254
255 // Mark blocks live if there is no path from the block to the
256 // return of the function or a successor for which this is true.
257 // This protects IDFCalculator which cannot handle such blocks.
258 for (auto &BBInfoPair : BlockInfo) {
259 auto &BBInfo = BBInfoPair.second;
260 if (BBInfo.terminatorIsLive())
255 // Mark blocks live if there is no path from the block to a
256 // return of the function.
257 // We do this by seeing which of the postdomtree root children exit the
258 // program, and for all others, mark the subtree live.
259 for (auto &PDTChild : children(PDT.getRootNode())) {
260 auto *BB = PDTChild->getBlock();
261 auto &Info = BlockInfo[BB];
262 // Real function return
263 if (isa(Info.Terminator)) {
264 DEBUG(dbgs() << "post-dom root child is a return: " << BB->getName()
265 << '\n';);
261266 continue;
262 auto *BB = BBInfo.BB;
263 if (!PDT.getNode(BB)) {
264 DEBUG(dbgs() << "Not post-dominated by return: " << BB->getName()
265 << '\n';);
266 markLive(BBInfo.Terminator);
267 continue;
268 }
269 for (auto *Succ : successors(BB))
270 if (!PDT.getNode(Succ)) {
271 DEBUG(dbgs() << "Successor not post-dominated by return: "
272 << BB->getName() << '\n';);
273 markLive(BBInfo.Terminator);
274 break;
275 }
267 }
268
269 // This child is something else, like an infinite loop.
270 for (auto DFNode : depth_first(PDTChild))
271 markLive(BlockInfo[DFNode->getBlock()].Terminator);
276272 }
277273
278274 // Treat the entry block as always live
0 ; RUN: opt < %s -postdomtree -analyze | FileCheck %s
1 ; RUN: opt < %s -passes='print' 2>&1 | FileCheck %s
2
3 @a = external global i32, align 4
4
5 define void @fn1() {
6 entry:
7 store i32 5, i32* @a, align 4
8 %call = call i32 (...) @foo()
9 %tobool = icmp ne i32 %call, 0
10 br i1 %tobool, label %if.then, label %if.end
11
12 if.then: ; preds = %entry
13 br label %loop
14
15 loop: ; preds = %loop, %if.then
16 br label %loop
17
18 if.end: ; preds = %entry
19 store i32 6, i32* @a, align 4
20 ret void
21 }
22
23 declare i32 @foo(...)
24
25 ; CHECK: Inorder PostDominator Tree:
26 ; CHECK-NEXT: [1] <>
27 ; CHECK: [2] %loop
28 ; CHECK-NEXT: [3] %if.then
29 ; CHECK: Roots: %if.end %loop
0 ; RUN: opt < %s -postdomtree -analyze | FileCheck %s
1 ; RUN: opt < %s -passes='print' 2>&1 | FileCheck %s
2
3 @a = external global i32, align 4
4
5 define void @fn1() {
6 entry:
7 store i32 5, i32* @a, align 4
8 %call = call i32 (...) @foo()
9 %tobool = icmp ne i32 %call, 0
10 br i1 %tobool, label %if.then, label %if.end
11
12 if.then: ; preds = %entry
13 br label %loop
14
15 loop: ; preds = %loop, %if.then
16 %0 = load i32, i32* @a, align 4
17 call void @bar(i32 %0)
18 br label %loop
19
20 if.end: ; preds = %entry
21 store i32 6, i32* @a, align 4
22 ret void
23 }
24
25 declare i32 @foo(...)
26 declare void @bar(i32)
27
28
29 ; CHECK: Inorder PostDominator Tree:
30 ; CHECK-NEXT: [1] <>
31 ; CHECK: [2] %loop
32 ; CHECK-NEXT: [3] %if.then
33 ; CHECK: Roots: %if.end %loop
0 ; RUN: opt < %s -postdomtree -analyze | FileCheck %s
1 ; RUN: opt < %s -passes='print' 2>&1 | FileCheck %s
2
3 @a = external global i32, align 4
4
5 define void @fn1() {
6 entry:
7 store i32 5, i32* @a, align 4
8 %call = call i32 (...) @foo()
9 %tobool = icmp ne i32 %call, 0
10 br i1 %tobool, label %if.then, label %if.end
11
12 if.then: ; preds = %entry, %loop
13 br label %loop
14
15 loop: ; preds = %loop, %if.then
16 %0 = load i32, i32* @a, align 4
17 call void @bar(i32 %0)
18 br i1 true, label %loop, label %if.then
19
20 if.end: ; preds = %entry
21 store i32 6, i32* @a, align 4
22 ret void
23 }
24
25 declare i32 @foo(...)
26 declare void @bar(i32)
27
28
29 ; CHECK: Inorder PostDominator Tree:
30 ; CHECK-NEXT: [1] <>
31 ; CHECK: [2] %loop
32 ; CHECK-NEXT: [3] %if.then
33 ; CHECK: Roots: %if.end %loop
0 ; RUN: opt < %s -postdomtree -analyze | FileCheck %s
1 ; RUN: opt < %s -passes='print' 2>&1 | FileCheck %s
2
3 ; Function Attrs: nounwind ssp uwtable
4 define void @foo() {
5 br label %1
6
7 ;
8 br label %1
9 ; No predecessors!
10 ret void
11 }
12
13 ; CHECK: Inorder PostDominator Tree:
14 ; CHECK-NEXT: [1] <>
15 ; CHECK-NEXT: [2] %2
16 ; CHECK-NEXT: [2] %1
17 ; CHECK-NEXT: [3] %0
1111 bb35:
1212 ret void
1313 }
14 ; CHECK: [3] %entry
14
15 ;CHECK:Inorder PostDominator Tree:
16 ;CHECK-NEXT: [1] <>
17 ;CHECK-NEXT: [2] %bb35
18 ;CHECK-NEXT: [3] %bb35.loopexit3
19 ;CHECK-NEXT: [2] %entry
20 ;CHECK-NEXT: [2] %bb3.i
1515 bb35:
1616 ret void
1717 }
18 ; CHECK: [4] %entry
18 ; CHECK: Inorder PostDominator Tree:
19 ; CHECK-NEXT: [1] <>
20 ; CHECK-NEXT: [2] %bb35
21 ; CHECK-NEXT: [3] %bb35.loopexit3
22 ; CHECK-NEXT: [2] %a
23 ; CHECK-NEXT: [2] %entry
24 ; CHECK-NEXT: [2] %bb3.i
143143 bb35:
144144 ret void
145145 }
146 ; CHECK: [3] %entry
146 ; CHECK: Inorder PostDominator Tree:
147 ; CHECK-NEXT: [1] <>
148 ; CHECK-NEXT: [2] %bb35
149 ; CHECK-NEXT: [3] %bb
150 ; CHECK-NEXT: [3] %bb.i
151 ; CHECK-NEXT: [3] %_float32_unpack.exit
152 ; CHECK-NEXT: [3] %bb.i5
153 ; CHECK-NEXT: [3] %_float32_unpack.exit8
154 ; CHECK-NEXT: [3] %bb32.preheader
155 ; CHECK-NEXT: [3] %bb3
156 ; CHECK-NEXT: [3] %bb3.split.us
157 ; CHECK-NEXT: [3] %bb.i4.us
158 ; CHECK-NEXT: [3] %bb7.i.us
159 ; CHECK-NEXT: [3] %bb.i4.us.backedge
160 ; CHECK-NEXT: [3] %bb1.i.us
161 ; CHECK-NEXT: [3] %bb6.i.us
162 ; CHECK-NEXT: [3] %bb4.i.us
163 ; CHECK-NEXT: [3] %bb8.i.us
164 ; CHECK-NEXT: [3] %bb3.i.loopexit.us
165 ; CHECK-NEXT: [3] %bb.nph21
166 ; CHECK-NEXT: [3] %bb4
167 ; CHECK-NEXT: [3] %bb5
168 ; CHECK-NEXT: [3] %bb14.preheader
169 ; CHECK-NEXT: [3] %bb.nph18
170 ; CHECK-NEXT: [3] %bb8.us.preheader
171 ; CHECK-NEXT: [3] %bb8.preheader
172 ; CHECK-NEXT: [3] %bb8.us
173 ; CHECK-NEXT: [3] %bb8
174 ; CHECK-NEXT: [3] %bb15.loopexit
175 ; CHECK-NEXT: [3] %bb15.loopexit2
176 ; CHECK-NEXT: [3] %bb15
177 ; CHECK-NEXT: [3] %bb16
178 ; CHECK-NEXT: [3] %bb17.loopexit.split
179 ; CHECK-NEXT: [3] %bb.nph14
180 ; CHECK-NEXT: [3] %bb19
181 ; CHECK-NEXT: [3] %bb20
182 ; CHECK-NEXT: [3] %bb29.preheader
183 ; CHECK-NEXT: [3] %bb.nph
184 ; CHECK-NEXT: [3] %bb23.us.preheader
185 ; CHECK-NEXT: [3] %bb23.preheader
186 ; CHECK-NEXT: [3] %bb23.us
187 ; CHECK-NEXT: [3] %bb23
188 ; CHECK-NEXT: [3] %bb30.loopexit
189 ; CHECK-NEXT: [3] %bb30.loopexit1
190 ; CHECK-NEXT: [3] %bb30
191 ; CHECK-NEXT: [3] %bb31
192 ; CHECK-NEXT: [3] %bb35.loopexit
193 ; CHECK-NEXT: [3] %bb35.loopexit3
194 ; CHECK-NEXT: [2] %entry
195 ; CHECK-NEXT: [2] %bb3.i
196 ; CHECK-NEXT: Roots: %bb35 %bb3.i
2020 bb35:
2121 ret void
2222 }
23 ; CHECK: [4] %entry
23 ; CHECK: Inorder PostDominator Tree:
24 ; CHECK-NEXT: [1] <>
25 ; CHECK-NEXT: [2] %bb35
26 ; CHECK-NEXT: [3] %bb35.loopexit3
27 ; CHECK-NEXT: [2] %c
28 ; CHECK-NEXT: [3] %a
29 ; CHECK-NEXT: [3] %entry
30 ; CHECK-NEXT: [3] %b
31 ; CHECK-NEXT: [2] %bb3.i
1515 }
1616 ; CHECK-NOT: =>
1717 ; CHECK: [0] 0 =>
18 ; CHECK: [1] 1 => 4
19 ; STAT: 2 region - The # of regions
20 ; STAT: 1 region - The # of simple regions
18 ; STAT: 1 region - The # of regions
2525 }
2626 ; CHECK-NOT: =>
2727 ; CHECK: [0] 0 =>
28 ; CHECK: [1] 1 => 3
29 ; STAT: 2 region - The # of regions
30 ; STAT: 1 region - The # of simple regions
28 ; CHECK-NOT: [1]
29 ; STAT: 1 region - The # of regions
3130
32 ; BBIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,
33 ; BBIT: 1, 2, 5, 11, 6, 12,
31 ; BBIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,
3432
35 ; RNIT: 0, 1 => 3, 3, 4,
36 ; RNIT: 1, 2, 5, 11, 6, 12,
33 ; RNIT: 0, 1, 2, 5, 11, 6, 12, 3, 4,
3737 ret void
3838 }
3939 ; CHECK-NOT: =>
40 ; CHECK: [0] 0 =>
41 ; CHECK-NEXT: [1] 1 => 3
42 ; CHECK-NEXT: [1] 7 => 1
43 ; STAT: 3 region - The # of regions
44 ; STAT: 2 region - The # of simple regions
40 ; CHECK:[0] 0 =>
41 ; CHECK-NOT: [1]
42 ; STAT: 1 region - The # of regions
4543
4644 ; BBIT: 0, 7, 1, 2, 5, 11, 6, 12, 3, 4, 8, 9, 13, 10, 14,
47 ; BBIT: 7, 8, 9, 13, 10, 14,
48 ; BBIT: 1, 2, 5, 11, 6, 12,
4945
50 ; RNIT: 0, 7 => 1, 1 => 3, 3, 4,
51 ; RNIT: 7, 8, 9, 13, 10, 14,
52 ; RNIT: 1, 2, 5, 11, 6, 12,
46 ; RNIT: 0, 7, 1, 2, 5, 11, 6, 12, 3, 4, 8, 9, 13, 10, 14,
3737 }
3838 ; CHECK-NOT: =>
3939 ; CHECK: [0] 0 =>
40 ; CHECK-NEXT: [1] 7 => 3
41 ; STAT: 2 region - The # of regions
40 ; CHECK-NEXT: [1] 2 => 10
41 ; CHECK_NEXT: [2] 5 => 6
42 ; STAT: 3 region - The # of regions
4243 ; STAT: 1 region - The # of simple regions
4344
4445 ; BBIT: 0, 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12, 3, 4,
45 ; BBIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12,
46
47 ; RNIT: 0, 7 => 3, 3, 4,
48 ; RNIT: 7, 1, 2, 5, 11, 6, 10, 8, 9, 13, 14, 12,
46 ; BBIT: 2, 5, 11, 6, 12,
47 ; BBIT: 5, 11, 12,
48 ; RNIT: 0, 7, 1, 2 => 10, 10, 8, 9, 13, 14, 3, 4,
49 ; RNIT: 2, 5 => 6, 6,
50 ; RNIT: 5, 11, 12,
1818
1919 ; CHECK: Region tree:
2020 ; CHECK-NEXT: [0] 0 =>
21 ; CHECK-NEXT: [1] 7 => 3
2221 ; CHECK-NEXT: End region tree
23
2020
2121 ; CHECK: Region tree:
2222 ; CHECK-NEXT: [0] 0 =>
23 ; CHECK-NEXT: [1] 7 => 3
2423 ; CHECK-NEXT: End region tree
427427 }
428428
429429 ; si_mask_branch
430 ; s_cbranch_execz
431 ; s_branch
432430
433431 ; GCN-LABEL: {{^}}analyze_mask_branch:
434432 ; GCN: v_cmp_lt_f32_e32 vcc
435433 ; GCN-NEXT: s_and_saveexec_b64 [[MASK:s\[[0-9]+:[0-9]+\]]], vcc
436434 ; GCN-NEXT: ; mask branch [[RET:BB[0-9]+_[0-9]+]]
437 ; GCN-NEXT: s_cbranch_execz [[BRANCH_SKIP:BB[0-9]+_[0-9]+]]
438 ; GCN-NEXT: s_branch [[LOOP_BODY:BB[0-9]+_[0-9]+]]
439
440 ; GCN-NEXT: [[BRANCH_SKIP]]: ; %entry
441 ; GCN-NEXT: s_getpc_b64 vcc
442 ; GCN-NEXT: s_add_u32 vcc_lo, vcc_lo, [[RET]]-([[BRANCH_SKIP]]+4)
443 ; GCN-NEXT: s_addc_u32 vcc_hi, vcc_hi, 0
444 ; GCN-NEXT: s_setpc_b64 vcc
445
446 ; GCN-NEXT: [[LOOP_BODY]]: ; %loop_body
447 ; GCN: s_mov_b64 vcc, -1{{$}}
435
436 ; GCN-NEXT: [[LOOP_BODY:BB[0-9]+_[0-9]+]]: ; %loop_body
448437 ; GCN: ;;#ASMSTART
449438 ; GCN: v_nop_e64
450439 ; GCN: v_nop_e64
453442 ; GCN: v_nop_e64
454443 ; GCN: v_nop_e64
455444 ; GCN: ;;#ASMEND
456 ; GCN-NEXT: s_cbranch_vccz [[RET]]
457445
458446 ; GCN-NEXT: [[LONGBB:BB[0-9]+_[0-9]+]]: ; %loop_body
459447 ; GCN-NEXT: ; in Loop: Header=[[LOOP_BODY]] Depth=1
462450 ; GCN-NEXT: s_subb_u32 vcc_hi, vcc_hi, 0
463451 ; GCN-NEXT: s_setpc_b64 vcc
464452
465 ; GCN-NEXT: [[RET]]: ; %Flow
453 ; GCN-NEXT: [[RET]]: ; %ret
466454 ; GCN-NEXT: s_or_b64 exec, exec, [[MASK]]
467455 ; GCN: buffer_store_dword
468456 ; GCN-NEXT: s_endpgm
33 ; generated.
44 ; PR16393
55
6 ; We expect the spill to be generated in %if.end230 and the reloads in
7 ; %if.end249 and %for.body285.
6 ; We expect 4-byte spill and reload to be generated.
87
98 ; CHECK: set_stored_macroblock_parameters
10 ; CHECK: @ %if.end230
11 ; CHECK-NOT:@ %if.
12 ; CHECK-NOT:@ %for.
13 ; CHECK: str r{{.*}}, [sp, [[SLOT:#[0-9]+]]] @ 4-byte Spill
14 ; CHECK: @ %if.end249
15 ; CHECK-NOT:@ %if.
16 ; CHECK-NOT:@ %for.
17 ; CHECK: ldr r{{.*}}, [sp, [[SLOT]]] @ 4-byte Reload
18 ; CHECK: @ %for.body285
19 ; CHECK-NOT:@ %if.
20 ; CHECK-NOT:@ %for.
21 ; CHECK: ldr r{{.*}}, [sp, [[SLOT]]] @ 4-byte Reload
9 ; CHECK: str r{{.*}}, [sp, {{#[0-9]+}}] @ 4-byte Spill
10 ; CHECK: ldr r{{.*}}, [lr, {{#[0-9]+}}] @ 4-byte Reload
2211
2312 target triple = "armv7l-unknown-linux-gnueabihf"
2413
0 ; RUN: llc < %s -mtriple=thumbv8 -arm-atomic-cfg-tidy=0 | FileCheck %s
11 ; RUN: llc < %s -mtriple=thumbv7 -arm-atomic-cfg-tidy=0 -arm-restrict-it | FileCheck %s
2 ; CHECK: it ne
2 ; CHECK: it ne
33 ; CHECK-NEXT: cmpne
44 ; CHECK-NEXT: bne [[JUMPTARGET:.LBB[0-9]+_[0-9]+]]
55 ; CHECK: cbz
88 ; CHECK-NEXT: b
99 ; CHECK: [[JUMPTARGET]]:{{.*}}%if.else173
1010 ; CHECK-NEXT: mov.w
11 ; CHECK-NEXT: pop
12 ; CHECK-NEXT: %if.else145
11 ; CHECK-NEXT: bx lr
12 ; CHECK: %if.else145
1313 ; CHECK-NEXT: mov.w
14 ; CHECK: pop.w
1415
1516 %struct.hc = type { i32, i32, i32, i32 }
1617
22 ; CHECK-LABEL: @invert_branch_on_arg_inf_loop(
33 ; CHECK: entry:
44 ; CHECK: %arg.inv = xor i1 %arg, true
5 ; CHECK: phi i1 [ false, %Flow1 ], [ %arg.inv, %entry ]
65 define void @invert_branch_on_arg_inf_loop(i32 addrspace(1)* %out, i1 %arg) {
76 entry:
8 br i1 %arg, label %for.end, label %for.body
7 br i1 %arg, label %for.end, label %sesestart
8 sesestart:
9 br label %for.body
910
1011 for.body: ; preds = %entry, %for.body
1112 store i32 999, i32 addrspace(1)* %out, align 4
12 br label %for.body
13 br i1 %arg, label %for.body, label %seseend
14 seseend:
15 ret void
1316
1417 for.end: ; preds = %Flow
1518 ret void
0 ; XFAIL: *
1
2 ; This test used to generate a region that caused it to delete the entry block,
3 ; but it does not anymore after the changes to handling of infinite loops in the
4 ; PostDominatorTree.
5 ; TODO: This should be either replaced with another IR or deleted completely.
6
7 ; RUN: opt -S -o - -structurizecfg -verify-dom-info < %s | FileCheck %s
18
29 ; CHECK-LABEL: @no_branch_to_entry_undef(
326326 }
327327
328328 // Verify that the PDT is correctly updated in case an edge removal results
329 // in a new unreachable CFG node.
329 // in a new unreachable CFG node. Also make sure that the updated PDT is the
330 // same as a freshly recalculated one.
330331 //
331332 // For the following input code and initial PDT:
332333 //
347348 // CFG' PDT-updated
348349 //
349350 // A Exit
350 // | |
351 // B D
351 // | / | \
352 // B C B D
352353 // | \ |
353 // v \ B
354 // / D \
355 // C \ A
356 // | v
354 // v \ A
355 // / D
356 // C \
357 // | \
357358 // unreachable Exit
358359 //
359 // WARNING: PDT-updated is inconsistent with PDT-recalculated, which is
360 // constructed from CFG' when recalculating the PDT from scratch.
361 //
362 // PDT-recalculated
363 //
364 // Exit
365 // / | \
366 // C B D
367 // |
368 // A
369 //
370 // TODO: document the wanted behavior after resolving this inconsistency.
360 // Both the blocks that end with ret and with unreachable become trivial
361 // PostDomTree roots, as they have no successors.
362 //
371363 TEST(DominatorTree, DeletingEdgesIntroducesUnreachables) {
372364 StringRef ModuleString =
373365 "define void @f() {\n"
394386 BasicBlock *C = &*FI++;
395387 BasicBlock *D = &*FI++;
396388
397 assert(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
389 ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
390 EXPECT_TRUE(DT->verify());
391 EXPECT_TRUE(PDT->verify());
398392
399393 C->getTerminator()->eraseFromParent();
400394 new UnreachableInst(C->getContext(), C);
402396 DT->deleteEdge(C, B);
403397 PDT->deleteEdge(C, B);
404398
405 EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
406 EXPECT_EQ(PDT->getNode(C), nullptr);
407
408 PDT->recalculate(F);
399 EXPECT_TRUE(DT->verify());
400 EXPECT_TRUE(PDT->verify());
409401
410402 EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
411403 EXPECT_NE(PDT->getNode(C), nullptr);
404
405 DominatorTree NDT(F);
406 EXPECT_EQ(DT->compare(NDT), 0);
407
408 PostDomTree NPDT(F);
409 EXPECT_EQ(PDT->compare(NPDT), 0);
412410 });
413411 }
414412
415413 // Verify that the PDT is correctly updated in case an edge removal results
416 // in an infinite loop.
414 // in an infinite loop. Also make sure that the updated PDT is the
415 // same as a freshly recalculated one.
417416 //
418417 // Test case:
419418 //
433432 // After deleting the edge C->B, C is part of an infinite reverse-unreachable
434433 // loop:
435434 //
436 // CFG' PDT'
435 // CFG' PDT'
437436 //
438437 // A Exit
439 // | |
440 // B D
438 // | / | \
439 // B C B D
441440 // | \ |
442 // v \ B
443 // / D \
444 // C \ A
441 // v \ A
442 // / D
443 // C \
445444 // / \ v
446445 // ^ v Exit
447446 // \_/
448447 //
449 // In PDT, D post-dominates B. We verify that this post-dominance
450 // relation is preserved _after_ deleting the edge C->B from CFG.
451 //
452 // As C now becomes reverse-unreachable, it is not anymore part of the
453 // PDT. We also verify this property.
454 //
455 // TODO: Can we change the PDT definition such that C remains part of the
456 // CFG?
448 // As C now becomes reverse-unreachable, it forms a new non-trivial root and
449 // gets connected to the virtual exit.
450 // D does not postdominate B anymore, because there are two forward paths from
451 // B to the virtual exit:
452 // - B -> C -> VirtualExit
453 // - B -> D -> VirtualExit.
454 //
457455 TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) {
458456 StringRef ModuleString =
459457 "define void @f() {\n"
482480 BasicBlock *C = &*FI++;
483481 BasicBlock *D = &*FI++;
484482
485 assert(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
483 ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
484 EXPECT_TRUE(DT->verify());
485 EXPECT_TRUE(PDT->verify());
486486
487487 auto SwitchC = cast(C->getTerminator());
488488 SwitchC->removeCase(SwitchC->case_begin());
489489 DT->deleteEdge(C, B);
490 EXPECT_TRUE(DT->verify());
490491 PDT->deleteEdge(C, B);
491
492 EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
493 EXPECT_EQ(PDT->getNode(C), nullptr);
494
495 PDT->recalculate(F);
496
497 EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
498 EXPECT_EQ(PDT->getNode(C), nullptr);
492 EXPECT_TRUE(PDT->verify());
493
494 EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
495 EXPECT_NE(PDT->getNode(C), nullptr);
496
497 DominatorTree NDT(F);
498 EXPECT_EQ(DT->compare(NDT), 0);
499
500 PostDomTree NPDT(F);
501 EXPECT_EQ(PDT->compare(NPDT), 0);
499502 });
500503 }
501504
508511 //
509512 // A Exit
510513 // | / | \
511 // B-- C B D
512 // | \ |
513 // v \ A
514 // B-- C2 B D
515 // | \ / |
516 // v \ C A
514517 // / D
515518 // C--C2 \
516519 // / \ \ v
520523 // After deleting the edge C->E, C is part of an infinite reverse-unreachable
521524 // loop:
522525 //
523 // CFG' PDT'
526 // CFG' PDT'
524527 //
525528 // A Exit
526 // | |
527 // B D
529 // | / | \
530 // B C B D
528531 // | \ |
529 // v \ B
530 // / D \
531 // C \ A
532 // v \ A
533 // / D
534 // C \
532535 // / \ v
533536 // ^ v Exit
534537 // \_/
535538 //
536 // In PDT, D does not post-dominate B. After the edge C->E is removed, a new
537 // post-dominance relation is introduced.
538 //
539 // As C now becomes reverse-unreachable, it is not anymore part of the
540 // PDT. We also verify this property.
541 //
542 // TODO: Can we change the PDT definition such that C remains part of the
543 // CFG, at best without loosing the dominance relation D postdom B.
539 // In PDT, D does not post-dominate B. After the edge C -> C2 is removed,
540 // C becomes a new nontrivial PDT root.
541 //
544542 TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop2) {
545543 StringRef ModuleString =
546544 "define void @f() {\n"
572570 BasicBlock *C2 = &*FI++;
573571 BasicBlock *D = &*FI++;
574572
573 EXPECT_TRUE(DT->verify());
574 EXPECT_TRUE(PDT->verify());
575
575576 auto SwitchC = cast(C->getTerminator());
576577 SwitchC->removeCase(SwitchC->case_begin());
577578 DT->deleteEdge(C, C2);
578579 PDT->deleteEdge(C, C2);
579 C2->eraseFromParent();
580 C2->removeFromParent();
580581
581582 EXPECT_EQ(DT->getNode(C2), nullptr);
582583 PDT->eraseNode(C2);
583
584 EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
585 EXPECT_EQ(PDT->getNode(C), nullptr);
586 EXPECT_EQ(PDT->getNode(C2), nullptr);
587
588 PDT->recalculate(F);
589
590 EXPECT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
591 EXPECT_EQ(PDT->getNode(C), nullptr);
592 EXPECT_EQ(PDT->getNode(C2), nullptr);
584 delete C2;
585
586 EXPECT_TRUE(DT->verify());
587 EXPECT_TRUE(PDT->verify());
588
589 EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B)));
590 EXPECT_NE(PDT->getNode(C), nullptr);
591
592 DominatorTree NDT(F);
593 EXPECT_EQ(DT->compare(NDT), 0);
594
595 PostDomTree NPDT(F);
596 EXPECT_EQ(PDT->compare(NPDT), 0);
593597 });
594598 }
595599
683687 PDT.insertEdge(From, To);
684688 EXPECT_TRUE(PDT.verify());
685689 }
690 }
691
692 TEST(DominatorTree, InsertFromUnreachable) {
693 CFGHolder Holder;
694 std::vector Arcs = {{"1", "2"}, {"2", "3"}, {"3", "4"}};
695
696 std::vector Updates = {{Insert, {"3", "5"}}};
697 CFGBuilder B(Holder.F, Arcs, Updates);
698 PostDomTree PDT(*Holder.F);
699 EXPECT_TRUE(PDT.verify());
700
701 Optional LastUpdate = B.applyUpdate();
702 EXPECT_TRUE(LastUpdate);
703
704 EXPECT_EQ(LastUpdate->Action, Insert);
705 BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From);
706 BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To);
707 PDT.insertEdge(From, To);
708 EXPECT_TRUE(PDT.verify());
709 EXPECT_TRUE(PDT.getRoots().size() == 2);
710 EXPECT_NE(PDT.getNode(B.getOrAddBlock("5")), nullptr);
686711 }
687712
688713 TEST(DominatorTree, InsertMixed) {