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