llvm.org GIT mirror llvm / 7083930
[Dominators] Add DFS number verification Summary: This patch teaches the DominatorTree verifier to check DFS In/Out numbers which are used to answer dominance queries. DFS number verification is done in O(nlogn), so it shouldn't add much overhead on top of the O(n^3) sibling property verification. This check should detect errors like the one spotted in PR34466 and related bug reports. The patch also cleans up the DFS calculation a bit, as all constructed trees should have a single root now. I see 2 new test failures when running check-all after this change: ``` Failing Tests (2): Polly :: Isl/CodeGen/OpenMP/reference-argument-from-non-affine-region.ll Polly :: Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll ``` which seem to happen just after `Create LLVM-IR from SCoPs` -- I XFAILed them in r314800. Reviewers: dberlin, grosser, davide, zhendongsu, bollu Reviewed By: dberlin Subscribers: nandini12396, bollu, Meinersbur, brzycki, llvm-commits Differential Revision: https://reviews.llvm.org/D38331 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314801 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 2 years ago
2 changed file(s) with 106 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
701701 return;
702702 }
703703
704 unsigned DFSNum = 0;
705
706704 SmallVector *,
707705 typename DomTreeNodeBase::const_iterator>,
708706 32> WorkStack;
709707
710708 const DomTreeNodeBase *ThisRoot = getRootNode();
711
709 assert((!Parent || ThisRoot) && "Empty constructed DomTree");
712710 if (!ThisRoot)
713711 return;
714712
715 // Even in the case of multiple exits that form the post dominator root
716 // nodes, do not iterate over all exits, but start from the virtual root
717 // node. Otherwise bbs, that are not post dominated by any exit but by the
718 // virtual root node, will never be assigned a DFS number.
719 WorkStack.push_back(std::make_pair(ThisRoot, ThisRoot->begin()));
713 // Both dominators and postdominators have a single root node. In the case
714 // case of PostDominatorTree, this node is a virtual root.
715 WorkStack.push_back({ThisRoot, ThisRoot->begin()});
716
717 unsigned DFSNum = 0;
720718 ThisRoot->DFSNumIn = DFSNum++;
721719
722720 while (!WorkStack.empty()) {
723721 const DomTreeNodeBase *Node = WorkStack.back().first;
724 typename DomTreeNodeBase::const_iterator ChildIt =
725 WorkStack.back().second;
722 const auto ChildIt = WorkStack.back().second;
726723
727724 // If we visited all of the children of this node, "recurse" back up the
728725 // stack setting the DFOutNum.
734731 const DomTreeNodeBase *Child = *ChildIt;
735732 ++WorkStack.back().second;
736733
737 WorkStack.push_back(std::make_pair(Child, Child->begin()));
734 WorkStack.push_back({Child, Child->begin()});
738735 Child->DFSNumIn = DFSNum++;
739736 }
740737 }
13481348 return true;
13491349 }
13501350
1351 // Check if the computed DFS numbers are correct. Note that DFS info may not
1352 // be valid, and when that is the case, we don't verify the numbers.
1353 static bool VerifyDFSNumbers(const DomTreeT &DT) {
1354 if (!DT.DFSInfoValid || !DT.Parent)
1355 return true;
1356
1357 const NodePtr RootBB = IsPostDom ? nullptr : DT.getRoots()[0];
1358 const TreeNodePtr Root = DT.getNode(RootBB);
1359
1360 auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) {
1361 errs() << BlockNamePrinter(TN) << " {" << TN->getDFSNumIn() << ", "
1362 << TN->getDFSNumOut() << '}';
1363 };
1364
1365 // Verify the root's DFS In number. Although DFS numbering would also work
1366 // if we started from some other value, we assume 0-based numbering.
1367 if (Root->getDFSNumIn() != 0) {
1368 errs() << "DFSIn number for the tree root is not:\n\t";
1369 PrintNodeAndDFSNums(Root);
1370 errs() << '\n';
1371 errs().flush();
1372 return false;
1373 }
1374
1375 // For each tree node verify if children's DFS numbers cover their parent's
1376 // DFS numbers with no gaps.
1377 for (const auto &NodeToTN : DT.DomTreeNodes) {
1378 const TreeNodePtr Node = NodeToTN.second.get();
1379
1380 // Handle tree leaves.
1381 if (Node->getChildren().empty()) {
1382 if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) {
1383 errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t";
1384 PrintNodeAndDFSNums(Node);
1385 errs() << '\n';
1386 errs().flush();
1387 return false;
1388 }
1389
1390 continue;
1391 }
1392
1393 // Make a copy and sort it such that it is possible to check if there are
1394 // no gaps between DFS numbers of adjacent children.
1395 SmallVector Children(Node->begin(), Node->end());
1396 std::sort(Children.begin(), Children.end(),
1397 [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
1398 return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
1399 });
1400
1401 auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
1402 const TreeNodePtr FirstCh, const TreeNodePtr SecondCh = nullptr) {
1403 assert(FirstCh);
1404
1405 errs() << "Incorrect DFS numbers for:\n\tParent ";
1406 PrintNodeAndDFSNums(Node);
1407
1408 errs() << "\n\tChild ";
1409 PrintNodeAndDFSNums(FirstCh);
1410
1411 if (SecondCh) {
1412 errs() << "\n\tSecond child ";
1413 PrintNodeAndDFSNums(SecondCh);
1414 }
1415
1416 errs() << "\nAll children: ";
1417 for (const TreeNodePtr Ch : Children) {
1418 PrintNodeAndDFSNums(Ch);
1419 errs() << ", ";
1420 }
1421
1422 errs() << '\n';
1423 errs().flush();
1424 };
1425
1426 if (Children.front()->getDFSNumIn() != Node->getDFSNumIn() + 1) {
1427 PrintChildrenError(Children.front());
1428 return false;
1429 }
1430
1431 if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
1432 PrintChildrenError(Children.back());
1433 return false;
1434 }
1435
1436 for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
1437 if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
1438 PrintChildrenError(Children[i], Children[i + 1]);
1439 return false;
1440 }
1441 }
1442 }
1443
1444 return true;
1445 }
1446
13511447 // Checks if for every edge From -> To in the graph
13521448 // NCD(From, To) == IDom(To) or To.
13531449 bool verifyNCD(const DomTreeT &DT) {
15201616 SemiNCAInfo SNCA(nullptr);
15211617 return SNCA.verifyRoots(DT) && SNCA.verifyReachability(DT) &&
15221618 SNCA.VerifyLevels(DT) && SNCA.verifyNCD(DT) &&
1523 SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT);
1619 SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT) &&
1620 SNCA.VerifyDFSNumbers(DT);
15241621 }
15251622
15261623 } // namespace DomTreeBuilder