blob: 51dd24bccfafbe77cced25d17eae493a81bcd830 [file] [log] [blame]
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +00001//===- 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
22namespace llvm {
23
24bool 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
51bool DomTreeUpdater::isSelfDominance(
52 const DominatorTree::UpdateType Update) const {
53 // Won't affect DomTree and PostDomTree.
54 return Update.getFrom() == Update.getTo();
55}
56
57bool DomTreeUpdater::applyLazyUpdate(DominatorTree::UpdateKind Kind,
58 BasicBlock *From, BasicBlock *To) {
Chijun Sima00712cb2018-07-13 04:02:13 +000059 assert(DT ||
60 PDT && "Call applyLazyUpdate() when both DT and PDT are nullptrs.");
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +000061 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
92void 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
107void DomTreeUpdater::flush() {
108 applyDomTreeUpdates();
109 applyPostDomTreeUpdates();
110 dropOutOfDateUpdates();
111}
112
113void 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
129void DomTreeUpdater::tryFlushDeletedBB() {
130 if (!hasPendingUpdates())
131 forceFlushDeletedBB();
132}
133
134bool DomTreeUpdater::forceFlushDeletedBB() {
135 if (DeletedBBs.empty())
136 return false;
137
138 for (auto *BB : DeletedBBs) {
139 BB->removeFromParent();
140 eraseDelBBNode(BB);
141 delete BB;
142 }
143 DeletedBBs.clear();
144 Callbacks.clear();
145 return true;
146}
147
148bool DomTreeUpdater::recalculate(Function &F) {
149 if (!DT && !PDT)
150 return false;
151
152 if (Strategy == UpdateStrategy::Eager) {
153 if (DT)
154 DT->recalculate(F);
155 if (PDT)
156 PDT->recalculate(F);
157 return true;
158 }
159
160 // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
161 IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
162
163 // Because all trees are going to be up-to-date after recalculation,
164 // flush awaiting deleted BasicBlocks.
165 if (forceFlushDeletedBB() || hasPendingUpdates()) {
166 if (DT)
167 DT->recalculate(F);
168 if (PDT)
169 PDT->recalculate(F);
170
171 // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
172 IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
173 PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
174 dropOutOfDateUpdates();
175 return true;
176 }
177
178 // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
179 IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
180 return false;
181}
182
183bool DomTreeUpdater::hasPendingUpdates() const {
184 return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
185}
186
187bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
188 if (!DT)
189 return false;
190 return PendUpdates.size() != PendDTUpdateIndex;
191}
192
193bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
194 if (!PDT)
195 return false;
196 return PendUpdates.size() != PendPDTUpdateIndex;
197}
198
199bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
200 if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
201 return false;
202 return DeletedBBs.count(DelBB) != 0;
203}
204
205// The DT and PDT require the nodes related to updates
206// are not deleted when update functions are called.
207// So BasicBlock deletions must be pended when the
208// UpdateStrategy is Lazy. When the UpdateStrategy is
209// Eager, the BasicBlock will be deleted immediately.
210void DomTreeUpdater::deleteBB(BasicBlock *DelBB) {
211 validateDeleteBB(DelBB);
212 if (Strategy == UpdateStrategy::Lazy) {
213 DeletedBBs.insert(DelBB);
214 return;
215 }
216
217 DelBB->removeFromParent();
218 eraseDelBBNode(DelBB);
219 delete DelBB;
220}
221
222void DomTreeUpdater::callbackDeleteBB(
223 BasicBlock *DelBB, std::function<void(BasicBlock *)> Callback) {
224 validateDeleteBB(DelBB);
225 if (Strategy == UpdateStrategy::Lazy) {
226 Callbacks.push_back(CallBackOnDeletion(DelBB, Callback));
227 DeletedBBs.insert(DelBB);
228 return;
229 }
230
231 DelBB->removeFromParent();
232 eraseDelBBNode(DelBB);
233 Callback(DelBB);
234 delete DelBB;
235}
236
237void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
238 if (DT && !IsRecalculatingDomTree)
239 if (DT->getNode(DelBB))
240 DT->eraseNode(DelBB);
241
242 if (PDT && !IsRecalculatingPostDomTree)
243 if (PDT->getNode(DelBB))
244 PDT->eraseNode(DelBB);
245}
246
247void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
248 assert(DelBB && "Invalid push_back of nullptr DelBB.");
249 assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
250 // DelBB is unreachable and all its instructions are dead.
251 while (!DelBB->empty()) {
252 Instruction &I = DelBB->back();
253 // Replace used instructions with an arbitrary value (undef).
254 if (!I.use_empty())
255 I.replaceAllUsesWith(llvm::UndefValue::get(I.getType()));
256 DelBB->getInstList().pop_back();
257 }
258 // Make sure DelBB has a valid terminator instruction. As long as DelBB is a
259 // Child of Function F it must contain valid IR.
260 new UnreachableInst(DelBB->getContext(), DelBB);
261}
262
263void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
264 bool ForceRemoveDuplicates) {
Chijun Sima00712cb2018-07-13 04:02:13 +0000265 if (!DT && !PDT)
266 return;
267
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000268 if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) {
269 SmallVector<DominatorTree::UpdateType, 8> Seen;
270 for (const auto U : Updates)
271 // For Lazy UpdateStrategy, avoid duplicates to applyLazyUpdate() to save
272 // on analysis.
273 if (llvm::none_of(
274 Seen,
275 [U](const DominatorTree::UpdateType S) { return S == U; }) &&
276 isUpdateValid(U) && !isSelfDominance(U)) {
277 Seen.push_back(U);
278 if (Strategy == UpdateStrategy::Lazy)
279 applyLazyUpdate(U.getKind(), U.getFrom(), U.getTo());
280 }
281 if (Strategy == UpdateStrategy::Lazy)
282 return;
283
284 if (DT)
285 DT->applyUpdates(Seen);
286 if (PDT)
287 PDT->applyUpdates(Seen);
288 return;
289 }
290
291 if (DT)
292 DT->applyUpdates(Updates);
293 if (PDT)
294 PDT->applyUpdates(Updates);
295}
296
297DominatorTree &DomTreeUpdater::getDomTree() {
298 assert(DT && "Invalid acquisition of a null DomTree");
299 applyDomTreeUpdates();
300 dropOutOfDateUpdates();
301 return *DT;
302}
303
304PostDominatorTree &DomTreeUpdater::getPostDomTree() {
305 assert(PDT && "Invalid acquisition of a null PostDomTree");
306 applyPostDomTreeUpdates();
307 dropOutOfDateUpdates();
308 return *PDT;
309}
310
311void DomTreeUpdater::insertEdge(BasicBlock *From, BasicBlock *To) {
312
313#ifndef NDEBUG
314 assert(isUpdateValid({DominatorTree::Insert, From, To}) &&
315 "Inserted edge does not appear in the CFG");
316#endif
317
Chijun Sima00712cb2018-07-13 04:02:13 +0000318 if (!DT && !PDT)
319 return;
320
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000321 // Won't affect DomTree and PostDomTree; discard update.
322 if (From == To)
323 return;
324
325 if (Strategy == UpdateStrategy::Eager) {
326 if (DT)
327 DT->insertEdge(From, To);
328 if (PDT)
329 PDT->insertEdge(From, To);
330 return;
331 }
332
333 applyLazyUpdate(DominatorTree::Insert, From, To);
334}
335
Chijun Sima00712cb2018-07-13 04:02:13 +0000336void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000337 if (From == To)
Chijun Sima00712cb2018-07-13 04:02:13 +0000338 return;
339
340 if (!DT && !PDT)
341 return;
342
343 if (!isUpdateValid({DominatorTree::Insert, From, To}))
344 return;
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000345
346 if (Strategy == UpdateStrategy::Eager) {
347 if (DT)
348 DT->insertEdge(From, To);
349 if (PDT)
350 PDT->insertEdge(From, To);
Chijun Sima00712cb2018-07-13 04:02:13 +0000351 return;
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000352 }
353
354 applyLazyUpdate(DominatorTree::Insert, From, To);
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000355}
356
357void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) {
358
359#ifndef NDEBUG
360 assert(isUpdateValid({DominatorTree::Delete, From, To}) &&
361 "Deleted edge still exists in the CFG!");
362#endif
363
Chijun Sima00712cb2018-07-13 04:02:13 +0000364 if (!DT && !PDT)
365 return;
366
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000367 // Won't affect DomTree and PostDomTree; discard update.
368 if (From == To)
369 return;
370
371 if (Strategy == UpdateStrategy::Eager) {
372 if (DT)
373 DT->deleteEdge(From, To);
374 if (PDT)
375 PDT->deleteEdge(From, To);
376 return;
377 }
378
379 applyLazyUpdate(DominatorTree::Delete, From, To);
380}
381
Chijun Sima00712cb2018-07-13 04:02:13 +0000382void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000383 if (From == To)
Chijun Sima00712cb2018-07-13 04:02:13 +0000384 return;
385
386 if (!DT && !PDT)
387 return;
388
389 if (!isUpdateValid({DominatorTree::Delete, From, To}))
390 return;
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000391
392 if (Strategy == UpdateStrategy::Eager) {
393 if (DT)
394 DT->deleteEdge(From, To);
395 if (PDT)
396 PDT->deleteEdge(From, To);
Chijun Sima00712cb2018-07-13 04:02:13 +0000397 return;
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000398 }
399
400 applyLazyUpdate(DominatorTree::Delete, From, To);
Jakub Kuderski5e3ab7a2018-07-03 02:06:23 +0000401}
402
403void DomTreeUpdater::dropOutOfDateUpdates() {
404 if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
405 return;
406
407 tryFlushDeletedBB();
408
409 // Drop all updates applied by both trees.
410 if (!DT)
411 PendDTUpdateIndex = PendUpdates.size();
412 if (!PDT)
413 PendPDTUpdateIndex = PendUpdates.size();
414
415 const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
416 const auto B = PendUpdates.begin();
417 const auto E = PendUpdates.begin() + dropIndex;
418 assert(B <= E && "Iterator out of range.");
419 PendUpdates.erase(B, E);
420 // Calculate current index.
421 PendDTUpdateIndex -= dropIndex;
422 PendPDTUpdateIndex -= dropIndex;
423}
424
425#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
426LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
427 raw_ostream &OS = llvm::dbgs();
428
429 OS << "Available Trees: ";
430 if (DT || PDT) {
431 if (DT)
432 OS << "DomTree ";
433 if (PDT)
434 OS << "PostDomTree ";
435 OS << "\n";
436 } else
437 OS << "None\n";
438
439 OS << "UpdateStrategy: ";
440 if (Strategy == UpdateStrategy::Eager) {
441 OS << "Eager\n";
442 return;
443 } else
444 OS << "Lazy\n";
445 int Index = 0;
446
447 auto printUpdates =
448 [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
449 ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
450 if (begin == end)
451 OS << " None\n";
452 Index = 0;
453 for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
454 auto U = *It;
455 OS << " " << Index << " : ";
456 ++Index;
457 if (U.getKind() == DominatorTree::Insert)
458 OS << "Insert, ";
459 else
460 OS << "Delete, ";
461 BasicBlock *From = U.getFrom();
462 if (From) {
463 auto S = From->getName();
464 if (!From->hasName())
465 S = "(no name)";
466 OS << S << "(" << From << "), ";
467 } else {
468 OS << "(badref), ";
469 }
470 BasicBlock *To = U.getTo();
471 if (To) {
472 auto S = To->getName();
473 if (!To->hasName())
474 S = "(no_name)";
475 OS << S << "(" << To << ")\n";
476 } else {
477 OS << "(badref)\n";
478 }
479 }
480 };
481
482 if (DT) {
483 const auto I = PendUpdates.begin() + PendDTUpdateIndex;
484 assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
485 "Iterator out of range.");
486 OS << "Applied but not cleared DomTreeUpdates:\n";
487 printUpdates(PendUpdates.begin(), I);
488 OS << "Pending DomTreeUpdates:\n";
489 printUpdates(I, PendUpdates.end());
490 }
491
492 if (PDT) {
493 const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
494 assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
495 "Iterator out of range.");
496 OS << "Applied but not cleared PostDomTreeUpdates:\n";
497 printUpdates(PendUpdates.begin(), I);
498 OS << "Pending PostDomTreeUpdates:\n";
499 printUpdates(I, PendUpdates.end());
500 }
501
502 OS << "Pending DeletedBBs:\n";
503 Index = 0;
504 for (auto BB : DeletedBBs) {
505 OS << " " << Index << " : ";
506 ++Index;
507 if (BB->hasName())
508 OS << BB->getName() << "(";
509 else
510 OS << "(no_name)(";
511 OS << BB << ")\n";
512 }
513
514 OS << "Pending Callbacks:\n";
515 Index = 0;
516 for (auto BB : Callbacks) {
517 OS << " " << Index << " : ";
518 ++Index;
519 if (BB->hasName())
520 OS << BB->getName() << "(";
521 else
522 OS << "(no_name)(";
523 OS << BB << ")\n";
524 }
525}
526#endif
527} // namespace llvm