Skip to content

Commit ce2e36e

Browse files
committed
[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 llvm-svn: 314801
1 parent 3c3bf74 commit ce2e36e

File tree

2 files changed

+106
-12
lines changed

2 files changed

+106
-12
lines changed

llvm/include/llvm/Support/GenericDomTree.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -702,28 +702,25 @@ class DominatorTreeBase {
702702
return;
703703
}
704704

705-
unsigned DFSNum = 0;
706-
707705
SmallVector<std::pair<const DomTreeNodeBase<NodeT> *,
708706
typename DomTreeNodeBase<NodeT>::const_iterator>,
709707
32> WorkStack;
710708

711709
const DomTreeNodeBase<NodeT> *ThisRoot = getRootNode();
712-
710+
assert((!Parent || ThisRoot) && "Empty constructed DomTree");
713711
if (!ThisRoot)
714712
return;
715713

716-
// Even in the case of multiple exits that form the post dominator root
717-
// nodes, do not iterate over all exits, but start from the virtual root
718-
// node. Otherwise bbs, that are not post dominated by any exit but by the
719-
// virtual root node, will never be assigned a DFS number.
720-
WorkStack.push_back(std::make_pair(ThisRoot, ThisRoot->begin()));
714+
// Both dominators and postdominators have a single root node. In the case
715+
// case of PostDominatorTree, this node is a virtual root.
716+
WorkStack.push_back({ThisRoot, ThisRoot->begin()});
717+
718+
unsigned DFSNum = 0;
721719
ThisRoot->DFSNumIn = DFSNum++;
722720

723721
while (!WorkStack.empty()) {
724722
const DomTreeNodeBase<NodeT> *Node = WorkStack.back().first;
725-
typename DomTreeNodeBase<NodeT>::const_iterator ChildIt =
726-
WorkStack.back().second;
723+
const auto ChildIt = WorkStack.back().second;
727724

728725
// If we visited all of the children of this node, "recurse" back up the
729726
// stack setting the DFOutNum.
@@ -735,7 +732,7 @@ class DominatorTreeBase {
735732
const DomTreeNodeBase<NodeT> *Child = *ChildIt;
736733
++WorkStack.back().second;
737734

738-
WorkStack.push_back(std::make_pair(Child, Child->begin()));
735+
WorkStack.push_back({Child, Child->begin()});
739736
Child->DFSNumIn = DFSNum++;
740737
}
741738
}

llvm/include/llvm/Support/GenericDomTreeConstruction.h

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,102 @@ struct SemiNCAInfo {
13491349
return true;
13501350
}
13511351

1352+
// Check if the computed DFS numbers are correct. Note that DFS info may not
1353+
// be valid, and when that is the case, we don't verify the numbers.
1354+
static bool VerifyDFSNumbers(const DomTreeT &DT) {
1355+
if (!DT.DFSInfoValid || !DT.Parent)
1356+
return true;
1357+
1358+
const NodePtr RootBB = IsPostDom ? nullptr : DT.getRoots()[0];
1359+
const TreeNodePtr Root = DT.getNode(RootBB);
1360+
1361+
auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) {
1362+
errs() << BlockNamePrinter(TN) << " {" << TN->getDFSNumIn() << ", "
1363+
<< TN->getDFSNumOut() << '}';
1364+
};
1365+
1366+
// Verify the root's DFS In number. Although DFS numbering would also work
1367+
// if we started from some other value, we assume 0-based numbering.
1368+
if (Root->getDFSNumIn() != 0) {
1369+
errs() << "DFSIn number for the tree root is not:\n\t";
1370+
PrintNodeAndDFSNums(Root);
1371+
errs() << '\n';
1372+
errs().flush();
1373+
return false;
1374+
}
1375+
1376+
// For each tree node verify if children's DFS numbers cover their parent's
1377+
// DFS numbers with no gaps.
1378+
for (const auto &NodeToTN : DT.DomTreeNodes) {
1379+
const TreeNodePtr Node = NodeToTN.second.get();
1380+
1381+
// Handle tree leaves.
1382+
if (Node->getChildren().empty()) {
1383+
if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) {
1384+
errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t";
1385+
PrintNodeAndDFSNums(Node);
1386+
errs() << '\n';
1387+
errs().flush();
1388+
return false;
1389+
}
1390+
1391+
continue;
1392+
}
1393+
1394+
// Make a copy and sort it such that it is possible to check if there are
1395+
// no gaps between DFS numbers of adjacent children.
1396+
SmallVector<TreeNodePtr, 8> Children(Node->begin(), Node->end());
1397+
std::sort(Children.begin(), Children.end(),
1398+
[](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
1399+
return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
1400+
});
1401+
1402+
auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
1403+
const TreeNodePtr FirstCh, const TreeNodePtr SecondCh = nullptr) {
1404+
assert(FirstCh);
1405+
1406+
errs() << "Incorrect DFS numbers for:\n\tParent ";
1407+
PrintNodeAndDFSNums(Node);
1408+
1409+
errs() << "\n\tChild ";
1410+
PrintNodeAndDFSNums(FirstCh);
1411+
1412+
if (SecondCh) {
1413+
errs() << "\n\tSecond child ";
1414+
PrintNodeAndDFSNums(SecondCh);
1415+
}
1416+
1417+
errs() << "\nAll children: ";
1418+
for (const TreeNodePtr Ch : Children) {
1419+
PrintNodeAndDFSNums(Ch);
1420+
errs() << ", ";
1421+
}
1422+
1423+
errs() << '\n';
1424+
errs().flush();
1425+
};
1426+
1427+
if (Children.front()->getDFSNumIn() != Node->getDFSNumIn() + 1) {
1428+
PrintChildrenError(Children.front());
1429+
return false;
1430+
}
1431+
1432+
if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
1433+
PrintChildrenError(Children.back());
1434+
return false;
1435+
}
1436+
1437+
for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
1438+
if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
1439+
PrintChildrenError(Children[i], Children[i + 1]);
1440+
return false;
1441+
}
1442+
}
1443+
}
1444+
1445+
return true;
1446+
}
1447+
13521448
// Checks if for every edge From -> To in the graph
13531449
// NCD(From, To) == IDom(To) or To.
13541450
bool verifyNCD(const DomTreeT &DT) {
@@ -1521,7 +1617,8 @@ bool Verify(const DomTreeT &DT) {
15211617
SemiNCAInfo<DomTreeT> SNCA(nullptr);
15221618
return SNCA.verifyRoots(DT) && SNCA.verifyReachability(DT) &&
15231619
SNCA.VerifyLevels(DT) && SNCA.verifyNCD(DT) &&
1524-
SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT);
1620+
SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT) &&
1621+
SNCA.VerifyDFSNumbers(DT);
15251622
}
15261623

15271624
} // namespace DomTreeBuilder

0 commit comments

Comments
 (0)