llvm.org GIT mirror llvm / 0fc4467
[PM] Introduce the facilities for registering cross-IR-unit dependencies that require deferred invalidation. This handles the other real-world invalidation scenario that we have cases of: a function analysis which caches references to a module analysis. We currently do this in the AA aggregation layer and might well do this in other places as well. Since this is relative rare, the technique is somewhat more cumbersome. Analyses need to register themselves when accessing the outer analysis manager's proxy. This proxy is already necessarily present to allow access to the outer IR unit's analyses. By registering here we can track and trigger invalidation when that outer analysis goes away. To make this work we need to enhance the PreservedAnalyses infrastructure to support a (slightly) more explicit model for "sets" of analyses, and allow abandoning a single specific analyses even when a set covering that analysis is preserved. That allows us to describe the scenario of preserving all Function analyses *except* for the one where deferred invalidation has triggered. We also need to teach the invalidator API to support direct ID calls instead of always going through a template to dispatch so that we can just record the ID mapping. I've introduced testing of all of this both for simple module<->function cases as well as for more complex cases involving a CGSCC layer. Much like the previous patch I've not tried to fully update the loop pass management layer because that layer is due to be heavily reworked to use similar techniques to the CGSCC to handle updates. As that happens, we'll have a better testing basis for adding support like this. Many thanks to both Justin and Sean for the extensive reviews on this to help bring the API design and documentation into a better state. Differential Revision: https://reviews.llvm.org/D27198 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290594 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 2 years ago
9 changed file(s) with 961 addition(s) and 142 deletion(s). Raw diff Collapse all Expand all
435435
436436 // By definition we preserve the call garph, all SCC analyses, and the
437437 // analysis proxies by handling them above and in any nested pass managers.
438 PA.preserveSet>();
438439 PA.preserve();
439 PA.preserve>();
440440 PA.preserve();
441441 PA.preserve();
442442 return PA;
584584 // Functions. This precludes *any* invalidation of function analyses by the
585585 // proxy, but that's OK because we've taken care to invalidate analyses in
586586 // the function analysis manager incrementally above.
587 PA.preserve>();
587 PA.preserveSet>();
588588 PA.preserve();
589589
590590 // We've also ensured that we updated the call graph along the way.
110110 // post-order.
111111 for (auto *L : reverse(Loops)) {
112112 PreservedAnalyses PassPA = Pass.run(*L, LAM);
113 assert(PassPA.preserved(getLoopPassPreservedAnalyses()) &&
114 "Loop passes must preserve all relevant analyses");
113 // FIXME: We should verify the set of analyses relevant to Loop passes
114 // are preserved.
115115
116116 // We know that the loop pass couldn't have invalidated any other loop's
117117 // analyses (that's the contract of a loop pass), so directly handle the
127127 // Loops. This precludes *any* invalidation of loop analyses by the proxy,
128128 // but that's OK because we've taken care to invalidate analyses in the
129129 // loop analysis manager incrementally above.
130 PA.preserve>();
130 PA.preserveSet>();
131131 PA.preserve();
132132 return PA;
133133 }
4040 #include "llvm/ADT/DenseMap.h"
4141 #include "llvm/ADT/STLExtras.h"
4242 #include "llvm/ADT/SmallPtrSet.h"
43 #include "llvm/ADT/TinyPtrVector.h"
4344 #include "llvm/IR/Function.h"
4445 #include "llvm/IR/Module.h"
4546 #include "llvm/IR/PassManagerInternal.h"
6162 /// the analysis in the pass management infrastructure.
6263 struct alignas(8) AnalysisKey {};
6364
64 /// \brief An abstract set of preserved analyses following a transformation pass
65 /// run.
66 ///
67 /// When a transformation pass is run, it can return a set of analyses whose
68 /// results were preserved by that transformation. The default set is "none",
69 /// and preserving analyses must be done explicitly.
70 ///
71 /// There is also an explicit all state which can be used (for example) when
72 /// the IR is not mutated at all.
65 /// A special type used to provide an address that identifies a set of related
66 /// analyses.
67 ///
68 /// These sets are primarily used below to mark sets of analyses as preserved.
69 /// An example would be analyses depending only on the CFG of a function.
70 /// A transformation can mark that it is preserving the CFG of a function and
71 /// then analyses can check for this rather than each transform having to fully
72 /// enumerate every analysis preserved.
73 struct alignas(8) AnalysisSetKey {};
74
75 /// Class for tracking what analyses are preserved after a transformation pass
76 /// runs over some unit of IR.
77 ///
78 /// Transformation passes build and return these objects when run over the IR
79 /// to communicate which analyses remain valid afterward. For most passes this
80 /// is fairly simple: if they don't change anything all analyses are preserved,
81 /// otherwise only a short list of analyses that have been explicitly updated
82 /// are preserved.
83 ///
84 /// This class also provides the ability to mark abstract *sets* of analyses as
85 /// preserved. These sets allow passes to indicate that they preserve broad
86 /// aspects of the IR (such as its CFG) and analyses to opt in to that being
87 /// sufficient without the passes having to fully enumerate such analyses.
88 ///
89 /// Finally, this class can represent "abandoning" an analysis, which marks it
90 /// as not-preserved even if it would be covered by some abstract set of
91 /// analyses.
92 ///
93 /// Given a `PreservedAnalyses` object, an analysis will typically want to
94 /// figure out whether it is preserved. In the example below, MyAnalysisType is
95 /// preserved if it's not abandoned, and (a) it's explicitly marked as
96 /// preserved, (b), the set AllAnalysesOn is preserved, or (c) both
97 /// AnalysisSetA and AnalysisSetB are preserved.
98 ///
99 /// ```
100 /// auto PAC = PA.getChecker();
101 /// if (PAC.preserved() || PAC.preservedSet>() ||
102 /// (PAC.preservedSet() &&
103 /// PAC.preservedSet())) {
104 /// // The analysis has been successfully preserved ...
105 /// }
106 /// ```
73107 class PreservedAnalyses {
74108 public:
75109 /// \brief Convenience factory function for the empty preserved set.
78112 /// \brief Construct a special preserved set that preserves all passes.
79113 static PreservedAnalyses all() {
80114 PreservedAnalyses PA;
81 PA.PreservedAnalysisIDs.insert(&AllAnalysesKey);
115 PA.PreservedIDs.insert(&AllAnalysesKey);
82116 return PA;
83117 }
84118
85 /// \brief Mark a particular pass as preserved, adding it to the set.
86 template void preserve() { preserve(PassT::ID()); }
87
88 /// \brief Mark an abstract ID as preserved, adding it to the set.
119 /// Mark an analysis as preserved.
120 template void preserve() { preserve(AnalysisT::ID()); }
121
122 /// Mark an analysis as preserved using its ID.
89123 void preserve(AnalysisKey *ID) {
124 // Clear this ID from the explicit not-preserved set if present.
125 NotPreservedAnalysisIDs.erase(ID);
126
127 // If we're not already preserving all analyses (other than those in
128 // NotPreservedAnalysisIDs).
90129 if (!areAllPreserved())
91 PreservedAnalysisIDs.insert(ID);
130 PreservedIDs.insert(ID);
131 }
132
133 /// Mark an analysis set as preserved.
134 template void preserveSet() {
135 preserveSet(AnalysisSetT::ID());
136 }
137
138 /// Mark an analysis set as preserved using its ID.
139 void preserveSet(AnalysisSetKey *ID) {
140 // If we're not already in the saturated 'all' state, add this set.
141 if (!areAllPreserved())
142 PreservedIDs.insert(ID);
143 }
144
145 /// Mark an analysis as abandoned.
146 ///
147 /// An abandoned analysis is not preserved, even if it is nominally covered
148 /// by some other set or was previously explicitly marked as preserved.
149 ///
150 /// Note that you can only abandon a specific analysis, not a *set* of
151 /// analyses.
152 template void abandon() { abandon(AnalysisT::ID()); }
153
154 /// Mark an analysis as abandoned using its ID.
155 ///
156 /// An abandoned analysis is not preserved, even if it is nominally covered
157 /// by some other set or was previously explicitly marked as preserved.
158 ///
159 /// Note that you can only abandon a specific analysis, not a *set* of
160 /// analyses.
161 void abandon(AnalysisKey *ID) {
162 PreservedIDs.erase(ID);
163 NotPreservedAnalysisIDs.insert(ID);
92164 }
93165
94166 /// \brief Intersect this set with another in place.
99171 if (Arg.areAllPreserved())
100172 return;
101173 if (areAllPreserved()) {
102 PreservedAnalysisIDs = Arg.PreservedAnalysisIDs;
174 *this = Arg;
103175 return;
104176 }
105 for (auto ID : PreservedAnalysisIDs)
106 if (!Arg.PreservedAnalysisIDs.count(ID))
107 PreservedAnalysisIDs.erase(ID);
177 // The intersection requires the *union* of the explicitly not-preserved
178 // IDs and the *intersection* of the preserved IDs.
179 for (auto ID : Arg.NotPreservedAnalysisIDs) {
180 PreservedIDs.erase(ID);
181 NotPreservedAnalysisIDs.insert(ID);
182 }
183 for (auto ID : PreservedIDs)
184 if (!Arg.PreservedIDs.count(ID))
185 PreservedIDs.erase(ID);
108186 }
109187
110188 /// \brief Intersect this set with a temporary other set in place.
115193 if (Arg.areAllPreserved())
116194 return;
117195 if (areAllPreserved()) {
118 PreservedAnalysisIDs = std::move(Arg.PreservedAnalysisIDs);
196 *this = std::move(Arg);
119197 return;
120198 }
121 for (auto ID : PreservedAnalysisIDs)
122 if (!Arg.PreservedAnalysisIDs.count(ID))
123 PreservedAnalysisIDs.erase(ID);
124 }
125
126 /// \brief Query whether a pass is marked as preserved by this set.
127 template bool preserved() const {
128 return preserved(PassT::ID());
129 }
130
131 /// \brief Query whether an abstract pass ID is marked as preserved by this
132 /// set.
133 bool preserved(AnalysisKey *ID) const {
134 return PreservedAnalysisIDs.count(&AllAnalysesKey) ||
135 PreservedAnalysisIDs.count(ID);
136 }
137
138 /// \brief Query whether all of the analyses in the set are preserved.
139 bool preserved(const PreservedAnalyses& Arg) {
140 if (Arg.areAllPreserved())
141 return areAllPreserved();
142 for (auto ID : Arg.PreservedAnalysisIDs)
143 if (!preserved(ID))
144 return false;
145 return true;
146 }
147
148 /// \brief Test whether all passes are preserved.
149 ///
150 /// This is used primarily to optimize for the case of no changes which will
151 /// common in many scenarios.
199 // The intersection requires the *union* of the explicitly not-preserved
200 // IDs and the *intersection* of the preserved IDs.
201 for (auto ID : Arg.NotPreservedAnalysisIDs) {
202 PreservedIDs.erase(ID);
203 NotPreservedAnalysisIDs.insert(ID);
204 }
205 for (auto ID : PreservedIDs)
206 if (!Arg.PreservedIDs.count(ID))
207 PreservedIDs.erase(ID);
208 }
209
210 /// A checker object that makes it easy to query for whether an analysis or
211 /// some set covering it is preserved.
212 class PreservedAnalysisChecker {
213 friend class PreservedAnalyses;
214
215 const PreservedAnalyses &PA;
216 AnalysisKey *const ID;
217 const bool IsAbandoned;
218
219 /// A PreservedAnalysisChecker is tied to a particular Analysis because
220 /// `preserved()` and `preservedSet()` both return false if the Analysis
221 /// was abandoned.
222 PreservedAnalysisChecker(const PreservedAnalyses &PA, AnalysisKey *ID)
223 : PA(PA), ID(ID), IsAbandoned(PA.NotPreservedAnalysisIDs.count(ID)) {}
224
225 public:
226 /// Returns true if the checker's analysis was not abandoned and the
227 /// analysis is either is explicitly preserved or all analyses are
228 /// preserved.
229 bool preserved() {
230 return !IsAbandoned && (PA.PreservedIDs.count(&AllAnalysesKey) ||
231 PA.PreservedIDs.count(ID));
232 }
233
234 /// Returns true if the checker's analysis was not abandoned and either the
235 /// provided set type is either explicitly preserved or all analyses are
236 /// preserved.
237 template bool preservedSet() {
238 AnalysisSetKey *SetID = AnalysisSetT::ID();
239 return !IsAbandoned && (PA.PreservedIDs.count(&AllAnalysesKey) ||
240 PA.PreservedIDs.count(SetID));
241 }
242 };
243
244 /// Build a checker for this `PreservedAnalyses` and the specified analysis
245 /// type.
246 ///
247 /// You can use the returned object to query whether an analysis was
248 /// preserved. See the example in the comment on `PreservedAnalysis`.
249 template PreservedAnalysisChecker getChecker() const {
250 return PreservedAnalysisChecker(*this, AnalysisT::ID());
251 }
252
253 /// Build a checker for this `PreservedAnalyses` and the specified analysis
254 /// ID.
255 ///
256 /// You can use the returned object to query whether an analysis was
257 /// preserved. See the example in the comment on `PreservedAnalysis`.
258 PreservedAnalysisChecker getChecker(AnalysisKey *ID) const {
259 return PreservedAnalysisChecker(*this, ID);
260 }
261
262 /// Test whether all analyses are preserved (and none are abandoned).
263 ///
264 /// This lets analyses optimize for the common case where a transformation
265 /// made no changes to the IR.
152266 bool areAllPreserved() const {
153 return PreservedAnalysisIDs.count(&AllAnalysesKey);
267 return NotPreservedAnalysisIDs.empty() &&
268 PreservedIDs.count(&AllAnalysesKey);
269 }
270
271 /// Directly test whether a set of analyses is preserved.
272 ///
273 /// This is only true when no analyses have been explicitly abandoned.
274 template bool allAnalysesInSetPreserved() const {
275 return allAnalysesInSetPreserved(AnalysisSetT::ID());
276 }
277
278 /// Directly test whether a set of analyses is preserved.
279 ///
280 /// This is only true when no analyses have been explicitly abandoned.
281 bool allAnalysesInSetPreserved(AnalysisSetKey *SetID) const {
282 return NotPreservedAnalysisIDs.empty() &&
283 (PreservedIDs.count(&AllAnalysesKey) || PreservedIDs.count(SetID));
154284 }
155285
156286 private:
157 // A special key used to indicate all analyses.
158 static AnalysisKey AllAnalysesKey;
159
160 SmallPtrSet PreservedAnalysisIDs;
287 /// A special key used to indicate all analyses.
288 static AnalysisSetKey AllAnalysesKey;
289
290 /// The IDs of analyses and analysis sets that are preserved.
291 SmallPtrSet PreservedIDs;
292
293 /// The IDs of explicitly not-preserved analyses.
294 ///
295 /// If an analysis in this set is covered by a set in `PreservedIDs`, we
296 /// consider it not-preserved. That is, `NotPreservedAnalysisIDs` always
297 /// "wins" over analysis sets in `PreservedIDs`.
298 ///
299 /// Also, a given ID should never occur both here and in `PreservedIDs`.
300 SmallPtrSet NotPreservedAnalysisIDs;
161301 };
162302
163303 // Forward declare the analysis manager template.
219359 template
220360 class AllAnalysesOn {
221361 public:
222 static AnalysisKey *ID() { return &SetKey; }
362 static AnalysisSetKey *ID() { return &SetKey; }
223363
224364 private:
225 static AnalysisKey SetKey;
365 static AnalysisSetKey SetKey;
226366 };
227367
228 template AnalysisKey AllAnalysesOn::SetKey;
368 template AnalysisSetKey AllAnalysesOn::SetKey;
229369
230370 extern template class AllAnalysesOn;
231371 extern template class AllAnalysesOn;
299439 // current unit of IR. Therefore, the remaining analysis results in the
300440 // AnalysisManager are preserved. We mark this with a set so that we don't
301441 // need to inspect each one individually.
302 PA.preserve>();
442 PA.preserveSet>();
303443
304444 if (DebugLogging)
305445 dbgs() << "Finished " << getTypeName() << " pass manager run.\n";
398538 /// any dependecies on it will become invalid as a result.
399539 template
400540 bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA) {
401 AnalysisKey *ID = PassT::ID();
402
541 typedef detail::AnalysisResultModel
542 typename PassT::Result,
543 PreservedAnalyses, Invalidator>
544 ResultModelT;
545 return invalidateImpl(PassT::ID(), IR, PA);
546 }
547
548 /// A type-erased variant of the above invalidate method with the same core
549 /// API other than passing an analysis ID rather than an analysis type
550 /// parameter.
551 ///
552 /// This is sadly less efficient than the above routine, which leverages
553 /// the type parameter to avoid the type erasure overhead.
554 bool invalidate(AnalysisKey *ID, IRUnitT &IR, const PreservedAnalyses &PA) {
555 return invalidateImpl<>(ID, IR, PA);
556 }
557
558 private:
559 friend class AnalysisManager;
560
561 template
562 bool invalidateImpl(AnalysisKey *ID, IRUnitT &IR,
563 const PreservedAnalyses &PA) {
403564 // If we've already visited this pass, return true if it was invalidated
404565 // and false otherwise.
405566 auto IMapI = IsResultInvalidated.find(ID);
413574 "manager's cache is always an error, likely due to a stale result "
414575 "handle!");
415576
416 typedef detail::AnalysisResultModel
417 typename PassT::Result,
418 PreservedAnalyses, Invalidator>
419 ResultModelT;
420 auto &ResultModel = static_castT &>(*RI->second->second);
577 auto &Result = static_castT &>(*RI->second->second);
421578
422579 // Insert into the map whether the result should be invalidated and
423580 // return that. Note that we cannot re-use IMapI and must do a fresh
424581 // insert here as calling the invalidate routine could (recursively)
425582 // insert things into the map making any iterator or reference invalid.
426583 bool Inserted;
427 std::tie(IMapI, Inserted) = IsResultInvalidated.insert(
428 {ID, ResultModel.invalidate(IR, PA, *this)});
584 std::tie(IMapI, Inserted) =
585 IsResultInvalidated.insert({ID, Result.invalidate(IR, PA, *this)});
429586 (void)Inserted;
430587 assert(Inserted && "Should not have already inserted this ID, likely "
431588 "indicates a dependency cycle!");
432589 return IMapI->second;
433590 }
434
435 private:
436 friend class AnalysisManager;
437591
438592 Invalidator(SmallDenseMap &IsResultInvalidated,
439593 const AnalysisResultMapT &Results)
575729 /// Walk through all of the analyses pertaining to this unit of IR and
576730 /// invalidate them unless they are preserved by the PreservedAnalyses set.
577731 void invalidate(IRUnitT &IR, const PreservedAnalyses &PA) {
578 // Short circuit for common cases of all analyses being preserved.
579 if (PA.areAllPreserved() || PA.preserved>())
732 // We're done if all analyses on this IR unit are preserved.
733 if (PA.allAnalysesInSetPreserved>())
580734 return;
581735
582736 if (DebugLogging)
8561010 /// cannot request a module analysis to actually run. Instead, the user must
8571011 /// rely on the \c getCachedResult API.
8581012 ///
859 /// This proxy *doesn't* manage the invalidation in any way. That is handled by
860 /// the recursive return path of each layer of the pass manager and the
861 /// returned PreservedAnalysis set.
1013 /// The invalidation provided by this proxy involves tracking when an
1014 /// invalidation event in the outer analysis manager needs to trigger an
1015 /// invalidation of a particular analysis on this IR unit.
1016 ///
1017 /// Because outer analyses aren't invalidated while these IR units are being
1018 /// precessed, we have to register and handle these as deferred invalidation
1019 /// events.
8621020 template
8631021 class OuterAnalysisManagerProxy
8641022 : public AnalysisInfoMixin<
8781036 return false;
8791037 }
8801038
1039 /// Register a deferred invalidation event for when the outer analysis
1040 /// manager processes its invalidations.
1041 template
1042 void registerOuterAnalysisInvalidation() {
1043 AnalysisKey *OuterID = OuterAnalysisT::ID();
1044 AnalysisKey *InvalidatedID = InvalidatedAnalysisT::ID();
1045
1046 auto &InvalidatedIDList = OuterAnalysisInvalidationMap[OuterID];
1047 // Note, this is a linear scan. If we end up with large numbers of
1048 // analyses that all trigger invalidation on the same outer analysis,
1049 // this entire system should be changed to some other deterministic
1050 // data structure such as a `SetVector` of a pair of pointers.
1051 auto InvalidatedIt = std::find(InvalidatedIDList.begin(),
1052 InvalidatedIDList.end(), InvalidatedID);
1053 if (InvalidatedIt == InvalidatedIDList.end())
1054 InvalidatedIDList.push_back(InvalidatedID);
1055 }
1056
1057 /// Access the map from outer analyses to deferred invalidation requiring
1058 /// analyses.
1059 const SmallDenseMap, 2> &
1060 getOuterInvalidations() const {
1061 return OuterAnalysisInvalidationMap;
1062 }
1063
8811064 private:
8821065 const AnalysisManagerT *AM;
1066
1067 /// A map from an outer analysis ID to the set of this IR-unit's analyses
1068 /// which need to be invalidated.
1069 SmallDenseMap, 2>
1070 OuterAnalysisInvalidationMap;
8831071 };
8841072
8851073 OuterAnalysisManagerProxy(const AnalysisManagerT &AM) : AM(&AM) {}
9661154 // Function units. This precludes *any* invalidation of function analyses
9671155 // by the proxy, but that's OK because we've taken care to invalidate
9681156 // analyses in the function analysis manager incrementally above.
969 PA.preserve>();
1157 PA.preserveSet>();
9701158 PA.preserve();
9711159 return PA;
9721160 }
2424
2525 namespace llvm {
2626
27 template class AllAnalysesOn;
2728 template class AnalysisManager;
2829 class Invalidator;
2930 class PreservedAnalyses;
190191 // ones that use the trivial behavior.
191192 bool invalidate(IRUnitT &, const PreservedAnalysesT &PA,
192193 InvalidatorT &) override {
193 return !PA.preserved(PassT::ID());
194 auto PAC = PA.template getChecker();
195 return !PAC.preserved() &&
196 !PAC.template preservedSet>();
194197 }
195198
196199 ResultT Result;
7575 // SCC. Therefore, the remaining analysis results in the AnalysisManager are
7676 // preserved. We mark this with a set so that we don't need to inspect each
7777 // one individually.
78 PA.preserve>();
78 PA.preserveSet>();
7979
8080 if (DebugLogging)
8181 dbgs() << "Finished CGSCC pass manager run.\n";
8686 bool CGSCCAnalysisManagerModuleProxy::Result::invalidate(
8787 Module &M, const PreservedAnalyses &PA,
8888 ModuleAnalysisManager::Invalidator &Inv) {
89 // If literally everything is preserved, we're done.
90 if (PA.areAllPreserved())
91 return false; // This is still a valid proxy.
92
8993 // If this proxy or the call graph is going to be invalidated, we also need
9094 // to clear all the keys coming from that analysis.
9195 //
9397 // that proxy isn't preserved we can't preserve this proxy either. We rely on
9498 // it to handle module -> function analysis invalidation in the face of
9599 // structural changes and so if it's unavailable we conservatively clear the
96 // entire SCC layer as well rather than trying to do invaliadtion ourselves.
97 if (!PA.preserved() ||
100 // entire SCC layer as well rather than trying to do invalidation ourselves.
101 auto PAC = PA.getChecker();
102 if (!(PAC.preserved() || PAC.preservedSet>()) ||
98103 Inv.invalidate(M, PA) ||
99104 Inv.invalidate(M, PA)) {
100105 InnerAM->clear();
105110 return true;
106111 }
107112
113 // Directly check if the relevant set is preserved so we can short circuit
114 // invalidating SCCs below.
115 bool AreSCCAnalysesPreserved =
116 PA.allAnalysesInSetPreserved>();
117
108118 // Ok, we have a graph, so we can propagate the invalidation down into it.
109119 for (auto &RC : G->postorder_ref_sccs())
110 for (auto &C : RC)
111 InnerAM->invalidate(C, PA);
120 for (auto &C : RC) {
121 Optional InnerPA;
122
123 // Check to see whether the preserved set needs to be adjusted based on
124 // module-level analysis invalidation triggering deferred invalidation
125 // for this SCC.
126 if (auto *OuterProxy =
127 InnerAM->getCachedResult(C))
128 for (const auto &OuterInvalidationPair :
129 OuterProxy->getOuterInvalidations()) {
130 AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
131 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
132 if (Inv.invalidate(OuterAnalysisID, M, PA)) {
133 if (!InnerPA)
134 InnerPA = PA;
135 for (AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
136 InnerPA->abandon(InnerAnalysisID);
137 }
138 }
139
140 // Check if we needed a custom PA set. If so we'll need to run the inner
141 // invalidation.
142 if (InnerPA) {
143 InnerAM->invalidate(C, *InnerPA);
144 continue;
145 }
146
147 // Otherwise we only need to do invalidation if the original PA set didn't
148 // preserve all SCC analyses.
149 if (!AreSCCAnalysesPreserved)
150 InnerAM->invalidate(C, PA);
151 }
112152
113153 // Return false to indicate that this result is still a valid proxy.
114154 return false;
3232 // the module may have changed. We therefore can't call
3333 // InnerAM->invalidate(), because any pointers to Functions it has may be
3434 // stale.
35 if (!PA.preserved(LoopAnalysisManagerFunctionProxy::ID()))
35 auto PAC = PA.getChecker();
36 if (!PAC.preserved() && !PAC.preservedSet>())
3637 InnerAM->clear();
3738
3839 // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM.
2828 bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
2929 Module &M, const PreservedAnalyses &PA,
3030 ModuleAnalysisManager::Invalidator &Inv) {
31 // If literally everything is preserved, we're done.
32 if (PA.areAllPreserved())
33 return false; // This is still a valid proxy.
34
3135 // If this proxy isn't marked as preserved, then even if the result remains
3236 // valid, the key itself may no longer be valid, so we clear everything.
3337 //
3640 // Specifically, any FAM-cached results for those functions need to have been
3741 // forcibly cleared. When preserved, this proxy will only invalidate results
3842 // cached on functions *still in the module* at the end of the module pass.
39 if (!PA.preserved(FunctionAnalysisManagerModuleProxy::ID())) {
43 auto PAC = PA.getChecker();
44 if (!PAC.preserved() && !PAC.preservedSet>()) {
4045 InnerAM->clear();
4146 return true;
4247 }
4348
44 // Otherwise propagate the invalidation event to all the remaining IR units.
45 for (Function &F : M)
46 InnerAM->invalidate(F, PA);
49 // Directly check if the relevant set is preserved.
50 bool AreFunctionAnalysesPreserved =
51 PA.allAnalysesInSetPreserved>();
52
53 // Now walk all the functions to see if any inner analysis invalidation is
54 // necessary.
55 for (Function &F : M) {
56 Optional FunctionPA;
57
58 // Check to see whether the preserved set needs to be pruned based on
59 // module-level analysis invalidation that triggers deferred invalidation
60 // registered with the outer analysis manager proxy for this function.
61 if (auto *OuterProxy =
62 InnerAM->getCachedResult(F))
63 for (const auto &OuterInvalidationPair :
64 OuterProxy->getOuterInvalidations()) {
65 AnalysisKey *OuterAnalysisID = OuterInvalidationPair.first;
66 const auto &InnerAnalysisIDs = OuterInvalidationPair.second;
67 if (Inv.invalidate(OuterAnalysisID, M, PA)) {
68 if (!FunctionPA)
69 FunctionPA = PA;
70 for (AnalysisKey *InnerAnalysisID : InnerAnalysisIDs)
71 FunctionPA->abandon(InnerAnalysisID);
72 }
73 }
74
75 // Check if we needed a custom PA set, and if so we'll need to run the
76 // inner invalidation.
77 if (FunctionPA) {
78 InnerAM->invalidate(F, *FunctionPA);
79 continue;
80 }
81
82 // Otherwise we only need to do invalidation if the original PA set didn't
83 // preserve all function analyses.
84 if (!AreFunctionAnalysesPreserved)
85 InnerAM->invalidate(F, PA);
86 }
4787
4888 // Return false to indicate that this result is still a valid proxy.
4989 return false;
5090 }
5191 }
5292
53 AnalysisKey PreservedAnalyses::AllAnalysesKey;
93 AnalysisSetKey PreservedAnalyses::AllAnalysesKey;
819819 // Two runs and 6 functions.
820820 EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
821821 }
822 }
822
823 /// A test CGSCC-level analysis pass which caches in its result another
824 /// analysis pass and uses it to serve queries. This requires the result to
825 /// invalidate itself when its dependency is invalidated.
826 ///
827 /// FIXME: Currently this doesn't also depend on a function analysis, and if it
828 /// did we would fail to invalidate it correctly.
829 struct TestIndirectSCCAnalysis
830 : public AnalysisInfoMixin {
831 struct Result {
832 Result(TestSCCAnalysis::Result &SCCDep, TestModuleAnalysis::Result &MDep)
833 : SCCDep(SCCDep), MDep(MDep) {}
834 TestSCCAnalysis::Result &SCCDep;
835 TestModuleAnalysis::Result &MDep;
836
837 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
838 CGSCCAnalysisManager::Invalidator &Inv) {
839 auto PAC = PA.getChecker();
840 return !(PAC.preserved() ||
841 PAC.preservedSet>()) ||
842 Inv.invalidate(C, PA);
843 }
844 };
845
846 TestIndirectSCCAnalysis(int &Runs) : Runs(Runs) {}
847
848 /// Run the analysis pass over the function and return a result.
849 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
850 LazyCallGraph &CG) {
851 ++Runs;
852 auto &SCCDep = AM.getResult(C, CG);
853
854 auto &ModuleProxy = AM.getResult(C, CG);
855 const ModuleAnalysisManager &MAM = ModuleProxy.getManager();
856 // For the test, we insist that the module analysis starts off in the
857 // cache.
858 auto &MDep = *MAM.getCachedResult(
859 *C.begin()->getFunction().getParent());
860 // Register the dependency as module analysis dependencies have to be
861 // pre-registered on the proxy.
862 ModuleProxy.registerOuterAnalysisInvalidation
863 TestIndirectSCCAnalysis>();
864
865 return Result(SCCDep, MDep);
866 }
867
868 private:
869 friend AnalysisInfoMixin;
870 static AnalysisKey Key;
871
872 int &Runs;
873 };
874
875 AnalysisKey TestIndirectSCCAnalysis::Key;
876
877 /// A test analysis pass which caches in its result the result from the above
878 /// indirect analysis pass.
879 ///
880 /// This allows us to ensure that whenever an analysis pass is invalidated due
881 /// to dependencies (especially dependencies across IR units that trigger
882 /// asynchronous invalidation) we correctly detect that this may in turn cause
883 /// other analysis to be invalidated.
884 struct TestDoublyIndirectSCCAnalysis
885 : public AnalysisInfoMixin {
886 struct Result {
887 Result(TestIndirectSCCAnalysis::Result &IDep) : IDep(IDep) {}
888 TestIndirectSCCAnalysis::Result &IDep;
889
890 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
891 CGSCCAnalysisManager::Invalidator &Inv) {
892 auto PAC = PA.getChecker();
893 return !(PAC.preserved() ||
894 PAC.preservedSet>()) ||
895 Inv.invalidate(C, PA);
896 }
897 };
898
899 TestDoublyIndirectSCCAnalysis(int &Runs) : Runs(Runs) {}
900
901 /// Run the analysis pass over the function and return a result.
902 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
903 LazyCallGraph &CG) {
904 ++Runs;
905 auto &IDep = AM.getResult(C, CG);
906 return Result(IDep);
907 }
908
909 private:
910 friend AnalysisInfoMixin;
911 static AnalysisKey Key;
912
913 int &Runs;
914 };
915
916 AnalysisKey TestDoublyIndirectSCCAnalysis::Key;
917
918 /// A test analysis pass which caches results from three different IR unit
919 /// layers and requires intermediate layers to correctly propagate the entire
920 /// distance.
921 struct TestIndirectFunctionAnalysis
922 : public AnalysisInfoMixin {
923 struct Result {
924 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep,
925 TestSCCAnalysis::Result &SCCDep)
926 : FDep(FDep), MDep(MDep), SCCDep(SCCDep) {}
927 TestFunctionAnalysis::Result &FDep;
928 TestModuleAnalysis::Result &MDep;
929 TestSCCAnalysis::Result &SCCDep;
930
931 bool invalidate(Function &F, const PreservedAnalyses &PA,
932 FunctionAnalysisManager::Invalidator &Inv) {
933 auto PAC = PA.getChecker();
934 return !(PAC.preserved() ||
935 PAC.preservedSet>()) ||
936 Inv.invalidate(F, PA);
937 }
938 };
939
940 TestIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
941
942 /// Run the analysis pass over the function and return a result.
943 Result run(Function &F, FunctionAnalysisManager &AM) {
944 ++Runs;
945 auto &FDep = AM.getResult(F);
946
947 auto &ModuleProxy = AM.getResult(F);
948 const ModuleAnalysisManager &MAM = ModuleProxy.getManager();
949 // For the test, we insist that the module analysis starts off in the
950 // cache.
951 auto &MDep = *MAM.getCachedResult(*F.getParent());
952 // Register the dependency as module analysis dependencies have to be
953 // pre-registered on the proxy.
954 ModuleProxy.registerOuterAnalysisInvalidation<
955 TestModuleAnalysis, TestIndirectFunctionAnalysis>();
956
957 // For thet test we assume this is run inside a CGSCC pass manager.
958 const LazyCallGraph &CG =
959 *MAM.getCachedResult(*F.getParent());
960 auto &CGSCCProxy = AM.getResult(F);
961 const CGSCCAnalysisManager &CGAM = CGSCCProxy.getManager();
962 // For the test, we insist that the CGSCC analysis starts off in the cache.
963 auto &SCCDep =
964 *CGAM.getCachedResult(*CG.lookupSCC(*CG.lookup(F)));
965 // Register the dependency as CGSCC analysis dependencies have to be
966 // pre-registered on the proxy.
967 CGSCCProxy.registerOuterAnalysisInvalidation<
968 TestSCCAnalysis, TestIndirectFunctionAnalysis>();
969
970 return Result(FDep, MDep, SCCDep);
971 }
972
973 private:
974 friend AnalysisInfoMixin;
975 static AnalysisKey Key;
976
977 int &Runs;
978 };
979
980 AnalysisKey TestIndirectFunctionAnalysis::Key;
981
982 TEST_F(CGSCCPassManagerTest, TestIndirectAnalysisInvalidation) {
983 int ModuleAnalysisRuns = 0;
984 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
985
986 int SCCAnalysisRuns = 0, IndirectSCCAnalysisRuns = 0,
987 DoublyIndirectSCCAnalysisRuns = 0;
988 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
989 CGAM.registerPass(
990 [&] { return TestIndirectSCCAnalysis(IndirectSCCAnalysisRuns); });
991 CGAM.registerPass([&] {
992 return TestDoublyIndirectSCCAnalysis(DoublyIndirectSCCAnalysisRuns);
993 });
994
995 int FunctionAnalysisRuns = 0, IndirectFunctionAnalysisRuns = 0;
996 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
997 FAM.registerPass([&] {
998 return TestIndirectFunctionAnalysis(IndirectFunctionAnalysisRuns);
999 });
1000
1001 ModulePassManager MPM(/*DebugLogging*/ true);
1002
1003 int FunctionCount = 0;
1004 CGSCCPassManager CGPM(/*DebugLogging*/ true);
1005 // First just use the analysis to get the function count and preserve
1006 // everything.
1007 CGPM.addPass(
1008 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1009 LazyCallGraph &CG, CGSCCUpdateResult &) {
1010 auto &DoublyIndirectResult =
1011 AM.getResult(C, CG);
1012 auto &IndirectResult = DoublyIndirectResult.IDep;
1013 FunctionCount += IndirectResult.SCCDep.FunctionCount;
1014 return PreservedAnalyses::all();
1015 }));
1016 // Next, invalidate
1017 // - both analyses for the (f) and (x) SCCs,
1018 // - just the underlying (indirect) analysis for (g) SCC, and
1019 // - just the direct analysis for (h1,h2,h3) SCC.
1020 CGPM.addPass(
1021 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1022 LazyCallGraph &CG, CGSCCUpdateResult &) {
1023 auto &DoublyIndirectResult =
1024 AM.getResult(C, CG);
1025 auto &IndirectResult = DoublyIndirectResult.IDep;
1026 FunctionCount += IndirectResult.SCCDep.FunctionCount;
1027 auto PA = PreservedAnalyses::none();
1028 if (C.getName() == "(g)")
1029 PA.preserve();
1030 else if (C.getName() == "(h3, h1, h2)")
1031 PA.preserve();
1032 return PA;
1033 }));
1034 // Finally, use the analysis again on each function, forcing re-computation
1035 // for all of them.
1036 CGPM.addPass(
1037 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1038 LazyCallGraph &CG, CGSCCUpdateResult &) {
1039 auto &DoublyIndirectResult =
1040 AM.getResult(C, CG);
1041 auto &IndirectResult = DoublyIndirectResult.IDep;
1042 FunctionCount += IndirectResult.SCCDep.FunctionCount;
1043 return PreservedAnalyses::all();
1044 }));
1045
1046 // Create a second CGSCC pass manager. This will cause the module-level
1047 // invalidation to occur, which will force yet another invalidation of the
1048 // indirect SCC-level analysis as the module analysis it depends on gets
1049 // invalidated.
1050 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
1051 CGPM2.addPass(
1052 LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
1053 LazyCallGraph &CG, CGSCCUpdateResult &) {
1054 auto &DoublyIndirectResult =
1055 AM.getResult(C, CG);
1056 auto &IndirectResult = DoublyIndirectResult.IDep;
1057 FunctionCount += IndirectResult.SCCDep.FunctionCount;
1058 return PreservedAnalyses::all();
1059 }));
1060
1061 // Add a requires pass to populate the module analysis and then our function
1062 // pass pipeline.
1063 MPM.addPass(RequireAnalysisPass());
1064 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
1065 // Now require the module analysis again (it will have been invalidated once)
1066 // and then use it again from a function pass manager.
1067 MPM.addPass(RequireAnalysisPass());
1068 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
1069 MPM.run(*M, MAM);
1070
1071 // There are generally two possible runs for each of the four SCCs. But
1072 // for one SCC, we only invalidate the indirect analysis so the base one
1073 // only gets run seven times.
1074 EXPECT_EQ(7, SCCAnalysisRuns);
1075 // The module analysis pass should be run twice here.
1076 EXPECT_EQ(2, ModuleAnalysisRuns);
1077 // The indirect analysis is invalidated (either directly or indirectly) three
1078 // times for each of four SCCs.
1079 EXPECT_EQ(3 * 4, IndirectSCCAnalysisRuns);
1080 EXPECT_EQ(3 * 4, DoublyIndirectSCCAnalysisRuns);
1081
1082 // Four passes count each of six functions once (via SCCs).
1083 EXPECT_EQ(4 * 6, FunctionCount);
1084 }
1085 }
167167 "}\n")) {}
168168 };
169169
170 TEST_F(PassManagerTest, BasicPreservedAnalyses) {
170 TEST(PreservedAnalysesTest, Basic) {
171171 PreservedAnalyses PA1 = PreservedAnalyses();
172 EXPECT_FALSE(PA1.preserved());
173 EXPECT_FALSE(PA1.preserved());
174 PreservedAnalyses PA2 = PreservedAnalyses::none();
175 EXPECT_FALSE(PA2.preserved());
176 EXPECT_FALSE(PA2.preserved());
177 PreservedAnalyses PA3 = PreservedAnalyses::all();
178 EXPECT_TRUE(PA3.preserved());
179 EXPECT_TRUE(PA3.preserved());
172 {
173 auto PAC = PA1.getChecker();
174 EXPECT_FALSE(PAC.preserved());
175 EXPECT_FALSE(PAC.preservedSet>());
176 }
177 {
178 auto PAC = PA1.getChecker();
179 EXPECT_FALSE(PAC.preserved());
180 EXPECT_FALSE(PAC.preservedSet>());
181 }
182 auto PA2 = PreservedAnalyses::none();
183 {
184 auto PAC = PA2.getChecker();
185 EXPECT_FALSE(PAC.preserved());
186 EXPECT_FALSE(PAC.preservedSet>());
187 }
188 auto PA3 = PreservedAnalyses::all();
189 {
190 auto PAC = PA3.getChecker();
191 EXPECT_TRUE(PAC.preserved());
192 EXPECT_TRUE(PAC.preservedSet>());
193 }
180194 PreservedAnalyses PA4 = PA1;
181 EXPECT_FALSE(PA4.preserved());
182 EXPECT_FALSE(PA4.preserved());
195 {
196 auto PAC = PA4.getChecker();
197 EXPECT_FALSE(PAC.preserved());
198 EXPECT_FALSE(PAC.preservedSet>());
199 }
183200 PA4 = PA3;
184 EXPECT_TRUE(PA4.preserved());
185 EXPECT_TRUE(PA4.preserved());
201 {
202 auto PAC = PA4.getChecker();
203 EXPECT_TRUE(PAC.preserved());
204 EXPECT_TRUE(PAC.preservedSet>());
205 }
186206 PA4 = std::move(PA2);
187 EXPECT_FALSE(PA4.preserved());
188 EXPECT_FALSE(PA4.preserved());
189 PA4.preserve();
190 EXPECT_TRUE(PA4.preserved());
191 EXPECT_FALSE(PA4.preserved());
192 PA1.preserve();
193 EXPECT_FALSE(PA1.preserved());
194 EXPECT_TRUE(PA1.preserved());
207 {
208 auto PAC = PA4.getChecker();
209 EXPECT_FALSE(PAC.preserved());
210 EXPECT_FALSE(PAC.preservedSet>());
211 }
212 }
213
214 TEST(PreservedAnalysesTest, Preserve) {
215 auto PA = PreservedAnalyses::none();
216 PA.preserve();
217 EXPECT_TRUE(PA.getChecker().preserved());
218 EXPECT_FALSE(PA.getChecker().preserved());
219 PA.preserve();
220 EXPECT_TRUE(PA.getChecker().preserved());
221 EXPECT_TRUE(PA.getChecker().preserved());
222
223 // Redundant calls are fine.
224 PA.preserve();
225 EXPECT_TRUE(PA.getChecker().preserved());
226 EXPECT_TRUE(PA.getChecker().preserved());
227 }
228
229 TEST(PreservedAnalysesTest, PreserveSets) {
230 auto PA = PreservedAnalyses::none();
231 PA.preserveSet>();
232 EXPECT_TRUE(PA.getChecker()
233 .preservedSet>());
234 EXPECT_FALSE(PA.getChecker()
235 .preservedSet>());
236 PA.preserveSet>();
237 EXPECT_TRUE(PA.getChecker()
238 .preservedSet>());
239 EXPECT_TRUE(PA.getChecker()
240 .preservedSet>());
241
242 // Mixing is fine.
243 PA.preserve();
244 EXPECT_TRUE(PA.getChecker()
245 .preservedSet>());
246 EXPECT_TRUE(PA.getChecker()
247 .preservedSet>());
248
249 // Redundant calls are fine.
250 PA.preserveSet>();
251 EXPECT_TRUE(PA.getChecker()
252 .preservedSet>());
253 EXPECT_TRUE(PA.getChecker()
254 .preservedSet>());
255 }
256
257 TEST(PreservedAnalysisTest, Intersect) {
258 // Setup the initial sets.
259 auto PA1 = PreservedAnalyses::none();
195260 PA1.preserve();
196 EXPECT_TRUE(PA1.preserved());
197 EXPECT_TRUE(PA1.preserved());
198 PA1.intersect(PA4);
199 EXPECT_TRUE(PA1.preserved());
200 EXPECT_FALSE(PA1.preserved());
261 PA1.preserveSet>();
262 auto PA2 = PreservedAnalyses::none();
263 PA2.preserve();
264 PA2.preserveSet>();
265 PA2.preserve();
266 PA2.preserveSet>();
267 auto PA3 = PreservedAnalyses::none();
268 PA3.preserve();
269 PA3.preserveSet>();
270
271 // Self intersection is a no-op.
272 auto Intersected = PA1;
273 Intersected.intersect(PA1);
274 EXPECT_TRUE(Intersected.getChecker().preserved());
275 EXPECT_FALSE(Intersected.getChecker()
276 .preservedSet>());
277 EXPECT_FALSE(Intersected.getChecker().preserved());
278 EXPECT_TRUE(Intersected.getChecker()
279 .preservedSet>());
280
281 // Intersecting with all is a no-op.
282 Intersected.intersect(PreservedAnalyses::all());
283 EXPECT_TRUE(Intersected.getChecker().preserved());
284 EXPECT_FALSE(Intersected.getChecker()
285 .preservedSet>());
286 EXPECT_FALSE(Intersected.getChecker().preserved());
287 EXPECT_TRUE(Intersected.getChecker()
288 .preservedSet>());
289
290 // Intersecting a narrow set with a more broad set is the narrow set.
291 Intersected.intersect(PA2);
292 EXPECT_TRUE(Intersected.getChecker().preserved());
293 EXPECT_FALSE(Intersected.getChecker()
294 .preservedSet>());
295 EXPECT_FALSE(Intersected.getChecker().preserved());
296 EXPECT_TRUE(Intersected.getChecker()
297 .preservedSet>());
298
299 // Intersecting a broad set with a more narrow set is the narrow set.
300 Intersected = PA2;
301 Intersected.intersect(PA1);
302 EXPECT_TRUE(Intersected.getChecker().preserved());
303 EXPECT_FALSE(Intersected.getChecker()
304 .preservedSet>());
305 EXPECT_FALSE(Intersected.getChecker().preserved());
306 EXPECT_TRUE(Intersected.getChecker()
307 .preservedSet>());
308
309 // Intersecting with empty clears.
310 Intersected.intersect(PreservedAnalyses::none());
311 EXPECT_FALSE(Intersected.getChecker().preserved());
312 EXPECT_FALSE(Intersected.getChecker()
313 .preservedSet>());
314 EXPECT_FALSE(Intersected.getChecker().preserved());
315 EXPECT_FALSE(Intersected.getChecker()
316 .preservedSet>());
317
318 // Intersecting non-overlapping clears.
319 Intersected = PA1;
320 Intersected.intersect(PA3);
321 EXPECT_FALSE(Intersected.getChecker().preserved());
322 EXPECT_FALSE(Intersected.getChecker()
323 .preservedSet>());
324 EXPECT_FALSE(Intersected.getChecker().preserved());
325 EXPECT_FALSE(Intersected.getChecker()
326 .preservedSet>());
327
328 // Intersecting with moves works in when there is storage on both sides.
329 Intersected = PA1;
330 auto Tmp = PA2;
331 Intersected.intersect(std::move(Tmp));
332 EXPECT_TRUE(Intersected.getChecker().preserved());
333 EXPECT_FALSE(Intersected.getChecker()
334 .preservedSet>());
335 EXPECT_FALSE(Intersected.getChecker().preserved());
336 EXPECT_TRUE(Intersected.getChecker()
337 .preservedSet>());
338
339 // Intersecting with move works for incoming all and existing all.
340 auto Tmp2 = PreservedAnalyses::all();
341 Intersected.intersect(std::move(Tmp2));
342 EXPECT_TRUE(Intersected.getChecker().preserved());
343 EXPECT_FALSE(Intersected.getChecker()
344 .preservedSet>());
345 EXPECT_FALSE(Intersected.getChecker().preserved());
346 EXPECT_TRUE(Intersected.getChecker()
347 .preservedSet>());
348 Intersected = PreservedAnalyses::all();
349 auto Tmp3 = PA1;
350 Intersected.intersect(std::move(Tmp3));
351 EXPECT_TRUE(Intersected.getChecker().preserved());
352 EXPECT_FALSE(Intersected.getChecker()
353 .preservedSet>());
354 EXPECT_FALSE(Intersected.getChecker().preserved());
355 EXPECT_TRUE(Intersected.getChecker()
356 .preservedSet>());
357 }
358
359 TEST(PreservedAnalysisTest, Abandon) {
360 auto PA = PreservedAnalyses::none();
361
362 // We can abandon things after they are preserved.
363 PA.preserve();
364 PA.abandon();
365 EXPECT_FALSE(PA.getChecker().preserved());
366
367 // Repeated is fine, and abandoning if they were never preserved is fine.
368 PA.abandon();
369 EXPECT_FALSE(PA.getChecker().preserved());
370 PA.abandon();
371 EXPECT_FALSE(PA.getChecker().preserved());
372
373 // Even if the sets are preserved, the abandoned analyses' checker won't
374 // return true for those sets.
375 PA.preserveSet>();
376 PA.preserveSet>();
377 EXPECT_FALSE(PA.getChecker()
378 .preservedSet>());
379 EXPECT_FALSE(PA.getChecker()
380 .preservedSet>());
381
382 // But an arbitrary (opaque) analysis will still observe the sets as
383 // preserved. This also checks that we can use an explicit ID rather than
384 // a type.
385 AnalysisKey FakeKey, *FakeID = &FakeKey;
386 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet>());
387 EXPECT_TRUE(PA.getChecker(FakeID).preservedSet>());
201388 }
202389
203390 TEST_F(PassManagerTest, Basic) {
384571 struct TestIndirectFunctionAnalysis
385572 : public AnalysisInfoMixin {
386573 struct Result {
387 Result(TestFunctionAnalysis::Result &Dep) : Dep(Dep) {}
388 TestFunctionAnalysis::Result &Dep;
574 Result(TestFunctionAnalysis::Result &FDep, TestModuleAnalysis::Result &MDep)
575 : FDep(FDep), MDep(MDep) {}
576 TestFunctionAnalysis::Result &FDep;
577 TestModuleAnalysis::Result &MDep;
389578
390579 bool invalidate(Function &F, const PreservedAnalyses &PA,
391580 FunctionAnalysisManager::Invalidator &Inv) {
392 return !PA.preserved() ||
581 auto PAC = PA.getChecker();
582 return !(PAC.preserved() ||
583 PAC.preservedSet>()) ||
393584 Inv.invalidate(F, PA);
394585 }
395586 };
399590 /// Run the analysis pass over the function and return a result.
400591 Result run(Function &F, FunctionAnalysisManager &AM) {
401592 ++Runs;
402 return Result(AM.getResult(F));
593 auto &FDep = AM.getResult(F);
594 auto &Proxy = AM.getResult(F);
595 const ModuleAnalysisManager &MAM = Proxy.getManager();
596 // For the test, we insist that the module analysis starts off in the
597 // cache.
598 auto &MDep = *MAM.getCachedResult(*F.getParent());
599 // And register the dependency as module analysis dependencies have to be
600 // pre-registered on the proxy.
601 Proxy.registerOuterAnalysisInvalidation
602 TestIndirectFunctionAnalysis>();
603 return Result(FDep, MDep);
403604 }
404605
405606 private:
411612
412613 AnalysisKey TestIndirectFunctionAnalysis::Key;
413614
615 /// A test analysis pass which chaches in its result the result from the above
616 /// indirect analysis pass.
617 ///
618 /// This allows us to ensure that whenever an analysis pass is invalidated due
619 /// to dependencies (especially dependencies across IR units that trigger
620 /// asynchronous invalidation) we correctly detect that this may in turn cause
621 /// other analysis to be invalidated.
622 struct TestDoublyIndirectFunctionAnalysis
623 : public AnalysisInfoMixin {
624 struct Result {
625 Result(TestIndirectFunctionAnalysis::Result &IDep) : IDep(IDep) {}
626 TestIndirectFunctionAnalysis::Result &IDep;
627
628 bool invalidate(Function &F, const PreservedAnalyses &PA,
629 FunctionAnalysisManager::Invalidator &Inv) {
630 auto PAC = PA.getChecker();
631 return !(PAC.preserved() ||
632 PAC.preservedSet>()) ||
633 Inv.invalidate(F, PA);
634 }
635 };
636
637 TestDoublyIndirectFunctionAnalysis(int &Runs) : Runs(Runs) {}
638
639 /// Run the analysis pass over the function and return a result.
640 Result run(Function &F, FunctionAnalysisManager &AM) {
641 ++Runs;
642 auto &IDep = AM.getResult(F);
643 return Result(IDep);
644 }
645
646 private:
647 friend AnalysisInfoMixin;
648 static AnalysisKey Key;
649
650 int &Runs;
651 };
652
653 AnalysisKey TestDoublyIndirectFunctionAnalysis::Key;
654
414655 struct LambdaPass : public PassInfoMixin {
415656 using FuncT = std::function;
416657
425666
426667 TEST_F(PassManagerTest, IndirectAnalysisInvalidation) {
427668 FunctionAnalysisManager FAM(/*DebugLogging*/ true);
428 int AnalysisRuns = 0, IndirectAnalysisRuns = 0;
429 FAM.registerPass([&] { return TestFunctionAnalysis(AnalysisRuns); });
669 int FunctionAnalysisRuns = 0, ModuleAnalysisRuns = 0,
670 IndirectAnalysisRuns = 0, DoublyIndirectAnalysisRuns = 0;
671 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
430672 FAM.registerPass(
431673 [&] { return TestIndirectFunctionAnalysis(IndirectAnalysisRuns); });
674 FAM.registerPass([&] {
675 return TestDoublyIndirectFunctionAnalysis(DoublyIndirectAnalysisRuns);
676 });
432677
433678 ModuleAnalysisManager MAM(/*DebugLogging*/ true);
679 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
434680 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
435681 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
436682
437 int InstrCount = 0;
683 int InstrCount = 0, FunctionCount = 0;
438684 ModulePassManager MPM(/*DebugLogging*/ true);
439685 FunctionPassManager FPM(/*DebugLogging*/ true);
440686 // First just use the analysis to get the instruction count, and preserve
441687 // everything.
442688 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
443 InstrCount +=
444 AM.getResult(F).Dep.InstructionCount;
689 auto &DoublyIndirectResult =
690 AM.getResult(F);
691 auto &IndirectResult = DoublyIndirectResult.IDep;
692 InstrCount += IndirectResult.FDep.InstructionCount;
693 FunctionCount += IndirectResult.MDep.FunctionCount;
445694 return PreservedAnalyses::all();
446695 }));
447696 // Next, invalidate
449698 // - just the underlying (indirect) analysis for "g", and
450699 // - just the direct analysis for "h".
451700 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
452 InstrCount +=
453 AM.getResult(F).Dep.InstructionCount;
701 auto &DoublyIndirectResult =
702 AM.getResult(F);
703 auto &IndirectResult = DoublyIndirectResult.IDep;
704 InstrCount += IndirectResult.FDep.InstructionCount;
705 FunctionCount += IndirectResult.MDep.FunctionCount;
454706 auto PA = PreservedAnalyses::none();
455707 if (F.getName() == "g")
456708 PA.preserve();
461713 // Finally, use the analysis again on each function, forcing re-computation
462714 // for all of them.
463715 FPM.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
464 InstrCount +=
465 AM.getResult(F).Dep.InstructionCount;
716 auto &DoublyIndirectResult =
717 AM.getResult(F);
718 auto &IndirectResult = DoublyIndirectResult.IDep;
719 InstrCount += IndirectResult.FDep.InstructionCount;
720 FunctionCount += IndirectResult.MDep.FunctionCount;
466721 return PreservedAnalyses::all();
467722 }));
723
724 // Create a second function pass manager. This will cause the module-level
725 // invalidation to occur, which will force yet another invalidation of the
726 // indirect function-level analysis as the module analysis it depends on gets
727 // invalidated.
728 FunctionPassManager FPM2(/*DebugLogging*/ true);
729 FPM2.addPass(LambdaPass([&](Function &F, FunctionAnalysisManager &AM) {
730 auto &DoublyIndirectResult =
731 AM.getResult(F);
732 auto &IndirectResult = DoublyIndirectResult.IDep;
733 InstrCount += IndirectResult.FDep.InstructionCount;
734 FunctionCount += IndirectResult.MDep.FunctionCount;
735 return PreservedAnalyses::all();
736 }));
737
738 // Add a requires pass to populate the module analysis and then our function
739 // pass pipeline.
740 MPM.addPass(RequireAnalysisPass());
468741 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
742 // Now require the module analysis again (it will have been invalidated once)
743 // and then use it again from a function pass manager.
744 MPM.addPass(RequireAnalysisPass());
745 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM2)));
469746 MPM.run(*M, MAM);
470747
471748 // There are generally two possible runs for each of the three functions. But
472749 // for one function, we only invalidate the indirect analysis so the base one
473750 // only gets run five times.
474 EXPECT_EQ(5, AnalysisRuns);
751 EXPECT_EQ(5, FunctionAnalysisRuns);
752 // The module analysis pass should be run twice here.
753 EXPECT_EQ(2, ModuleAnalysisRuns);
475754 // The indirect analysis is invalidated for each function (either directly or
476755 // indirectly) and run twice for each.
477 EXPECT_EQ(6, IndirectAnalysisRuns);
478
479 // There are five instructions in the module and we add the count three
756 EXPECT_EQ(9, IndirectAnalysisRuns);
757 EXPECT_EQ(9, DoublyIndirectAnalysisRuns);
758
759 // There are five instructions in the module and we add the count four
480760 // times.
481 EXPECT_EQ(5 * 3, InstrCount);
482 }
483 }
761 EXPECT_EQ(5 * 4, InstrCount);
762
763 // There are three functions and we count them four times for each of the
764 // three functions.
765 EXPECT_EQ(3 * 4 * 3, FunctionCount);
766 }
767 }