llvm.org GIT mirror llvm / 1eb58b7
[Dominators] Add parent and sibling property verification (non-hacky) Summary: This patch adds an additional level of verification - it checks parent and sibling properties of a tree. By definition, every tree with these two properties is a dominator tree. It is possible to run those check by running llvm with `-verify-dom-info=1`. Bootstrapping clang and building the llvm test suite with this option enabled doesn't yield any errors. Reviewers: dberlin, sanjoy, chandlerc Reviewed By: dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34482 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306711 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 3 years ago
4 changed file(s) with 175 addition(s) and 20 deletion(s). Raw diff Collapse all Expand all
3535 extern template class DomTreeNodeBase;
3636 extern template class DominatorTreeBase;
3737
38 namespace DomTreeBuilder {
3839 extern template void Calculate(
3940 DominatorTreeBaseByGraphTraits> &DT, Function &F);
41
4042 extern template void Calculate>(
4143 DominatorTreeBaseByGraphTraits>> &DT,
4244 Function &F);
45
46 extern template bool Verify(
47 const DominatorTreeBaseByGraphTraits> &DT);
48
49 extern template bool Verify>(
50 const DominatorTreeBaseByGraphTraits>>
51 &DT);
52 } // namespace DomTreeBuilder
4353
4454 using DomTreeNode = DomTreeNodeBase;
4555
203203 namespace DomTreeBuilder {
204204 template
205205 struct SemiNCAInfo;
206 } // namespace DomTreeBuilder
207206
208207 // The calculate routine is provided in a separate header but referenced here.
209208 template
210209 void Calculate(DominatorTreeBaseByGraphTraits> &DT, FuncT &F);
210
211 // The verify function is provided in a separate header but referenced here.
212 template
213 bool Verify(const DominatorTreeBaseByGraphTraits> &DT);
214 } // namespace DomTreeBuilder
211215
212216 /// \brief Core dominator tree base class.
213217 ///
722726 NodeT *entry = TraitsTy::getEntryNode(&F);
723727 addRoot(entry);
724728
725 Calculate(*this, F);
729 DomTreeBuilder::Calculate(*this, F);
726730 } else {
727731 // Initialize the roots list
728732 for (auto *Node : nodes(&F))
729733 if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node))
730734 addRoot(Node);
731735
732 Calculate>(*this, F);
733 }
736 DomTreeBuilder::Calculate>(*this, F);
737 }
738 }
739
740 /// verify - check parent and sibling property
741 bool verify() const {
742 return this->isPostDominator()
743 ? DomTreeBuilder::Verify>(*this)
744 : DomTreeBuilder::Verify(*this);
734745 }
735746 };
736747
2929 #include "llvm/Support/GenericDomTree.h"
3030
3131 namespace llvm {
32
3332 namespace DomTreeBuilder {
33
3434 // Information record used by Semi-NCA during tree construction.
3535 template
3636 struct SemiNCAInfo {
4646 NodePtr IDom = nullptr;
4747 };
4848
49 DomTreeT &DT;
5049 std::vector NumToNode;
5150 DenseMap NodeToInfo;
5251
53 SemiNCAInfo(DomTreeT &DT) : DT(DT) {}
52 void clear() {
53 NumToNode.clear();
54 NodeToInfo.clear();
55 }
5456
5557 NodePtr getIDom(NodePtr BB) const {
5658 auto InfoIt = NodeToInfo.find(BB);
5961 return InfoIt->second.IDom;
6062 }
6163
62 TreeNodePtr getNodeForBlock(NodePtr BB) {
64 TreeNodePtr getNodeForBlock(NodePtr BB, DomTreeT &DT) {
6365 if (TreeNodePtr Node = DT.getNode(BB)) return Node;
6466
6567 // Haven't calculated this node yet? Get or calculate the node for the
6769 NodePtr IDom = getIDom(BB);
6870
6971 assert(IDom || DT.DomTreeNodes[nullptr]);
70 TreeNodePtr IDomNode = getNodeForBlock(IDom);
72 TreeNodePtr IDomNode = getNodeForBlock(IDom, DT);
7173
7274 // Add a new tree node for this NodeT, and link it as a child of
7375 // IDomNode
120122 return N;
121123 }
122124
123 unsigned runDFS(NodePtr V, unsigned N) {
125 unsigned runForwardDFS(NodePtr V, unsigned N) {
124126 auto DFStorage = getStorage();
125127
126128 for (auto I = df_ext_begin(V, DFStorage), E = df_ext_end(V, DFStorage);
177179 }
178180
179181 template
180 void runSemiNCA(unsigned NumBlocks) {
182 void runSemiNCA(DomTreeT &DT, unsigned NumBlocks) {
181183 unsigned N = 0;
182184 NumToNode.push_back(nullptr);
183185
197199 i != e; ++i)
198200 N = runReverseDFS(DT.Roots[i], N);
199201 } else {
200 N = runDFS(DT.Roots[0], N);
202 N = runForwardDFS(DT.Roots[0], N);
201203 }
202204
203205 // It might be that some blocks did not get a DFS number (e.g., blocks of
267269 assert(ImmDom || DT.DomTreeNodes[nullptr]);
268270
269271 // Get or calculate the node for the immediate dominator
270 TreeNodePtr IDomNode = getNodeForBlock(ImmDom);
272 TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT);
271273
272274 // Add a new tree node for this BasicBlock, and link it as a child of
273275 // IDomNode
277279
278280 DT.updateDFSNumbers();
279281 }
282
283 void doFullDFSWalk(const DomTreeT &DT) {
284 unsigned Num = 0;
285 for (auto *Root : DT.Roots)
286 if (!DT.isPostDominator())
287 Num = runForwardDFS(Root, Num);
288 else
289 Num = runReverseDFS(Root, Num);
290 }
291
292 static void PrintBlockOrNullptr(raw_ostream &O, NodePtr Obj) {
293 if (!Obj)
294 O << "nullptr";
295 else
296 Obj->printAsOperand(O, false);
297 }
298
299 // Checks if the tree contains all reachable nodes in the input graph.
300 bool verifyReachability(const DomTreeT &DT) {
301 clear();
302 doFullDFSWalk(DT);
303
304 for (auto &NodeToTN : DT.DomTreeNodes) {
305 const TreeNodePtr TN = NodeToTN.second.get();
306 const NodePtr BB = TN->getBlock();
307 if (!BB) continue;
308
309 if (NodeToInfo.count(BB) == 0) {
310 errs() << "DomTree node ";
311 PrintBlockOrNullptr(errs(), BB);
312 errs() << " not found by DFS walk!\n";
313 errs().flush();
314
315 return false;
316 }
317 }
318
319 return true;
320 }
321
322 // Checks if the tree has the parent property: if for all edges from V to W in
323 // the input graph, such that V is reachable, the parent of W in the tree is
324 // an ancestor of V in the tree.
325 //
326 // This means that if a node gets disconnected from the graph, then all of
327 // the nodes it dominated previously will now become unreachable.
328 bool verifyParentProperty(const DomTreeT &DT) {
329 for (auto &NodeToTN : DT.DomTreeNodes) {
330 const TreeNodePtr TN = NodeToTN.second.get();
331 const NodePtr BB = TN->getBlock();
332 if (!BB || TN->getChildren().empty()) continue;
333
334 clear();
335 NodeToInfo.insert({BB, {}});
336 doFullDFSWalk(DT);
337
338 for (TreeNodePtr Child : TN->getChildren())
339 if (NodeToInfo.count(Child->getBlock()) != 0) {
340 errs() << "Child ";
341 PrintBlockOrNullptr(errs(), Child->getBlock());
342 errs() << " reachable after its parent ";
343 PrintBlockOrNullptr(errs(), BB);
344 errs() << " is removed!\n";
345 errs().flush();
346
347 return false;
348 }
349 }
350
351 return true;
352 }
353
354 // Check if the tree has sibling property: if a node V does not dominate a
355 // node W for all siblings V and W in the tree.
356 //
357 // This means that if a node gets disconnected from the graph, then all of its
358 // siblings will now still be reachable.
359 bool verifySiblingProperty(const DomTreeT &DT) {
360 for (auto &NodeToTN : DT.DomTreeNodes) {
361 const TreeNodePtr TN = NodeToTN.second.get();
362 const NodePtr BB = TN->getBlock();
363 if (!BB || TN->getChildren().empty()) continue;
364
365 const auto &Siblings = TN->getChildren();
366 for (const TreeNodePtr N : Siblings) {
367 clear();
368 NodeToInfo.insert({N->getBlock(), {}});
369 doFullDFSWalk(DT);
370
371 for (const TreeNodePtr S : Siblings) {
372 if (S == N) continue;
373
374 if (NodeToInfo.count(S->getBlock()) == 0) {
375 errs() << "Node ";
376 PrintBlockOrNullptr(errs(), S->getBlock());
377 errs() << " not reachable when its sibling ";
378 PrintBlockOrNullptr(errs(), N->getBlock());
379 errs() << " is removed!\n";
380 errs().flush();
381
382 return false;
383 }
384 }
385 }
386 }
387
388 return true;
389 }
280390 };
281 } // namespace DomTreeBuilder
282391
283392 template
284393 void Calculate(DominatorTreeBaseByGraphTraits> &DT,
286395 using NodePtr = typename GraphTraits::NodeRef;
287396 static_assert(std::is_pointer::value,
288397 "NodePtr should be a pointer type");
289
290 DomTreeBuilder::SemiNCAInfo::type>
291 SNCA(DT);
292 SNCA.template runSemiNCA(GraphTraits::size(&F));
398 SemiNCAInfo::type> SNCA;
399 SNCA.template runSemiNCA(DT, GraphTraits::size(&F));
293400 }
401
402 template
403 bool Verify(const DominatorTreeBaseByGraphTraits> &DT) {
404 using NodePtr = typename GraphTraits::NodeRef;
405 static_assert(std::is_pointer::value,
406 "NodePtr should be a pointer type");
407 SemiNCAInfo::type> SNCA;
408
409 return SNCA.verifyReachability(DT) && SNCA.verifyParentProperty(DT) &&
410 SNCA.verifySiblingProperty(DT);
411
412 }
413
414 } // namespace DomTreeBuilder
294415 } // namespace llvm
295416
296417 #endif
6262 template class llvm::DomTreeNodeBase;
6363 template class llvm::DominatorTreeBase;
6464
65 template void llvm::Calculate(
65 template void llvm::DomTreeBuilder::Calculate(
6666 DominatorTreeBase<
6767 typename std::remove_pointer::NodeRef>::type>
6868 &DT,
6969 Function &F);
70 template void llvm::Calculate>(
70 template void llvm::DomTreeBuilder::Calculate>(
7171 DominatorTreeBase
7272 GraphTraits>::NodeRef>::type> &DT,
7373 Function &F);
74 template bool llvm::DomTreeBuilder::Verify(
75 const DominatorTreeBase<
76 typename std::remove_pointer::NodeRef>::type>
77 &DT);
78 template bool llvm::DomTreeBuilder::Verify>(
79 const DominatorTreeBase
80 GraphTraits>::NodeRef>::type> &DT);
7481
7582 bool DominatorTree::invalidate(Function &F, const PreservedAnalyses &PA,
7683 FunctionAnalysisManager::Invalidator &) {
284291 }
285292
286293 void DominatorTree::verifyDomTree() const {
294 if (!verify()) {
295 errs() << "\n~~~~~~~~~~~\n\t\tDomTree verification failed!\n~~~~~~~~~~~\n";
296 print(errs());
297 abort();
298 }
299
287300 Function &F = *getRoot()->getParent();
288301
289302 DominatorTree OtherDT;