• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- DomTreeUpdater.cpp - DomTree/Post DomTree Updater --------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the DomTreeUpdater class, which provides a uniform way
11 // to update dominator tree related data structures.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "llvm/IR/DomTreeUpdater.h"
16 #include "llvm/Analysis/PostDominators.h"
17 #include "llvm/IR/Dominators.h"
18 #include "llvm/Support/GenericDomTree.h"
19 #include <algorithm>
20 #include <functional>
21 
22 namespace llvm {
23 
isUpdateValid(const DominatorTree::UpdateType Update) const24 bool DomTreeUpdater::isUpdateValid(
25     const DominatorTree::UpdateType Update) const {
26   const auto *From = Update.getFrom();
27   const auto *To = Update.getTo();
28   const auto Kind = Update.getKind();
29 
30   // Discard updates by inspecting the current state of successors of From.
31   // Since isUpdateValid() must be called *after* the Terminator of From is
32   // altered we can determine if the update is unnecessary for batch updates
33   // or invalid for a single update.
34   const bool HasEdge = llvm::any_of(
35       successors(From), [To](const BasicBlock *B) { return B == To; });
36 
37   // If the IR does not match the update,
38   // 1. In batch updates, this update is unnecessary.
39   // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
40   // Edge does not exist in IR.
41   if (Kind == DominatorTree::Insert && !HasEdge)
42     return false;
43 
44   // Edge exists in IR.
45   if (Kind == DominatorTree::Delete && HasEdge)
46     return false;
47 
48   return true;
49 }
50 
isSelfDominance(const DominatorTree::UpdateType Update) const51 bool DomTreeUpdater::isSelfDominance(
52     const DominatorTree::UpdateType Update) const {
53   // Won't affect DomTree and PostDomTree.
54   return Update.getFrom() == Update.getTo();
55 }
56 
applyLazyUpdate(DominatorTree::UpdateKind Kind,BasicBlock * From,BasicBlock * To)57 bool DomTreeUpdater::applyLazyUpdate(DominatorTree::UpdateKind Kind,
58                                      BasicBlock *From, BasicBlock *To) {
59   assert((DT || PDT) &&
60          "Call applyLazyUpdate() when both DT and PDT are nullptrs.");
61   assert(Strategy == DomTreeUpdater::UpdateStrategy::Lazy &&
62          "Call applyLazyUpdate() with Eager strategy error");
63   // Analyze pending updates to determine if the update is unnecessary.
64   const DominatorTree::UpdateType Update = {Kind, From, To};
65   const DominatorTree::UpdateType Invert = {Kind != DominatorTree::Insert
66                                                 ? DominatorTree::Insert
67                                                 : DominatorTree::Delete,
68                                             From, To};
69   // Only check duplicates in updates that are not applied by both trees.
70   auto I =
71       PendUpdates.begin() + std::max(PendDTUpdateIndex, PendPDTUpdateIndex);
72   const auto E = PendUpdates.end();
73 
74   assert(I <= E && "Iterator out of range.");
75 
76   for (; I != E; ++I) {
77     if (Update == *I)
78       return false; // Discard duplicate updates.
79 
80     if (Invert == *I) {
81       // Update and Invert are both valid (equivalent to a no-op). Remove
82       // Invert from PendUpdates and discard the Update.
83       PendUpdates.erase(I);
84       return false;
85     }
86   }
87 
88   PendUpdates.push_back(Update); // Save the valid update.
89   return true;
90 }
91 
applyDomTreeUpdates()92 void DomTreeUpdater::applyDomTreeUpdates() {
93   // No pending DomTreeUpdates.
94   if (Strategy != UpdateStrategy::Lazy || !DT)
95     return;
96 
97   // Only apply updates not are applied by DomTree.
98   if (hasPendingDomTreeUpdates()) {
99     const auto I = PendUpdates.begin() + PendDTUpdateIndex;
100     const auto E = PendUpdates.end();
101     assert(I < E && "Iterator range invalid; there should be DomTree updates.");
102     DT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
103     PendDTUpdateIndex = PendUpdates.size();
104   }
105 }
106 
flush()107 void DomTreeUpdater::flush() {
108   applyDomTreeUpdates();
109   applyPostDomTreeUpdates();
110   dropOutOfDateUpdates();
111 }
112 
applyPostDomTreeUpdates()113 void DomTreeUpdater::applyPostDomTreeUpdates() {
114   // No pending PostDomTreeUpdates.
115   if (Strategy != UpdateStrategy::Lazy || !PDT)
116     return;
117 
118   // Only apply updates not are applied by PostDomTree.
119   if (hasPendingPostDomTreeUpdates()) {
120     const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
121     const auto E = PendUpdates.end();
122     assert(I < E &&
123            "Iterator range invalid; there should be PostDomTree updates.");
124     PDT->applyUpdates(ArrayRef<DominatorTree::UpdateType>(I, E));
125     PendPDTUpdateIndex = PendUpdates.size();
126   }
127 }
128 
tryFlushDeletedBB()129 void DomTreeUpdater::tryFlushDeletedBB() {
130   if (!hasPendingUpdates())
131     forceFlushDeletedBB();
132 }
133 
forceFlushDeletedBB()134 bool DomTreeUpdater::forceFlushDeletedBB() {
135   if (DeletedBBs.empty())
136     return false;
137 
138   for (auto *BB : DeletedBBs) {
139     // After calling deleteBB or callbackDeleteBB under Lazy UpdateStrategy,
140     // validateDeleteBB() removes all instructions of DelBB and adds an
141     // UnreachableInst as its terminator. So we check whether the BasicBlock to
142     // delete only has an UnreachableInst inside.
143     assert(BB->getInstList().size() == 1 &&
144            isa<UnreachableInst>(BB->getTerminator()) &&
145            "DelBB has been modified while awaiting deletion.");
146     BB->removeFromParent();
147     eraseDelBBNode(BB);
148     delete BB;
149   }
150   DeletedBBs.clear();
151   Callbacks.clear();
152   return true;
153 }
154 
recalculate(Function & F)155 bool DomTreeUpdater::recalculate(Function &F) {
156   if (!DT && !PDT)
157     return false;
158 
159   if (Strategy == UpdateStrategy::Eager) {
160     if (DT)
161       DT->recalculate(F);
162     if (PDT)
163       PDT->recalculate(F);
164     return true;
165   }
166 
167   // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
168   IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
169 
170   // Because all trees are going to be up-to-date after recalculation,
171   // flush awaiting deleted BasicBlocks.
172   if (forceFlushDeletedBB() || hasPendingUpdates()) {
173     if (DT)
174       DT->recalculate(F);
175     if (PDT)
176       PDT->recalculate(F);
177 
178     // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
179     IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
180     PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
181     dropOutOfDateUpdates();
182     return true;
183   }
184 
185   // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
186   IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
187   return false;
188 }
189 
hasPendingUpdates() const190 bool DomTreeUpdater::hasPendingUpdates() const {
191   return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
192 }
193 
hasPendingDomTreeUpdates() const194 bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
195   if (!DT)
196     return false;
197   return PendUpdates.size() != PendDTUpdateIndex;
198 }
199 
hasPendingPostDomTreeUpdates() const200 bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
201   if (!PDT)
202     return false;
203   return PendUpdates.size() != PendPDTUpdateIndex;
204 }
205 
isBBPendingDeletion(llvm::BasicBlock * DelBB) const206 bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
207   if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
208     return false;
209   return DeletedBBs.count(DelBB) != 0;
210 }
211 
212 // The DT and PDT require the nodes related to updates
213 // are not deleted when update functions are called.
214 // So BasicBlock deletions must be pended when the
215 // UpdateStrategy is Lazy. When the UpdateStrategy is
216 // Eager, the BasicBlock will be deleted immediately.
deleteBB(BasicBlock * DelBB)217 void DomTreeUpdater::deleteBB(BasicBlock *DelBB) {
218   validateDeleteBB(DelBB);
219   if (Strategy == UpdateStrategy::Lazy) {
220     DeletedBBs.insert(DelBB);
221     return;
222   }
223 
224   DelBB->removeFromParent();
225   eraseDelBBNode(DelBB);
226   delete DelBB;
227 }
228 
callbackDeleteBB(BasicBlock * DelBB,std::function<void (BasicBlock *)> Callback)229 void DomTreeUpdater::callbackDeleteBB(
230     BasicBlock *DelBB, std::function<void(BasicBlock *)> Callback) {
231   validateDeleteBB(DelBB);
232   if (Strategy == UpdateStrategy::Lazy) {
233     Callbacks.push_back(CallBackOnDeletion(DelBB, Callback));
234     DeletedBBs.insert(DelBB);
235     return;
236   }
237 
238   DelBB->removeFromParent();
239   eraseDelBBNode(DelBB);
240   Callback(DelBB);
241   delete DelBB;
242 }
243 
eraseDelBBNode(BasicBlock * DelBB)244 void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
245   if (DT && !IsRecalculatingDomTree)
246     if (DT->getNode(DelBB))
247       DT->eraseNode(DelBB);
248 
249   if (PDT && !IsRecalculatingPostDomTree)
250     if (PDT->getNode(DelBB))
251       PDT->eraseNode(DelBB);
252 }
253 
validateDeleteBB(BasicBlock * DelBB)254 void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
255   assert(DelBB && "Invalid push_back of nullptr DelBB.");
256   assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
257   // DelBB is unreachable and all its instructions are dead.
258   while (!DelBB->empty()) {
259     Instruction &I = DelBB->back();
260     // Replace used instructions with an arbitrary value (undef).
261     if (!I.use_empty())
262       I.replaceAllUsesWith(llvm::UndefValue::get(I.getType()));
263     DelBB->getInstList().pop_back();
264   }
265   // Make sure DelBB has a valid terminator instruction. As long as DelBB is a
266   // Child of Function F it must contain valid IR.
267   new UnreachableInst(DelBB->getContext(), DelBB);
268 }
269 
applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,bool ForceRemoveDuplicates)270 void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
271                                   bool ForceRemoveDuplicates) {
272   if (!DT && !PDT)
273     return;
274 
275   if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) {
276     SmallVector<DominatorTree::UpdateType, 8> Seen;
277     for (const auto U : Updates)
278       // For Lazy UpdateStrategy, avoid duplicates to applyLazyUpdate() to save
279       // on analysis.
280       if (llvm::none_of(
281               Seen,
282               [U](const DominatorTree::UpdateType S) { return S == U; }) &&
283           isUpdateValid(U) && !isSelfDominance(U)) {
284         Seen.push_back(U);
285         if (Strategy == UpdateStrategy::Lazy)
286           applyLazyUpdate(U.getKind(), U.getFrom(), U.getTo());
287       }
288     if (Strategy == UpdateStrategy::Lazy)
289       return;
290 
291     if (DT)
292       DT->applyUpdates(Seen);
293     if (PDT)
294       PDT->applyUpdates(Seen);
295     return;
296   }
297 
298   if (DT)
299     DT->applyUpdates(Updates);
300   if (PDT)
301     PDT->applyUpdates(Updates);
302 }
303 
getDomTree()304 DominatorTree &DomTreeUpdater::getDomTree() {
305   assert(DT && "Invalid acquisition of a null DomTree");
306   applyDomTreeUpdates();
307   dropOutOfDateUpdates();
308   return *DT;
309 }
310 
getPostDomTree()311 PostDominatorTree &DomTreeUpdater::getPostDomTree() {
312   assert(PDT && "Invalid acquisition of a null PostDomTree");
313   applyPostDomTreeUpdates();
314   dropOutOfDateUpdates();
315   return *PDT;
316 }
317 
insertEdge(BasicBlock * From,BasicBlock * To)318 void DomTreeUpdater::insertEdge(BasicBlock *From, BasicBlock *To) {
319 
320 #ifndef NDEBUG
321   assert(isUpdateValid({DominatorTree::Insert, From, To}) &&
322          "Inserted edge does not appear in the CFG");
323 #endif
324 
325   if (!DT && !PDT)
326     return;
327 
328   // Won't affect DomTree and PostDomTree; discard update.
329   if (From == To)
330     return;
331 
332   if (Strategy == UpdateStrategy::Eager) {
333     if (DT)
334       DT->insertEdge(From, To);
335     if (PDT)
336       PDT->insertEdge(From, To);
337     return;
338   }
339 
340   applyLazyUpdate(DominatorTree::Insert, From, To);
341 }
342 
insertEdgeRelaxed(BasicBlock * From,BasicBlock * To)343 void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
344   if (From == To)
345     return;
346 
347   if (!DT && !PDT)
348     return;
349 
350   if (!isUpdateValid({DominatorTree::Insert, From, To}))
351     return;
352 
353   if (Strategy == UpdateStrategy::Eager) {
354     if (DT)
355       DT->insertEdge(From, To);
356     if (PDT)
357       PDT->insertEdge(From, To);
358     return;
359   }
360 
361   applyLazyUpdate(DominatorTree::Insert, From, To);
362 }
363 
deleteEdge(BasicBlock * From,BasicBlock * To)364 void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) {
365 
366 #ifndef NDEBUG
367   assert(isUpdateValid({DominatorTree::Delete, From, To}) &&
368          "Deleted edge still exists in the CFG!");
369 #endif
370 
371   if (!DT && !PDT)
372     return;
373 
374   // Won't affect DomTree and PostDomTree; discard update.
375   if (From == To)
376     return;
377 
378   if (Strategy == UpdateStrategy::Eager) {
379     if (DT)
380       DT->deleteEdge(From, To);
381     if (PDT)
382       PDT->deleteEdge(From, To);
383     return;
384   }
385 
386   applyLazyUpdate(DominatorTree::Delete, From, To);
387 }
388 
deleteEdgeRelaxed(BasicBlock * From,BasicBlock * To)389 void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
390   if (From == To)
391     return;
392 
393   if (!DT && !PDT)
394     return;
395 
396   if (!isUpdateValid({DominatorTree::Delete, From, To}))
397     return;
398 
399   if (Strategy == UpdateStrategy::Eager) {
400     if (DT)
401       DT->deleteEdge(From, To);
402     if (PDT)
403       PDT->deleteEdge(From, To);
404     return;
405   }
406 
407   applyLazyUpdate(DominatorTree::Delete, From, To);
408 }
409 
dropOutOfDateUpdates()410 void DomTreeUpdater::dropOutOfDateUpdates() {
411   if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
412     return;
413 
414   tryFlushDeletedBB();
415 
416   // Drop all updates applied by both trees.
417   if (!DT)
418     PendDTUpdateIndex = PendUpdates.size();
419   if (!PDT)
420     PendPDTUpdateIndex = PendUpdates.size();
421 
422   const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
423   const auto B = PendUpdates.begin();
424   const auto E = PendUpdates.begin() + dropIndex;
425   assert(B <= E && "Iterator out of range.");
426   PendUpdates.erase(B, E);
427   // Calculate current index.
428   PendDTUpdateIndex -= dropIndex;
429   PendPDTUpdateIndex -= dropIndex;
430 }
431 
432 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const433 LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
434   raw_ostream &OS = llvm::dbgs();
435 
436   OS << "Available Trees: ";
437   if (DT || PDT) {
438     if (DT)
439       OS << "DomTree ";
440     if (PDT)
441       OS << "PostDomTree ";
442     OS << "\n";
443   } else
444     OS << "None\n";
445 
446   OS << "UpdateStrategy: ";
447   if (Strategy == UpdateStrategy::Eager) {
448     OS << "Eager\n";
449     return;
450   } else
451     OS << "Lazy\n";
452   int Index = 0;
453 
454   auto printUpdates =
455       [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
456           ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
457         if (begin == end)
458           OS << "  None\n";
459         Index = 0;
460         for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
461           auto U = *It;
462           OS << "  " << Index << " : ";
463           ++Index;
464           if (U.getKind() == DominatorTree::Insert)
465             OS << "Insert, ";
466           else
467             OS << "Delete, ";
468           BasicBlock *From = U.getFrom();
469           if (From) {
470             auto S = From->getName();
471             if (!From->hasName())
472               S = "(no name)";
473             OS << S << "(" << From << "), ";
474           } else {
475             OS << "(badref), ";
476           }
477           BasicBlock *To = U.getTo();
478           if (To) {
479             auto S = To->getName();
480             if (!To->hasName())
481               S = "(no_name)";
482             OS << S << "(" << To << ")\n";
483           } else {
484             OS << "(badref)\n";
485           }
486         }
487       };
488 
489   if (DT) {
490     const auto I = PendUpdates.begin() + PendDTUpdateIndex;
491     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
492            "Iterator out of range.");
493     OS << "Applied but not cleared DomTreeUpdates:\n";
494     printUpdates(PendUpdates.begin(), I);
495     OS << "Pending DomTreeUpdates:\n";
496     printUpdates(I, PendUpdates.end());
497   }
498 
499   if (PDT) {
500     const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
501     assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
502            "Iterator out of range.");
503     OS << "Applied but not cleared PostDomTreeUpdates:\n";
504     printUpdates(PendUpdates.begin(), I);
505     OS << "Pending PostDomTreeUpdates:\n";
506     printUpdates(I, PendUpdates.end());
507   }
508 
509   OS << "Pending DeletedBBs:\n";
510   Index = 0;
511   for (auto BB : DeletedBBs) {
512     OS << "  " << Index << " : ";
513     ++Index;
514     if (BB->hasName())
515       OS << BB->getName() << "(";
516     else
517       OS << "(no_name)(";
518     OS << BB << ")\n";
519   }
520 
521   OS << "Pending Callbacks:\n";
522   Index = 0;
523   for (auto BB : Callbacks) {
524     OS << "  " << Index << " : ";
525     ++Index;
526     if (BB->hasName())
527       OS << BB->getName() << "(";
528     else
529       OS << "(no_name)(";
530     OS << BB << ")\n";
531   }
532 }
533 #endif
534 } // namespace llvm
535