1//===- GenericDomTreeUpdaterImpl.h ------------------------------*- C++ -*-===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
9// This file implements the GenericDomTreeUpdater class. This file should only
10// be included by files that implement a specialization of the relevant
11// templates. Currently these are:
12// - llvm/lib/Analysis/DomTreeUpdater.cpp
13// - llvm/lib/CodeGen/MachineDomTreeUpdater.cpp
15//===----------------------------------------------------------------------===//
16#ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
17#define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
26template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
27template <
typename FuncT>
38 // There is little performance gain if we pend the recalculation under
39 // Lazy UpdateStrategy so we recalculate available trees immediately.
41 // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes.
44 // Because all trees are going to be up-to-date after recalculation,
45 // flush awaiting deleted BasicBlocks.
46 derived().forceFlushDeletedBB();
52 // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes.
58template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
66 for (
const auto &U : Updates)
74 DT->applyUpdates(Updates);
76 PDT->applyUpdates(Updates);
79template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
87 for (
const auto &U : Updates) {
88 auto Edge = std::make_pair(U.getFrom(), U.getTo());
89 // Because it is illegal to submit updates that have already been applied
90 // and updates to an edge need to be strictly ordered,
91 // it is safe to infer the existence of an edge from the first update
93 // If the first update to an edge is "Delete", it means that the edge
94 // existed before. If the first update to an edge is "Insert", it means
95 // that the edge didn't exist before.
97 // For example, if the user submits {{Delete, A, B}, {Insert, A, B}},
99 // 1. it is illegal to submit updates that have already been applied,
100 // i.e., user cannot delete an nonexistent edge,
101 // 2. updates to an edge need to be strictly ordered,
102 // So, initially edge A -> B existed.
103 // We can then safely ignore future updates to this edge and directly
104 // inspect the current CFG:
105 // a. If the edge still exists, because the user cannot insert an existent
106 // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and
107 // resulted in a no-op. DTU won't submit any update in this case.
108 // b. If the edge doesn't exist, we can then infer that {Delete, A, B}
109 // actually happened but {Insert, A, B} was an invalid update which never
110 // happened. DTU will submit {Delete, A, B} in this case.
112 // If the update doesn't appear in the CFG, it means that
113 // either the change isn't made or relevant operations
114 // result in a no-op.
128 DT->applyUpdates(DeduplicatedUpdates);
130 PDT->applyUpdates(DeduplicatedUpdates);
133template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
146 splitDTCriticalEdges(
E);
148 splitPDTCriticalEdges(
E);
151template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
154 assert(
DT &&
"Invalid acquisition of a null DomTree");
160template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
163 assert(
PDT &&
"Invalid acquisition of a null PostDomTree");
169template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
172#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
175 OS <<
"Available Trees: ";
180 OS <<
"PostDomTree ";
185 OS <<
"UpdateStrategy: ";
195 auto S = BB->getName();
198 OS << S <<
"(" << BB <<
")" << Ending;
200 OS <<
"(badref)" << Ending;
210 for (
auto It = begin, ItEnd = end; It != ItEnd; ++It) {
211 if (!It->IsCriticalEdgeSplit) {
213 OS <<
" " << Index <<
" : ";
215 if (U.getKind() == DomTreeT::Insert)
219 printBlockInfo(U.getFrom(),
", ");
220 printBlockInfo(U.getTo(),
"\n");
222 const auto &Edge = It->EdgeSplit;
223 OS <<
" " << Index++ <<
" : Split critical edge, ";
224 printBlockInfo(Edge.FromBB,
", ");
225 printBlockInfo(Edge.ToBB,
", ");
226 printBlockInfo(Edge.NewBB,
"\n");
234 "Iterator out of range.");
235 OS <<
"Applied but not cleared DomTreeUpdates:\n";
237 OS <<
"Pending DomTreeUpdates:\n";
244 "Iterator out of range.");
245 OS <<
"Applied but not cleared PostDomTreeUpdates:\n";
247 OS <<
"Pending PostDomTreeUpdates:\n";
251 OS <<
"Pending DeletedBBs:\n";
254 OS <<
" " << Index <<
" : ";
257 OS << BB->getName() <<
"(";
265template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
266template <
bool IsForward>
268 PostDomTreeT>::applyUpdatesImpl() {
269 auto *DomTree = [&]() {
270 if constexpr (IsForward)
275 // No pending DomTreeUpdates.
276 if (Strategy != UpdateStrategy::Lazy || !DomTree)
278 size_t &PendUpdateIndex = IsForward ? PendDTUpdateIndex : PendPDTUpdateIndex;
280 // Only apply updates not are applied by (Post)DomTree.
281 while (IsForward ? hasPendingDomTreeUpdates()
282 : hasPendingPostDomTreeUpdates()) {
283 auto I = PendUpdates.begin() + PendUpdateIndex;
284 const auto E = PendUpdates.end();
285 assert(
I <
E &&
"Iterator range invalid; there should be DomTree updates.");
286 if (!
I->IsCriticalEdgeSplit) {
288 for (;
I !=
E && !
I->IsCriticalEdgeSplit; ++
I)
289 NormalUpdates.push_back(
I->Update);
290 DomTree->applyUpdates(NormalUpdates);
291 PendUpdateIndex += NormalUpdates.size();
294 for (;
I !=
E &&
I->IsCriticalEdgeSplit; ++
I)
296 IsForward ? splitDTCriticalEdges(CriticalEdges)
297 : splitPDTCriticalEdges(CriticalEdges);
298 PendUpdateIndex += CriticalEdges.size();
303template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
306 const auto *From = Update.getFrom();
307 const auto *To = Update.getTo();
308 const auto Kind = Update.getKind();
310 // Discard updates by inspecting the current state of successors of From.
311 // Since isUpdateValid() must be called *after* the Terminator of From is
312 // altered we can determine if the update is unnecessary for batch updates
313 // or invalid for a single update.
316 // If the IR does not match the update,
317 // 1. In batch updates, this update is unnecessary.
318 // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid.
319 // Edge does not exist in IR.
320 if (Kind == DomTreeT::Insert && !HasEdge)
323 // Edge exists in IR.
324 if (Kind == DomTreeT::Delete && HasEdge)
330template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
334 if (
DT->getNode(DelBB))
335 DT->eraseNode(DelBB);
338 if (
PDT->getNode(DelBB))
339 PDT->eraseNode(DelBB);
342template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
346 derived().forceFlushDeletedBB();
349template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
357 // Drop all updates applied by both trees.
366 assert(
B <=
E &&
"Iterator out of range.");
368 // Calculate current index.
373template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
376 // Bail out early if there is nothing to do.
377 if (!DT || Edges.
empty())
380 // Remember all the basic blocks that are inserted during
382 // Invariant: NewBBs == all the basic blocks contained in the NewBB
383 // field of all the elements of Edges.
384 // I.e., forall elt in Edges, it exists BB in NewBBs
385 // such as BB == elt.NewBB.
387 for (
auto &Edge : Edges)
388 NewBBs.
insert(Edge.NewBB);
389 // For each element in Edges, remember whether or not element
390 // is the new immediate domminator of its successor. The mapping is done by
391 // index, i.e., the information for the ith element of Edges is
392 // the ith element of IsNewIDom.
395 // Collect all the dominance properties info, before invalidating
396 // the underlying DT.
397 for (
const auto &[Idx, Edge] :
enumerate(Edges)) {
398 // Update dominator information.
399 BasicBlockT *Succ = Edge.ToBB;
400 auto *SuccDTNode = DT->getNode(Succ);
403 if (PredBB == Edge.NewBB)
405 // If we are in this situation:
410 // ... Split1 Split2 ...
415 // Instead of checking the domiance property with Split2, we check it
416 // with FromBB2 since Split2 is still unknown of the underlying DT
420 "critical edge split has more "
421 "than one predecessor!");
424 if (!DT->dominates(SuccDTNode, DT->getNode(PredBB))) {
425 IsNewIDom[Idx] =
false;
431 // Now, update DT with the collected dominance properties info.
433 // We know FromBB dominates NewBB.
434 auto *NewDTNode = DT->addNewBlock(
Edge.NewBB,
Edge.FromBB);
436 // If all the other predecessors of "Succ" are dominated by "Succ" itself
437 // then the new block is the new immediate dominator of "Succ". Otherwise,
438 // the new block doesn't dominate anything.
440 DT->changeImmediateDominator(DT->getNode(
Edge.ToBB), NewDTNode);
444// Post dominator tree is different, the new basic block in critical edge
445// may become the new root.
446template <
typename DerivedT,
typename DomTreeT,
typename PostDomTreeT>
449 // Bail out early if there is nothing to do.
450 if (!PDT || Edges.empty())
453 std::vector<UpdateT> Updates;
454 for (
const auto &
Edge : Edges) {
455 Updates.push_back({PostDomTreeT::Insert,
Edge.FromBB,
Edge.NewBB});
456 Updates.push_back({PostDomTreeT::Insert,
Edge.NewBB,
Edge.ToBB});
458 Updates.push_back({PostDomTreeT::Delete,
Edge.FromBB,
Edge.ToBB});
465#endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
std::pair< BasicBlock *, BasicBlock * > Edge
This file implements the SmallBitVector class.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
const_pointer const_iterator
size_t size() const
size - Get the array size.
bool empty() const
empty - Check if the array is empty.
SmallPtrSet< BasicBlockT *, 8 > DeletedBBs
DomTreeT & getDomTree()
Flush DomTree updates and return DomTree.
PostDomTreeT & getPostDomTree()
Flush PostDomTree updates and return PostDomTree.
void applyPostDomTreeUpdates()
Helper function to apply all pending PostDomTree updates.
void applyUpdatesPermissive(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
bool IsRecalculatingPostDomTree
void eraseDelBBNode(BasicBlockT *DelBB)
Erase Basic Block node before it is unlinked from Function in the DomTree and PostDomTree.
bool hasPendingUpdates() const
Returns true if either of DT or PDT is valid and the tree has at least one update pending.
bool isSelfDominance(UpdateT Update) const
Returns true if the update is self dominance.
const UpdateStrategy Strategy
typename DomTreeT::UpdateType UpdateT
typename DomTreeT::NodeType BasicBlockT
void recalculate(FuncT &F)
Notify DTU that the entry block was replaced.
void tryFlushDeletedBB()
Helper function to flush deleted BasicBlocks if all available trees are up-to-date.
void dropOutOfDateUpdates()
Drop all updates applied by all available trees and delete BasicBlocks if all available trees are up-...
bool IsRecalculatingDomTree
size_t PendPDTUpdateIndex
void splitCriticalEdge(BasicBlockT *FromBB, BasicBlockT *ToBB, BasicBlockT *NewBB)
Apply updates that the critical edge (FromBB, ToBB) has been split with NewBB.
void applyDomTreeUpdates()
Helper function to apply all pending DomTree updates.
bool isUpdateValid(UpdateT Update) const
Returns true if the update appears in the LLVM IR.
SmallVector< DomTreeUpdate, 16 > PendUpdates
LLVM_DUMP_METHOD void dump() const
Debug method to help view the internal state of this class.
bool isLazy() const
Returns true if the current strategy is Lazy.
This is a 'bitvector' (really, a variable-sized bit array), optimized for the case when the array is ...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
This class implements an extremely fast bulk output stream that can only output to a stream.
This is an optimization pass for GlobalISel generic memory operations.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
auto successors(const MachineBasicBlock *BB)
auto pred_size(const MachineBasicBlock *BB)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto pred_begin(const MachineBasicBlock *BB)
auto predecessors(const MachineBasicBlock *BB)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Helper structure used to hold all the basic blocks involved in the split of a critical edge.