blob: b72c1b77c2ce06507164a7df71c98124f4431c55 [file] [log] [blame]
Jakub Kuderski57fa5c92018-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) {
Erich Keane8689f342018-07-13 14:41:15 +000059 assert((DT || PDT) &&
60 "Call applyLazyUpdate() when both DT and PDT are nullptrs.");
Jakub Kuderski57fa5c92018-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) {
Chijun Simaa23be0642018-07-25 06:18:33 +0000139 // 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.");
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000146 BB->removeFromParent();
147 eraseDelBBNode(BB);
148 delete BB;
149 }
150 DeletedBBs.clear();
151 Callbacks.clear();
152 return true;
153}
154
Chijun Simaa9028ca2018-08-03 06:51:35 +0000155void DomTreeUpdater::recalculate(Function &F) {
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000156
157 if (Strategy == UpdateStrategy::Eager) {
158 if (DT)
159 DT->recalculate(F);
160 if (PDT)
161 PDT->recalculate(F);
Chijun Simaa9028ca2018-08-03 06:51:35 +0000162 return;
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000163 }
164
Chijun Simaa9028ca2018-08-03 06:51:35 +0000165 // There is little performance gain if we pend the recalculation under
166 // Lazy UpdateStrategy so we recalculate available trees immediately.
167
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000168 // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
169 IsRecalculatingDomTree = IsRecalculatingPostDomTree = true;
170
171 // Because all trees are going to be up-to-date after recalculation,
172 // flush awaiting deleted BasicBlocks.
Chijun Simaa9028ca2018-08-03 06:51:35 +0000173 forceFlushDeletedBB();
174 if (DT)
175 DT->recalculate(F);
176 if (PDT)
177 PDT->recalculate(F);
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000178
179 // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
180 IsRecalculatingDomTree = IsRecalculatingPostDomTree = false;
Chijun Simaa9028ca2018-08-03 06:51:35 +0000181 PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size();
182 dropOutOfDateUpdates();
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000183}
184
185bool DomTreeUpdater::hasPendingUpdates() const {
186 return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
187}
188
189bool DomTreeUpdater::hasPendingDomTreeUpdates() const {
190 if (!DT)
191 return false;
192 return PendUpdates.size() != PendDTUpdateIndex;
193}
194
195bool DomTreeUpdater::hasPendingPostDomTreeUpdates() const {
196 if (!PDT)
197 return false;
198 return PendUpdates.size() != PendPDTUpdateIndex;
199}
200
201bool DomTreeUpdater::isBBPendingDeletion(llvm::BasicBlock *DelBB) const {
202 if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
203 return false;
204 return DeletedBBs.count(DelBB) != 0;
205}
206
207// The DT and PDT require the nodes related to updates
208// are not deleted when update functions are called.
209// So BasicBlock deletions must be pended when the
210// UpdateStrategy is Lazy. When the UpdateStrategy is
211// Eager, the BasicBlock will be deleted immediately.
212void DomTreeUpdater::deleteBB(BasicBlock *DelBB) {
213 validateDeleteBB(DelBB);
214 if (Strategy == UpdateStrategy::Lazy) {
215 DeletedBBs.insert(DelBB);
216 return;
217 }
218
219 DelBB->removeFromParent();
220 eraseDelBBNode(DelBB);
221 delete DelBB;
222}
223
224void DomTreeUpdater::callbackDeleteBB(
225 BasicBlock *DelBB, std::function<void(BasicBlock *)> Callback) {
226 validateDeleteBB(DelBB);
227 if (Strategy == UpdateStrategy::Lazy) {
228 Callbacks.push_back(CallBackOnDeletion(DelBB, Callback));
229 DeletedBBs.insert(DelBB);
230 return;
231 }
232
233 DelBB->removeFromParent();
234 eraseDelBBNode(DelBB);
235 Callback(DelBB);
236 delete DelBB;
237}
238
239void DomTreeUpdater::eraseDelBBNode(BasicBlock *DelBB) {
240 if (DT && !IsRecalculatingDomTree)
241 if (DT->getNode(DelBB))
242 DT->eraseNode(DelBB);
243
244 if (PDT && !IsRecalculatingPostDomTree)
245 if (PDT->getNode(DelBB))
246 PDT->eraseNode(DelBB);
247}
248
249void DomTreeUpdater::validateDeleteBB(BasicBlock *DelBB) {
250 assert(DelBB && "Invalid push_back of nullptr DelBB.");
251 assert(pred_empty(DelBB) && "DelBB has one or more predecessors.");
252 // DelBB is unreachable and all its instructions are dead.
253 while (!DelBB->empty()) {
254 Instruction &I = DelBB->back();
255 // Replace used instructions with an arbitrary value (undef).
256 if (!I.use_empty())
257 I.replaceAllUsesWith(llvm::UndefValue::get(I.getType()));
258 DelBB->getInstList().pop_back();
259 }
260 // Make sure DelBB has a valid terminator instruction. As long as DelBB is a
261 // Child of Function F it must contain valid IR.
262 new UnreachableInst(DelBB->getContext(), DelBB);
263}
264
265void DomTreeUpdater::applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates,
266 bool ForceRemoveDuplicates) {
Chijun Simabc2f48c2018-07-13 04:02:13 +0000267 if (!DT && !PDT)
268 return;
269
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000270 if (Strategy == UpdateStrategy::Lazy || ForceRemoveDuplicates) {
271 SmallVector<DominatorTree::UpdateType, 8> Seen;
272 for (const auto U : Updates)
273 // For Lazy UpdateStrategy, avoid duplicates to applyLazyUpdate() to save
274 // on analysis.
275 if (llvm::none_of(
276 Seen,
277 [U](const DominatorTree::UpdateType S) { return S == U; }) &&
278 isUpdateValid(U) && !isSelfDominance(U)) {
279 Seen.push_back(U);
280 if (Strategy == UpdateStrategy::Lazy)
281 applyLazyUpdate(U.getKind(), U.getFrom(), U.getTo());
282 }
283 if (Strategy == UpdateStrategy::Lazy)
284 return;
285
286 if (DT)
287 DT->applyUpdates(Seen);
288 if (PDT)
289 PDT->applyUpdates(Seen);
290 return;
291 }
292
293 if (DT)
294 DT->applyUpdates(Updates);
295 if (PDT)
296 PDT->applyUpdates(Updates);
297}
298
299DominatorTree &DomTreeUpdater::getDomTree() {
300 assert(DT && "Invalid acquisition of a null DomTree");
301 applyDomTreeUpdates();
302 dropOutOfDateUpdates();
303 return *DT;
304}
305
306PostDominatorTree &DomTreeUpdater::getPostDomTree() {
307 assert(PDT && "Invalid acquisition of a null PostDomTree");
308 applyPostDomTreeUpdates();
309 dropOutOfDateUpdates();
310 return *PDT;
311}
312
313void DomTreeUpdater::insertEdge(BasicBlock *From, BasicBlock *To) {
314
315#ifndef NDEBUG
316 assert(isUpdateValid({DominatorTree::Insert, From, To}) &&
317 "Inserted edge does not appear in the CFG");
318#endif
319
Chijun Simabc2f48c2018-07-13 04:02:13 +0000320 if (!DT && !PDT)
321 return;
322
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000323 // Won't affect DomTree and PostDomTree; discard update.
324 if (From == To)
325 return;
326
327 if (Strategy == UpdateStrategy::Eager) {
328 if (DT)
329 DT->insertEdge(From, To);
330 if (PDT)
331 PDT->insertEdge(From, To);
332 return;
333 }
334
335 applyLazyUpdate(DominatorTree::Insert, From, To);
336}
337
Chijun Simabc2f48c2018-07-13 04:02:13 +0000338void DomTreeUpdater::insertEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000339 if (From == To)
Chijun Simabc2f48c2018-07-13 04:02:13 +0000340 return;
341
342 if (!DT && !PDT)
343 return;
344
345 if (!isUpdateValid({DominatorTree::Insert, From, To}))
346 return;
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000347
348 if (Strategy == UpdateStrategy::Eager) {
349 if (DT)
350 DT->insertEdge(From, To);
351 if (PDT)
352 PDT->insertEdge(From, To);
Chijun Simabc2f48c2018-07-13 04:02:13 +0000353 return;
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000354 }
355
356 applyLazyUpdate(DominatorTree::Insert, From, To);
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000357}
358
359void DomTreeUpdater::deleteEdge(BasicBlock *From, BasicBlock *To) {
360
361#ifndef NDEBUG
362 assert(isUpdateValid({DominatorTree::Delete, From, To}) &&
363 "Deleted edge still exists in the CFG!");
364#endif
365
Chijun Simabc2f48c2018-07-13 04:02:13 +0000366 if (!DT && !PDT)
367 return;
368
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000369 // Won't affect DomTree and PostDomTree; discard update.
370 if (From == To)
371 return;
372
373 if (Strategy == UpdateStrategy::Eager) {
374 if (DT)
375 DT->deleteEdge(From, To);
376 if (PDT)
377 PDT->deleteEdge(From, To);
378 return;
379 }
380
381 applyLazyUpdate(DominatorTree::Delete, From, To);
382}
383
Chijun Simabc2f48c2018-07-13 04:02:13 +0000384void DomTreeUpdater::deleteEdgeRelaxed(BasicBlock *From, BasicBlock *To) {
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000385 if (From == To)
Chijun Simabc2f48c2018-07-13 04:02:13 +0000386 return;
387
388 if (!DT && !PDT)
389 return;
390
391 if (!isUpdateValid({DominatorTree::Delete, From, To}))
392 return;
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000393
394 if (Strategy == UpdateStrategy::Eager) {
395 if (DT)
396 DT->deleteEdge(From, To);
397 if (PDT)
398 PDT->deleteEdge(From, To);
Chijun Simabc2f48c2018-07-13 04:02:13 +0000399 return;
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000400 }
401
402 applyLazyUpdate(DominatorTree::Delete, From, To);
Jakub Kuderski57fa5c92018-07-03 02:06:23 +0000403}
404
405void DomTreeUpdater::dropOutOfDateUpdates() {
406 if (Strategy == DomTreeUpdater::UpdateStrategy::Eager)
407 return;
408
409 tryFlushDeletedBB();
410
411 // Drop all updates applied by both trees.
412 if (!DT)
413 PendDTUpdateIndex = PendUpdates.size();
414 if (!PDT)
415 PendPDTUpdateIndex = PendUpdates.size();
416
417 const size_t dropIndex = std::min(PendDTUpdateIndex, PendPDTUpdateIndex);
418 const auto B = PendUpdates.begin();
419 const auto E = PendUpdates.begin() + dropIndex;
420 assert(B <= E && "Iterator out of range.");
421 PendUpdates.erase(B, E);
422 // Calculate current index.
423 PendDTUpdateIndex -= dropIndex;
424 PendPDTUpdateIndex -= dropIndex;
425}
426
427#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
428LLVM_DUMP_METHOD void DomTreeUpdater::dump() const {
429 raw_ostream &OS = llvm::dbgs();
430
431 OS << "Available Trees: ";
432 if (DT || PDT) {
433 if (DT)
434 OS << "DomTree ";
435 if (PDT)
436 OS << "PostDomTree ";
437 OS << "\n";
438 } else
439 OS << "None\n";
440
441 OS << "UpdateStrategy: ";
442 if (Strategy == UpdateStrategy::Eager) {
443 OS << "Eager\n";
444 return;
445 } else
446 OS << "Lazy\n";
447 int Index = 0;
448
449 auto printUpdates =
450 [&](ArrayRef<DominatorTree::UpdateType>::const_iterator begin,
451 ArrayRef<DominatorTree::UpdateType>::const_iterator end) {
452 if (begin == end)
453 OS << " None\n";
454 Index = 0;
455 for (auto It = begin, ItEnd = end; It != ItEnd; ++It) {
456 auto U = *It;
457 OS << " " << Index << " : ";
458 ++Index;
459 if (U.getKind() == DominatorTree::Insert)
460 OS << "Insert, ";
461 else
462 OS << "Delete, ";
463 BasicBlock *From = U.getFrom();
464 if (From) {
465 auto S = From->getName();
466 if (!From->hasName())
467 S = "(no name)";
468 OS << S << "(" << From << "), ";
469 } else {
470 OS << "(badref), ";
471 }
472 BasicBlock *To = U.getTo();
473 if (To) {
474 auto S = To->getName();
475 if (!To->hasName())
476 S = "(no_name)";
477 OS << S << "(" << To << ")\n";
478 } else {
479 OS << "(badref)\n";
480 }
481 }
482 };
483
484 if (DT) {
485 const auto I = PendUpdates.begin() + PendDTUpdateIndex;
486 assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
487 "Iterator out of range.");
488 OS << "Applied but not cleared DomTreeUpdates:\n";
489 printUpdates(PendUpdates.begin(), I);
490 OS << "Pending DomTreeUpdates:\n";
491 printUpdates(I, PendUpdates.end());
492 }
493
494 if (PDT) {
495 const auto I = PendUpdates.begin() + PendPDTUpdateIndex;
496 assert(PendUpdates.begin() <= I && I <= PendUpdates.end() &&
497 "Iterator out of range.");
498 OS << "Applied but not cleared PostDomTreeUpdates:\n";
499 printUpdates(PendUpdates.begin(), I);
500 OS << "Pending PostDomTreeUpdates:\n";
501 printUpdates(I, PendUpdates.end());
502 }
503
504 OS << "Pending DeletedBBs:\n";
505 Index = 0;
506 for (auto BB : DeletedBBs) {
507 OS << " " << Index << " : ";
508 ++Index;
509 if (BB->hasName())
510 OS << BB->getName() << "(";
511 else
512 OS << "(no_name)(";
513 OS << BB << ")\n";
514 }
515
516 OS << "Pending Callbacks:\n";
517 Index = 0;
518 for (auto BB : Callbacks) {
519 OS << " " << Index << " : ";
520 ++Index;
521 if (BB->hasName())
522 OS << BB->getName() << "(";
523 else
524 OS << "(no_name)(";
525 OS << BB << ")\n";
526 }
527}
528#endif
529} // namespace llvm