1 | //===- GenericDomTreeUpdaterImpl.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 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 |
14 | // |
15 | //===----------------------------------------------------------------------===// |
16 | #ifndef LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H |
17 | #define LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H |
18 | |
19 | #include "llvm/Analysis/GenericDomTreeUpdater.h" |
20 | #include "llvm/Support/Debug.h" |
21 | #include "llvm/Support/raw_ostream.h" |
22 | |
23 | namespace llvm { |
24 | |
25 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
26 | template <typename FuncT> |
27 | void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::recalculate( |
28 | FuncT &F) { |
29 | if (Strategy == UpdateStrategy::Eager) { |
30 | if (DT) |
31 | DT->recalculate(F); |
32 | if (PDT) |
33 | PDT->recalculate(F); |
34 | return; |
35 | } |
36 | |
37 | // There is little performance gain if we pend the recalculation under |
38 | // Lazy UpdateStrategy so we recalculate available trees immediately. |
39 | |
40 | // Prevent forceFlushDeletedBB() from erasing DomTree or PostDomTree nodes. |
41 | IsRecalculatingDomTree = IsRecalculatingPostDomTree = true; |
42 | |
43 | // Because all trees are going to be up-to-date after recalculation, |
44 | // flush awaiting deleted BasicBlocks. |
45 | derived().forceFlushDeletedBB(); |
46 | if (DT) |
47 | DT->recalculate(F); |
48 | if (PDT) |
49 | PDT->recalculate(F); |
50 | |
51 | // Resume forceFlushDeletedBB() to erase DomTree or PostDomTree nodes. |
52 | IsRecalculatingDomTree = IsRecalculatingPostDomTree = false; |
53 | PendDTUpdateIndex = PendPDTUpdateIndex = PendUpdates.size(); |
54 | dropOutOfDateUpdates(); |
55 | } |
56 | |
57 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
58 | void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::applyUpdates( |
59 | ArrayRef<typename DomTreeT::UpdateType> Updates) { |
60 | if (!DT && !PDT) |
61 | return; |
62 | |
63 | if (Strategy == UpdateStrategy::Lazy) { |
64 | PendUpdates.reserve(PendUpdates.size() + Updates.size()); |
65 | for (const auto &U : Updates) |
66 | if (!isSelfDominance(Update: U)) |
67 | PendUpdates.push_back(U); |
68 | |
69 | return; |
70 | } |
71 | |
72 | if (DT) |
73 | DT->applyUpdates(Updates); |
74 | if (PDT) |
75 | PDT->applyUpdates(Updates); |
76 | } |
77 | |
78 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
79 | void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>:: |
80 | applyUpdatesPermissive(ArrayRef<typename DomTreeT::UpdateType> Updates) { |
81 | if (!DT && !PDT) |
82 | return; |
83 | |
84 | SmallSet<std::pair<BasicBlockT *, BasicBlockT *>, 8> Seen; |
85 | SmallVector<typename DomTreeT::UpdateType, 8> DeduplicatedUpdates; |
86 | for (const auto &U : Updates) { |
87 | auto Edge = std::make_pair(U.getFrom(), U.getTo()); |
88 | // Because it is illegal to submit updates that have already been applied |
89 | // and updates to an edge need to be strictly ordered, |
90 | // it is safe to infer the existence of an edge from the first update |
91 | // to this edge. |
92 | // If the first update to an edge is "Delete", it means that the edge |
93 | // existed before. If the first update to an edge is "Insert", it means |
94 | // that the edge didn't exist before. |
95 | // |
96 | // For example, if the user submits {{Delete, A, B}, {Insert, A, B}}, |
97 | // because |
98 | // 1. it is illegal to submit updates that have already been applied, |
99 | // i.e., user cannot delete an nonexistent edge, |
100 | // 2. updates to an edge need to be strictly ordered, |
101 | // So, initially edge A -> B existed. |
102 | // We can then safely ignore future updates to this edge and directly |
103 | // inspect the current CFG: |
104 | // a. If the edge still exists, because the user cannot insert an existent |
105 | // edge, so both {Delete, A, B}, {Insert, A, B} actually happened and |
106 | // resulted in a no-op. DTU won't submit any update in this case. |
107 | // b. If the edge doesn't exist, we can then infer that {Delete, A, B} |
108 | // actually happened but {Insert, A, B} was an invalid update which never |
109 | // happened. DTU will submit {Delete, A, B} in this case. |
110 | if (!isSelfDominance(Update: U) && Seen.count(Edge) == 0) { |
111 | Seen.insert(Edge); |
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. |
115 | if (isUpdateValid(Update: U)) { |
116 | if (isLazy()) |
117 | PendUpdates.push_back(U); |
118 | else |
119 | DeduplicatedUpdates.push_back(U); |
120 | } |
121 | } |
122 | } |
123 | |
124 | if (Strategy == UpdateStrategy::Lazy) |
125 | return; |
126 | |
127 | if (DT) |
128 | DT->applyUpdates(DeduplicatedUpdates); |
129 | if (PDT) |
130 | PDT->applyUpdates(DeduplicatedUpdates); |
131 | } |
132 | |
133 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
134 | DomTreeT & |
135 | GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getDomTree() { |
136 | assert(DT && "Invalid acquisition of a null DomTree" ); |
137 | applyDomTreeUpdates(); |
138 | dropOutOfDateUpdates(); |
139 | return *DT; |
140 | } |
141 | |
142 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
143 | PostDomTreeT & |
144 | GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::getPostDomTree() { |
145 | assert(PDT && "Invalid acquisition of a null PostDomTree" ); |
146 | applyPostDomTreeUpdates(); |
147 | dropOutOfDateUpdates(); |
148 | return *PDT; |
149 | } |
150 | |
151 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
152 | LLVM_DUMP_METHOD void |
153 | GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::dump() const { |
154 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
155 | raw_ostream &OS = llvm::dbgs(); |
156 | |
157 | OS << "Available Trees: " ; |
158 | if (DT || PDT) { |
159 | if (DT) |
160 | OS << "DomTree " ; |
161 | if (PDT) |
162 | OS << "PostDomTree " ; |
163 | OS << "\n" ; |
164 | } else |
165 | OS << "None\n" ; |
166 | |
167 | OS << "UpdateStrategy: " ; |
168 | if (Strategy == UpdateStrategy::Eager) { |
169 | OS << "Eager\n" ; |
170 | return; |
171 | } else |
172 | OS << "Lazy\n" ; |
173 | int Index = 0; |
174 | |
175 | auto printUpdates = |
176 | [&](typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator |
177 | begin, |
178 | typename ArrayRef<typename DomTreeT::UpdateType>::const_iterator |
179 | end) { |
180 | if (begin == end) |
181 | OS << " None\n" ; |
182 | Index = 0; |
183 | for (auto It = begin, ItEnd = end; It != ItEnd; ++It) { |
184 | auto U = *It; |
185 | OS << " " << Index << " : " ; |
186 | ++Index; |
187 | if (U.getKind() == DomTreeT::Insert) |
188 | OS << "Insert, " ; |
189 | else |
190 | OS << "Delete, " ; |
191 | BasicBlockT *From = U.getFrom(); |
192 | if (From) { |
193 | auto S = From->getName(); |
194 | if (!From->hasName()) |
195 | S = "(no name)" ; |
196 | OS << S << "(" << From << "), " ; |
197 | } else { |
198 | OS << "(badref), " ; |
199 | } |
200 | BasicBlockT *To = U.getTo(); |
201 | if (To) { |
202 | auto S = To->getName(); |
203 | if (!To->hasName()) |
204 | S = "(no_name)" ; |
205 | OS << S << "(" << To << ")\n" ; |
206 | } else { |
207 | OS << "(badref)\n" ; |
208 | } |
209 | } |
210 | }; |
211 | |
212 | if (DT) { |
213 | const auto I = PendUpdates.begin() + PendDTUpdateIndex; |
214 | assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && |
215 | "Iterator out of range." ); |
216 | OS << "Applied but not cleared DomTreeUpdates:\n" ; |
217 | printUpdates(PendUpdates.begin(), I); |
218 | OS << "Pending DomTreeUpdates:\n" ; |
219 | printUpdates(I, PendUpdates.end()); |
220 | } |
221 | |
222 | if (PDT) { |
223 | const auto I = PendUpdates.begin() + PendPDTUpdateIndex; |
224 | assert(PendUpdates.begin() <= I && I <= PendUpdates.end() && |
225 | "Iterator out of range." ); |
226 | OS << "Applied but not cleared PostDomTreeUpdates:\n" ; |
227 | printUpdates(PendUpdates.begin(), I); |
228 | OS << "Pending PostDomTreeUpdates:\n" ; |
229 | printUpdates(I, PendUpdates.end()); |
230 | } |
231 | |
232 | OS << "Pending DeletedBBs:\n" ; |
233 | Index = 0; |
234 | for (const auto *BB : DeletedBBs) { |
235 | OS << " " << Index << " : " ; |
236 | ++Index; |
237 | if (BB->hasName()) |
238 | OS << BB->getName() << "(" ; |
239 | else |
240 | OS << "(no_name)(" ; |
241 | OS << BB << ")\n" ; |
242 | } |
243 | #endif |
244 | } |
245 | |
246 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
247 | void GenericDomTreeUpdater<DerivedT, DomTreeT, |
248 | PostDomTreeT>::applyDomTreeUpdates() { |
249 | // No pending DomTreeUpdates. |
250 | if (Strategy != UpdateStrategy::Lazy || !DT) |
251 | return; |
252 | |
253 | // Only apply updates not are applied by DomTree. |
254 | if (hasPendingDomTreeUpdates()) { |
255 | const auto I = PendUpdates.begin() + PendDTUpdateIndex; |
256 | const auto E = PendUpdates.end(); |
257 | assert(I < E && "Iterator range invalid; there should be DomTree updates." ); |
258 | DT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E)); |
259 | PendDTUpdateIndex = PendUpdates.size(); |
260 | } |
261 | } |
262 | |
263 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
264 | void GenericDomTreeUpdater<DerivedT, DomTreeT, |
265 | PostDomTreeT>::applyPostDomTreeUpdates() { |
266 | // No pending PostDomTreeUpdates. |
267 | if (Strategy != UpdateStrategy::Lazy || !PDT) |
268 | return; |
269 | |
270 | // Only apply updates not are applied by PostDomTree. |
271 | if (hasPendingPostDomTreeUpdates()) { |
272 | const auto I = PendUpdates.begin() + PendPDTUpdateIndex; |
273 | const auto E = PendUpdates.end(); |
274 | assert(I < E && |
275 | "Iterator range invalid; there should be PostDomTree updates." ); |
276 | PDT->applyUpdates(ArrayRef<typename DomTreeT::UpdateType>(I, E)); |
277 | PendPDTUpdateIndex = PendUpdates.size(); |
278 | } |
279 | } |
280 | |
281 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
282 | bool GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::isUpdateValid( |
283 | typename DomTreeT::UpdateType Update) const { |
284 | const auto *From = Update.getFrom(); |
285 | const auto *To = Update.getTo(); |
286 | const auto Kind = Update.getKind(); |
287 | |
288 | // Discard updates by inspecting the current state of successors of From. |
289 | // Since isUpdateValid() must be called *after* the Terminator of From is |
290 | // altered we can determine if the update is unnecessary for batch updates |
291 | // or invalid for a single update. |
292 | const bool HasEdge = llvm::is_contained(successors(From), To); |
293 | |
294 | // If the IR does not match the update, |
295 | // 1. In batch updates, this update is unnecessary. |
296 | // 2. When called by insertEdge*()/deleteEdge*(), this update is invalid. |
297 | // Edge does not exist in IR. |
298 | if (Kind == DomTreeT::Insert && !HasEdge) |
299 | return false; |
300 | |
301 | // Edge exists in IR. |
302 | if (Kind == DomTreeT::Delete && HasEdge) |
303 | return false; |
304 | |
305 | return true; |
306 | } |
307 | |
308 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
309 | void GenericDomTreeUpdater<DerivedT, DomTreeT, PostDomTreeT>::eraseDelBBNode( |
310 | BasicBlockT *DelBB) { |
311 | if (DT && !IsRecalculatingDomTree) |
312 | if (DT->getNode(DelBB)) |
313 | DT->eraseNode(DelBB); |
314 | |
315 | if (PDT && !IsRecalculatingPostDomTree) |
316 | if (PDT->getNode(DelBB)) |
317 | PDT->eraseNode(DelBB); |
318 | } |
319 | |
320 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
321 | void GenericDomTreeUpdater<DerivedT, DomTreeT, |
322 | PostDomTreeT>::tryFlushDeletedBB() { |
323 | if (!hasPendingUpdates()) |
324 | derived().forceFlushDeletedBB(); |
325 | } |
326 | |
327 | template <typename DerivedT, typename DomTreeT, typename PostDomTreeT> |
328 | void GenericDomTreeUpdater<DerivedT, DomTreeT, |
329 | PostDomTreeT>::dropOutOfDateUpdates() { |
330 | if (Strategy == UpdateStrategy::Eager) |
331 | return; |
332 | |
333 | tryFlushDeletedBB(); |
334 | |
335 | // Drop all updates applied by both trees. |
336 | if (!DT) |
337 | PendDTUpdateIndex = PendUpdates.size(); |
338 | if (!PDT) |
339 | PendPDTUpdateIndex = PendUpdates.size(); |
340 | |
341 | const size_t dropIndex = std::min(a: PendDTUpdateIndex, b: PendPDTUpdateIndex); |
342 | const auto B = PendUpdates.begin(); |
343 | const auto E = PendUpdates.begin() + dropIndex; |
344 | assert(B <= E && "Iterator out of range." ); |
345 | PendUpdates.erase(B, E); |
346 | // Calculate current index. |
347 | PendDTUpdateIndex -= dropIndex; |
348 | PendPDTUpdateIndex -= dropIndex; |
349 | } |
350 | |
351 | } // namespace llvm |
352 | |
353 | #endif // LLVM_ANALYSIS_GENERICDOMTREEUPDATERIMPL_H |
354 | |