1 //===- GenericDomTreeUpdater.h ----------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the GenericDomTreeUpdater class, which provides a uniform
10 // way to update dominator tree related data structures.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
15 #define LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
16 
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/Support/Compiler.h"
20 
21 namespace llvm {
22 
23 template <typename DerivedT, typename DomTreeT, typename PostDomTreeT>
24 class GenericDomTreeUpdater {
derived()25   DerivedT &derived() { return *static_cast<DerivedT *>(this); }
derived()26   const DerivedT &derived() const {
27     return *static_cast<const DerivedT *>(this);
28   }
29 
30 public:
31   enum class UpdateStrategy : unsigned char { Eager = 0, Lazy = 1 };
32   using BasicBlockT = typename DomTreeT::NodeType;
33 
GenericDomTreeUpdater(UpdateStrategy Strategy_)34   explicit GenericDomTreeUpdater(UpdateStrategy Strategy_)
35       : Strategy(Strategy_) {}
GenericDomTreeUpdater(DomTreeT & DT_,UpdateStrategy Strategy_)36   GenericDomTreeUpdater(DomTreeT &DT_, UpdateStrategy Strategy_)
37       : DT(&DT_), Strategy(Strategy_) {}
GenericDomTreeUpdater(DomTreeT * DT_,UpdateStrategy Strategy_)38   GenericDomTreeUpdater(DomTreeT *DT_, UpdateStrategy Strategy_)
39       : DT(DT_), Strategy(Strategy_) {}
GenericDomTreeUpdater(PostDomTreeT & PDT_,UpdateStrategy Strategy_)40   GenericDomTreeUpdater(PostDomTreeT &PDT_, UpdateStrategy Strategy_)
41       : PDT(&PDT_), Strategy(Strategy_) {}
GenericDomTreeUpdater(PostDomTreeT * PDT_,UpdateStrategy Strategy_)42   GenericDomTreeUpdater(PostDomTreeT *PDT_, UpdateStrategy Strategy_)
43       : PDT(PDT_), Strategy(Strategy_) {}
GenericDomTreeUpdater(DomTreeT & DT_,PostDomTreeT & PDT_,UpdateStrategy Strategy_)44   GenericDomTreeUpdater(DomTreeT &DT_, PostDomTreeT &PDT_,
45                         UpdateStrategy Strategy_)
46       : DT(&DT_), PDT(&PDT_), Strategy(Strategy_) {}
GenericDomTreeUpdater(DomTreeT * DT_,PostDomTreeT * PDT_,UpdateStrategy Strategy_)47   GenericDomTreeUpdater(DomTreeT *DT_, PostDomTreeT *PDT_,
48                         UpdateStrategy Strategy_)
49       : DT(DT_), PDT(PDT_), Strategy(Strategy_) {}
50 
~GenericDomTreeUpdater()51   ~GenericDomTreeUpdater() {
52     // We cannot call into derived() here as it will already be destroyed.
53     assert(!hasPendingUpdates() &&
54            "Pending updates were not flushed by derived class.");
55   }
56 
57   /// Returns true if the current strategy is Lazy.
isLazy()58   bool isLazy() const { return Strategy == UpdateStrategy::Lazy; }
59 
60   /// Returns true if the current strategy is Eager.
isEager()61   bool isEager() const { return Strategy == UpdateStrategy::Eager; }
62 
63   /// Returns true if it holds a DomTreeT.
hasDomTree()64   bool hasDomTree() const { return DT != nullptr; }
65 
66   /// Returns true if it holds a PostDomTreeT.
hasPostDomTree()67   bool hasPostDomTree() const { return PDT != nullptr; }
68 
69   /// Returns true if there is BasicBlockT awaiting deletion.
70   /// The deletion will only happen until a flush event and
71   /// all available trees are up-to-date.
72   /// Returns false under Eager UpdateStrategy.
hasPendingDeletedBB()73   bool hasPendingDeletedBB() const { return !DeletedBBs.empty(); }
74 
75   /// Returns true if DelBB is awaiting deletion.
76   /// Returns false under Eager UpdateStrategy.
isBBPendingDeletion(BasicBlockT * DelBB)77   bool isBBPendingDeletion(BasicBlockT *DelBB) const {
78     if (Strategy == UpdateStrategy::Eager || DeletedBBs.empty())
79       return false;
80     return DeletedBBs.contains(DelBB);
81   }
82 
83   /// Returns true if either of DT or PDT is valid and the tree has at
84   /// least one update pending. If DT or PDT is nullptr it is treated
85   /// as having no pending updates. This function does not check
86   /// whether there is MachineBasicBlock awaiting deletion.
87   /// Returns false under Eager UpdateStrategy.
hasPendingUpdates()88   bool hasPendingUpdates() const {
89     return hasPendingDomTreeUpdates() || hasPendingPostDomTreeUpdates();
90   }
91 
92   /// Returns true if there are DomTreeT updates queued.
93   /// Returns false under Eager UpdateStrategy or DT is nullptr.
hasPendingDomTreeUpdates()94   bool hasPendingDomTreeUpdates() const {
95     if (!DT)
96       return false;
97     return PendUpdates.size() != PendDTUpdateIndex;
98   }
99 
100   /// Returns true if there are PostDomTreeT updates queued.
101   /// Returns false under Eager UpdateStrategy or PDT is nullptr.
hasPendingPostDomTreeUpdates()102   bool hasPendingPostDomTreeUpdates() const {
103     if (!PDT)
104       return false;
105     return PendUpdates.size() != PendPDTUpdateIndex;
106   }
107 
108   ///@{
109   /// \name Mutation APIs
110   ///
111   /// These methods provide APIs for submitting updates to the DomTreeT and
112   /// the PostDominatorTree.
113   ///
114   /// Note: There are two strategies to update the DomTreeT and the
115   /// PostDominatorTree:
116   /// 1. Eager UpdateStrategy: Updates are submitted and then flushed
117   /// immediately.
118   /// 2. Lazy UpdateStrategy: Updates are submitted but only flushed when you
119   /// explicitly call Flush APIs. It is recommended to use this update strategy
120   /// when you submit a bunch of updates multiple times which can then
121   /// add up to a large number of updates between two queries on the
122   /// DomTreeT. The incremental updater can reschedule the updates or
123   /// decide to recalculate the dominator tree in order to speedup the updating
124   /// process depending on the number of updates.
125   ///
126   /// Although GenericDomTree provides several update primitives,
127   /// it is not encouraged to use these APIs directly.
128 
129   /// Notify DTU that the entry block was replaced.
130   /// Recalculate all available trees and flush all BasicBlocks
131   /// awaiting deletion immediately.
132   template <typename FuncT> void recalculate(FuncT &F);
133 
134   /// Submit updates to all available trees.
135   /// The Eager Strategy flushes updates immediately while the Lazy Strategy
136   /// queues the updates.
137   ///
138   /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
139   /// in sync with + all updates before that single update.
140   ///
141   /// CAUTION!
142   /// 1. It is required for the state of the LLVM IR to be updated
143   /// *before* submitting the updates because the internal update routine will
144   /// analyze the current state of the CFG to determine whether an update
145   /// is valid.
146   /// 2. It is illegal to submit any update that has already been submitted,
147   /// i.e., you are supposed not to insert an existent edge or delete a
148   /// nonexistent edge.
149   void applyUpdates(ArrayRef<typename DomTreeT::UpdateType> Updates);
150 
151   /// Submit updates to all available trees. It will also
152   /// 1. discard duplicated updates,
153   /// 2. remove invalid updates. (Invalid updates means deletion of an edge that
154   /// still exists or insertion of an edge that does not exist.)
155   /// The Eager Strategy flushes updates immediately while the Lazy Strategy
156   /// queues the updates.
157   ///
158   /// Note: The "existence" of an edge in a CFG refers to the CFG which DTU is
159   /// in sync with + all updates before that single update.
160   ///
161   /// CAUTION!
162   /// 1. It is required for the state of the LLVM IR to be updated
163   /// *before* submitting the updates because the internal update routine will
164   /// analyze the current state of the CFG to determine whether an update
165   /// is valid.
166   /// 2. It is illegal to submit any update that has already been submitted,
167   /// i.e., you are supposed not to insert an existent edge or delete a
168   /// nonexistent edge.
169   /// 3. It is only legal to submit updates to an edge in the order CFG changes
170   /// are made. The order you submit updates on different edges is not
171   /// restricted.
172   void applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates);
173 
174   ///@}
175 
176   ///@{
177   /// \name Flush APIs
178   ///
179   /// CAUTION! By the moment these flush APIs are called, the current CFG needs
180   /// to be the same as the CFG which DTU is in sync with + all updates
181   /// submitted.
182 
183   /// Flush DomTree updates and return DomTree.
184   /// It flushes Deleted BBs if both trees are up-to-date.
185   /// It must only be called when it has a DomTree.
186   DomTreeT &getDomTree();
187 
188   /// Flush PostDomTree updates and return PostDomTree.
189   /// It flushes Deleted BBs if both trees are up-to-date.
190   /// It must only be called when it has a PostDomTree.
191   PostDomTreeT &getPostDomTree();
192 
193   /// Apply all pending updates to available trees and flush all BasicBlocks
194   /// awaiting deletion.
195 
flush()196   void flush() {
197     applyDomTreeUpdates();
198     applyPostDomTreeUpdates();
199     dropOutOfDateUpdates();
200   }
201 
202   ///@}
203 
204   /// Debug method to help view the internal state of this class.
205   LLVM_DUMP_METHOD void dump() const;
206 
207 protected:
208   SmallVector<typename DomTreeT::UpdateType, 16> PendUpdates;
209   size_t PendDTUpdateIndex = 0;
210   size_t PendPDTUpdateIndex = 0;
211   DomTreeT *DT = nullptr;
212   PostDomTreeT *PDT = nullptr;
213   const UpdateStrategy Strategy;
214   SmallPtrSet<BasicBlockT *, 8> DeletedBBs;
215   bool IsRecalculatingDomTree = false;
216   bool IsRecalculatingPostDomTree = false;
217 
218   /// Returns true if the update is self dominance.
isSelfDominance(typename DomTreeT::UpdateType Update)219   bool isSelfDominance(typename DomTreeT::UpdateType Update) const {
220     // Won't affect DomTree and PostDomTree.
221     return Update.getFrom() == Update.getTo();
222   }
223 
224   /// Helper function to apply all pending DomTree updates.
225   void applyDomTreeUpdates();
226 
227   /// Helper function to apply all pending PostDomTree updates.
228   void applyPostDomTreeUpdates();
229 
230   /// Returns true if the update appears in the LLVM IR.
231   /// It is used to check whether an update is valid in
232   /// insertEdge/deleteEdge or is unnecessary in the batch update.
233   bool isUpdateValid(typename DomTreeT::UpdateType Update) const;
234 
235   /// Erase Basic Block node that has been unlinked from Function
236   /// in the DomTree and PostDomTree.
237   void eraseDelBBNode(BasicBlockT *DelBB);
238 
239   /// Helper function to flush deleted BasicBlocks if all available
240   /// trees are up-to-date.
241   void tryFlushDeletedBB();
242 
243   /// Drop all updates applied by all available trees and delete BasicBlocks if
244   /// all available trees are up-to-date.
245   void dropOutOfDateUpdates();
246 };
247 
248 } // namespace llvm
249 
250 #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATER_H
251