llvm.org GIT mirror llvm / 950d20c
[Dominators] Keep tree level in DomTreeNode and use it to find NCD and answer dominance queries Summary: This patch makes DomTreeNodes keep their level (depth) in the DomTree. By having this information always available, it is possible to speedup and simplify findNearestCommonDominator and certain dominance queries. In the future, level information will be also needed to perform incremental updates. My testing doesn't show any noticeable performance differences after applying this patch. There may be some improvements when other passes are thought to use the level information. Reviewers: dberlin, sanjoy, chandlerc, grosser Reviewed By: dberlin Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D34548 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306892 91177308-0d34-0410-b5e6-96231b3b80d8 Jakub Kuderski 2 years ago
3 changed file(s) with 108 addition(s) and 63 deletion(s). Raw diff Collapse all Expand all
6464
6565 NodeT *TheBB;
6666 DomTreeNodeBase *IDom;
67 unsigned Level;
6768 std::vector Children;
6869 mutable unsigned DFSNumIn = ~0;
6970 mutable unsigned DFSNumOut = ~0;
7071
7172 public:
72 DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) : TheBB(BB), IDom(iDom) {}
73 DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom)
74 : TheBB(BB), IDom(iDom), Level(IDom ? IDom->Level + 1 : 0) {}
7375
7476 using iterator = typename std::vector::iterator;
7577 using const_iterator =
8284
8385 NodeT *getBlock() const { return TheBB; }
8486 DomTreeNodeBase *getIDom() const { return IDom; }
87 unsigned getLevel() const { return Level; }
8588
8689 const std::vector &getChildren() const { return Children; }
8790
99102 if (getNumChildren() != Other->getNumChildren())
100103 return true;
101104
105 if (Level != Other->Level) return true;
106
102107 SmallPtrSet OtherChildren;
103108 for (const DomTreeNodeBase *I : *Other) {
104109 const NodeT *Nd = I->getBlock();
115120
116121 void setIDom(DomTreeNodeBase *NewIDom) {
117122 assert(IDom && "No immediate dominator?");
118 if (IDom != NewIDom) {
119 typename std::vector::iterator I =
120 find(IDom->Children, this);
121 assert(I != IDom->Children.end() &&
122 "Not in immediate dominator children set!");
123 // I am no longer your child...
124 IDom->Children.erase(I);
125
126 // Switch to new dominator
127 IDom = NewIDom;
128 IDom->Children.push_back(this);
129 }
123 if (IDom == NewIDom) return;
124
125 auto I = find(IDom->Children, this);
126 assert(I != IDom->Children.end() &&
127 "Not in immediate dominator children set!");
128 // I am no longer your child...
129 IDom->Children.erase(I);
130
131 // Switch to new dominator
132 IDom = NewIDom;
133 IDom->Children.push_back(this);
134
135 UpdateLevel();
130136 }
131137
132138 /// getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes
142148 return this->DFSNumIn >= other->DFSNumIn &&
143149 this->DFSNumOut <= other->DFSNumOut;
144150 }
151
152 void UpdateLevel() {
153 assert(IDom);
154 if (Level == IDom->Level + 1) return;
155
156 SmallVector WorkStack = {this};
157
158 while (!WorkStack.empty()) {
159 DomTreeNodeBase *Current = WorkStack.pop_back_val();
160 Current->Level = Current->IDom->Level + 1;
161
162 for (DomTreeNodeBase *C : *Current) {
163 assert(C->IDom);
164 if (C->Level != C->IDom->Level + 1) WorkStack.push_back(C);
165 }
166 }
167 }
145168 };
146169
147170 template
151174 else
152175 O << " <>";
153176
154 O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "}";
155
156 return O << "\n";
177 O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "} ["
178 << Node->getLevel() << "]\n";
179
180 return O;
157181 }
158182
159183 template
344368 if (!isReachableFromEntry(A))
345369 return false;
346370
371 if (B->getIDom() == A) return true;
372
373 if (A->getIDom() == B) return false;
374
375 // A can only dominate B if it is higher in the tree.
376 if (A->getLevel() >= B->getLevel()) return false;
377
347378 // Compare the result of the tree walk and the dfs numbers, if expensive
348379 // checks are enabled.
349380 #ifdef EXPENSIVE_CHECKS
387418 return &Entry;
388419 }
389420
390 // If B dominates A then B is nearest common dominator.
391 if (dominates(B, A))
392 return B;
393
394 // If A dominates B then A is nearest common dominator.
395 if (dominates(A, B))
396 return A;
397
398421 DomTreeNodeBase *NodeA = getNode(A);
399422 DomTreeNodeBase *NodeB = getNode(B);
400423
401 // If we have DFS info, then we can avoid all allocations by just querying
402 // it from each IDom. Note that because we call 'dominates' twice above, we
403 // expect to call through this code at most 16 times in a row without
404 // building valid DFS information. This is important as below is a *very*
405 // slow tree walk.
406 if (DFSInfoValid) {
407 DomTreeNodeBase *IDomA = NodeA->getIDom();
408 while (IDomA) {
409 if (NodeB->DominatedBy(IDomA))
410 return IDomA->getBlock();
411 IDomA = IDomA->getIDom();
412 }
413 return nullptr;
414 }
415
416 // Collect NodeA dominators set.
417 SmallPtrSet *, 16> NodeADoms;
418 NodeADoms.insert(NodeA);
419 DomTreeNodeBase *IDomA = NodeA->getIDom();
420 while (IDomA) {
421 NodeADoms.insert(IDomA);
422 IDomA = IDomA->getIDom();
423 }
424
425 // Walk NodeB immediate dominators chain and find common dominator node.
426 DomTreeNodeBase *IDomB = NodeB->getIDom();
427 while (IDomB) {
428 if (NodeADoms.count(IDomB) != 0)
429 return IDomB->getBlock();
430
431 IDomB = IDomB->getIDom();
432 }
433
434 return nullptr;
424 // Use level information to go up the tree until the levels match. Then
425 // continue going up til we arrive at the same node.
426 while (NodeA && NodeA != NodeB) {
427 if (NodeA->getLevel() < NodeB->getLevel()) std::swap(NodeA, NodeB);
428
429 NodeA = NodeA->IDom;
430 }
431
432 return NodeA ? NodeA->getBlock() : nullptr;
435433 }
436434
437435 const NodeT *findNearestCommonDominator(const NodeT *A, const NodeT *B) {
480478 } else {
481479 assert(Roots.size() == 1);
482480 NodeT *OldRoot = Roots.front();
483 DomTreeNodes[OldRoot] =
484 NewNode->addChild(std::move(DomTreeNodes[OldRoot]));
481 auto &OldNode = DomTreeNodes[OldRoot];
482 OldNode = NewNode->addChild(std::move(DomTreeNodes[OldRoot]));
483 OldNode->IDom = NewNode;
484 OldNode->UpdateLevel();
485485 Roots[0] = BB;
486486 }
487487 return RootNode = NewNode;
317317 return true;
318318 }
319319
320 // Check if for every parent with a level L in the tree all of its children
321 // have level L + 1.
322 static bool VerifyLevels(const DomTreeT &DT) {
323 for (auto &NodeToTN : DT.DomTreeNodes) {
324 const TreeNodePtr TN = NodeToTN.second.get();
325 const NodePtr BB = TN->getBlock();
326 if (!BB) continue;
327
328 const TreeNodePtr IDom = TN->getIDom();
329 if (!IDom && TN->getLevel() != 0) {
330 errs() << "Node without an IDom ";
331 PrintBlockOrNullptr(errs(), BB);
332 errs() << " has a nonzero level " << TN->getLevel() << "!\n";
333 errs().flush();
334
335 return false;
336 }
337
338 if (IDom && TN->getLevel() != IDom->getLevel() + 1) {
339 errs() << "Node ";
340 PrintBlockOrNullptr(errs(), BB);
341 errs() << " has level " << TN->getLevel() << " while it's IDom ";
342 PrintBlockOrNullptr(errs(), IDom->getBlock());
343 errs() << " has level " << IDom->getLevel() << "!\n";
344 errs().flush();
345
346 return false;
347 }
348 }
349
350 return true;
351 }
352
320353 // Checks if the tree has the parent property: if for all edges from V to W in
321354 // the input graph, such that V is reachable, the parent of W in the tree is
322355 // an ancestor of V in the tree.
404437 "NodePtr should be a pointer type");
405438 SemiNCAInfo::type> SNCA;
406439
407 return SNCA.verifyReachability(DT) && SNCA.verifyParentProperty(DT) &&
408 SNCA.verifySiblingProperty(DT);
409
440 return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&
441 SNCA.verifyParentProperty(DT) && SNCA.verifySiblingProperty(DT);
410442 }
411443
412444 } // namespace DomTreeBuilder
229229 EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL);
230230 EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL);
231231
232 // Check levels before
233 EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);
234 EXPECT_EQ(DT->getNode(BB1)->getLevel(), 1U);
235 EXPECT_EQ(DT->getNode(BB2)->getLevel(), 1U);
236 EXPECT_EQ(DT->getNode(BB4)->getLevel(), 1U);
237
232238 // Reattach block 3 to block 1 and recalculate
233239 BB1->getTerminator()->eraseFromParent();
234240 BranchInst::Create(BB4, BB3, ConstantInt::getTrue(F.getContext()), BB1);
246252 EXPECT_EQ(DT->getNode(BB3)->getDFSNumOut(), 3UL);
247253 EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 5UL);
248254 EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 6UL);
255
256 // Check levels after
257 EXPECT_EQ(DT->getNode(BB0)->getLevel(), 0U);
258 EXPECT_EQ(DT->getNode(BB1)->getLevel(), 1U);
259 EXPECT_EQ(DT->getNode(BB2)->getLevel(), 1U);
260 EXPECT_EQ(DT->getNode(BB3)->getLevel(), 2U);
261 EXPECT_EQ(DT->getNode(BB4)->getLevel(), 1U);
249262
250263 // Change root node
251264 DT->verifyDomTree();