llvm.org GIT mirror llvm / 8bf2780
[PM] Support invalidation of inner analysis managers from a pass over the outer IR unit. Summary: This never really got implemented, and was very hard to test before a lot of the refactoring changes to make things more robust. But now we can test it thoroughly and cleanly, especially at the CGSCC level. The core idea is that when an inner analysis manager proxy receives the invalidation event for the outer IR unit, it needs to walk the inner IR units and propagate it to the inner analysis manager for each of those units. For example, each function in the SCC needs to get an invalidation event when the SCC gets one. The function / module interaction is somewhat boring here. This really becomes interesting in the face of analysis-backed IR units. This patch effectively handles all of the CGSCC layer's needs -- both invalidating SCC analysis and invalidating function analysis when an SCC gets invalidated. However, this second aspect doesn't really handle the LoopAnalysisManager well at this point. That one will need some change of design in order to fully integrate, because unlike the call graph, the entire function behind a LoopAnalysis's results can vanish out from under us, and we won't even have a cached API to access. I'd like to try to separate solving the loop problems into a subsequent patch though in order to keep this more focused so I've adapted them to the API and updated the tests that immediately fail, but I've not added the level of testing and validation at that layer that I have at the CGSCC layer. An important aspect of this change is that the proxy for the FunctionAnalysisManager at the SCC pass layer doesn't work like the other proxies for an inner IR unit as it doesn't directly manage the FunctionAnalysisManager and invalidation or clearing of it. This would create an ever worsening problem of dual ownership of this responsibility, split between the module-level FAM proxy and this SCC-level FAM proxy. Instead, this patch changes the SCC-level FAM proxy to work in terms of the module-level proxy and defer to it to handle much of the updates. It only does SCC-specific invalidation. This will become more important in subsequent patches that support more complex invalidaiton scenarios. Reviewers: jlebar Subscribers: mehdi_amini, mcrosier, mzolotukhin, llvm-commits Differential Revision: https://reviews.llvm.org/D27197 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289317 91177308-0d34-0410-b5e6-96231b3b80d8 Chandler Carruth 2 years ago
11 changed file(s) with 658 addition(s) and 105 deletion(s). Raw diff Collapse all Expand all
144144 }
145145 };
146146
147 extern template class InnerAnalysisManagerProxy;
148147 /// A proxy from a \c CGSCCAnalysisManager to a \c Module.
149148 typedef InnerAnalysisManagerProxy
150149 CGSCCAnalysisManagerModuleProxy;
151150
152 extern template class OuterAnalysisManagerProxy
153 LazyCallGraph::SCC>;
151 /// We need a specialized result for the \c CGSCCAnalysisManagerModuleProxy so
152 /// it can have access to the call graph in order to walk all the SCCs when
153 /// invalidating things.
154 template <> class CGSCCAnalysisManagerModuleProxy::Result {
155 public:
156 explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G)
157 : InnerAM(&InnerAM), G(&G) {}
158
159 /// \brief Accessor for the analysis manager.
160 CGSCCAnalysisManager &getManager() { return *InnerAM; }
161
162 /// \brief Handler for invalidation of the Module.
163 ///
164 /// If the proxy analysis itself is preserved, then we assume that the set of
165 /// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the
166 /// CGSCCAnalysisManager are still valid, and we don't need to call \c clear
167 /// on the CGSCCAnalysisManager.
168 ///
169 /// Regardless of whether this analysis is marked as preserved, all of the
170 /// analyses in the \c CGSCCAnalysisManager are potentially invalidated based
171 /// on the set of preserved analyses.
172 bool invalidate(Module &M, const PreservedAnalyses &PA,
173 ModuleAnalysisManager::Invalidator &Inv);
174
175 private:
176 CGSCCAnalysisManager *InnerAM;
177 LazyCallGraph *G;
178 };
179
180 /// Provide a specialized run method for the \c CGSCCAnalysisManagerModuleProxy
181 /// so it can pass the lazy call graph to the result.
182 template <>
183 CGSCCAnalysisManagerModuleProxy::Result
184 CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager &AM);
185
186 // Ensure the \c CGSCCAnalysisManagerModuleProxy is provided as an extern
187 // template.
188 extern template class InnerAnalysisManagerProxy;
189
190 extern template class OuterAnalysisManagerProxy<
191 ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;
154192 /// A proxy from a \c ModuleAnalysisManager to an \c SCC.
155193 typedef OuterAnalysisManagerProxy
156194 LazyCallGraph &>
386424 } while (!RCWorklist.empty());
387425 }
388426
389 // By definition we preserve the proxy. We also preserve all analyses on
390 // SCCs. This precludes *any* invalidation of CGSCC analyses by the proxy,
391 // but that's OK because we've taken care to invalidate analyses in the
392 // CGSCC analysis manager incrementally above.
427 // By definition we preserve the call garph, all SCC analyses, and the
428 // analysis proxies by handling them above and in any nested pass managers.
429 PA.preserve();
393430 PA.preserve>();
394431 PA.preserve();
432 PA.preserve();
395433 return PA;
396434 }
397435
408446 return ModuleToPostOrderCGSCCPassAdaptor(std::move(Pass), DebugLogging);
409447 }
410448
411 extern template class InnerAnalysisManagerProxy
412 LazyCallGraph::SCC>;
413449 /// A proxy from a \c FunctionAnalysisManager to an \c SCC.
414 typedef InnerAnalysisManagerProxy
415 LazyCallGraph &>
416 FunctionAnalysisManagerCGSCCProxy;
450 ///
451 /// When a module pass runs and triggers invalidation, both the CGSCC and
452 /// Function analysis manager proxies on the module get an invalidation event.
453 /// We don't want to fully duplicate responsibility for most of the
454 /// invalidation logic. Instead, this layer is only responsible for SCC-local
455 /// invalidation events. We work with the module's FunctionAnalysisManager to
456 /// invalidate function analyses.
457 class FunctionAnalysisManagerCGSCCProxy
458 : public AnalysisInfoMixin {
459 public:
460 class Result {
461 public:
462 explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
463
464 /// \brief Accessor for the analysis manager.
465 FunctionAnalysisManager &getManager() { return *FAM; }
466
467 bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
468 CGSCCAnalysisManager::Invalidator &Inv);
469
470 private:
471 FunctionAnalysisManager *FAM;
472 };
473
474 /// Computes the \c FunctionAnalysisManager and stores it in the result proxy.
475 Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &);
476
477 private:
478 friend AnalysisInfoMixin;
479 static AnalysisKey Key;
480 };
481
482 // Ensure the \c FunctionAnalysisManagerCGSCCProxy is provided as an extern
483 // template.
484 extern template class InnerAnalysisManagerProxy<
485 FunctionAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;
417486
418487 extern template class OuterAnalysisManagerProxy;
419488 /// A proxy from a \c CGSCCAnalysisManager to a \c Function.
3737 /// pass manager infrastructure.
3838 typedef AnalysisManager LoopAnalysisManager;
3939
40 extern template class InnerAnalysisManagerProxy;
4140 /// A proxy from a \c LoopAnalysisManager to a \c Function.
4241 typedef InnerAnalysisManagerProxy
4342 LoopAnalysisManagerFunctionProxy;
43
44 /// Specialization of the invalidate method for the \c
45 /// LoopAnalysisManagerFunctionProxy's result.
46 template <>
47 bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
48 Function &F, const PreservedAnalyses &PA,
49 FunctionAnalysisManager::Invalidator &Inv);
50
51 // Ensure the \c LoopAnalysisManagerFunctionProxy is provided as an extern
52 // template.
53 extern template class InnerAnalysisManagerProxy;
4454
4555 extern template class OuterAnalysisManagerProxy;
4656 /// A proxy from a \c FunctionAnalysisManager to a \c Loop.
749749 public:
750750 class Result {
751751 public:
752 explicit Result(AnalysisManagerT &AM) : AM(&AM) {}
753 Result(Result &&Arg) : AM(std::move(Arg.AM)) {
752 explicit Result(AnalysisManagerT &InnerAM) : InnerAM(&InnerAM) {}
753 Result(Result &&Arg) : InnerAM(std::move(Arg.InnerAM)) {
754754 // We have to null out the analysis manager in the moved-from state
755755 // because we are taking ownership of the responsibilty to clear the
756756 // analysis state.
757 Arg.AM = nullptr;
757 Arg.InnerAM = nullptr;
758758 }
759759 Result &operator=(Result &&RHS) {
760 AM = RHS.AM;
760 InnerAM = RHS.InnerAM;
761761 // We have to null out the analysis manager in the moved-from state
762762 // because we are taking ownership of the responsibilty to clear the
763763 // analysis state.
764 RHS.AM = nullptr;
764 RHS.InnerAM = nullptr;
765765 return *this;
766766 }
767767 ~Result() {
768 // AM is cleared in a moved from state where there is nothing to do.
769 if (!AM)
768 // InnerAM is cleared in a moved from state where there is nothing to do.
769 if (!InnerAM)
770770 return;
771771
772772 // Clear out the analysis manager if we're being destroyed -- it means we
773773 // didn't even see an invalidate call when we got invalidated.
774 AM->clear();
774 InnerAM->clear();
775775 }
776776
777777 /// \brief Accessor for the analysis manager.
778 AnalysisManagerT &getManager() { return *AM; }
779
780 /// \brief Handler for invalidation of the module.
778 AnalysisManagerT &getManager() { return *InnerAM; }
779
780 /// \brief Handler for invalidation of the outer IR unit.
781781 ///
782782 /// If this analysis itself is preserved, then we assume that the set of \c
783 /// Function objects in the \c Module hasn't changed and thus we don't need
784 /// to invalidate *all* cached data associated with a \c Function* in the \c
785 /// FunctionAnalysisManager.
783 /// IR units that the inner analysis manager controls hasn't changed and
784 /// thus we don't need to invalidate *all* cached data associated with any
785 /// \c IRUnitT* in the \c AnalysisManagerT.
786786 ///
787787 /// Regardless of whether this analysis is marked as preserved, all of the
788 /// analyses in the \c FunctionAnalysisManager are potentially invalidated
789 /// based on the set of preserved analyses.
788 /// analyses in the \c AnalysisManagerT are potentially invalidated (for
789 /// the relevant inner set of their IR units) based on the set of preserved
790 /// analyses.
791 ///
792 /// Because this needs to understand the mapping from one IR unit to an
793 /// inner IR unit, this method isn't defined in the primary template.
794 /// Instead, each specialization of this template will need to provide an
795 /// explicit specialization of this method to handle that particular pair
796 /// of IR unit and inner AnalysisManagerT.
790797 bool invalidate(
791798 IRUnitT &IR, const PreservedAnalyses &PA,
792 typename AnalysisManager::Invalidator &) {
793 // If this proxy isn't marked as preserved, then we can't even invalidate
794 // individual function analyses, there may be an invalid set of Function
795 // objects in the cache making it impossible to incrementally preserve
796 // them. Just clear the entire manager.
797 if (!PA.preserved(InnerAnalysisManagerProxy::ID()))
798 AM->clear();
799
800 // Return false to indicate that this result is still a valid proxy.
801 return false;
802 }
799 typename AnalysisManager::Invalidator &Inv);
803800
804801 private:
805 AnalysisManagerT *AM;
802 AnalysisManagerT *InnerAM;
806803 };
807804
808 explicit InnerAnalysisManagerProxy(AnalysisManagerT &AM) : AM(&AM) {}
805 explicit InnerAnalysisManagerProxy(AnalysisManagerT &InnerAM)
806 : InnerAM(&InnerAM) {}
809807
810808 /// \brief Run the analysis pass and create our proxy result object.
811809 ///
816814 /// In debug builds, it will also assert that the analysis manager is empty
817815 /// as no queries should arrive at the function analysis manager prior to
818816 /// this analysis being requested.
819 Result run(IRUnitT &IR, AnalysisManager &,
817 Result run(IRUnitT &IR, AnalysisManager &AM,
820818 ExtraArgTs...) {
821 return Result(*AM);
819 return Result(*InnerAM);
822820 }
823821
824822 private:
826824 InnerAnalysisManagerProxy>;
827825 static AnalysisKey Key;
828826
829 AnalysisManagerT *AM;
827 AnalysisManagerT *InnerAM;
830828 };
831829
832830 template
833831 AnalysisKey
834832 InnerAnalysisManagerProxy::Key;
835833
836 extern template class InnerAnalysisManagerProxy
837 Module>;
838834 /// Provide the \c FunctionAnalysisManager to \c Module proxy.
839835 typedef InnerAnalysisManagerProxy
840836 FunctionAnalysisManagerModuleProxy;
837
838 /// Specialization of the invalidate method for the \c
839 /// FunctionAnalysisManagerModuleProxy's result.
840 template <>
841 bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
842 Module &M, const PreservedAnalyses &PA,
843 ModuleAnalysisManager::Invalidator &Inv);
844
845 // Ensure the \c FunctionAnalysisManagerModuleProxy is provided as an extern
846 // template.
847 extern template class InnerAnalysisManagerProxy
848 Module>;
841849
842850 /// \brief A function analysis which acts as a proxy for a module analysis
843851 /// manager.
1212
1313 using namespace llvm;
1414
15 // Explicit template instantiations and specialization defininitions for core
16 // template typedefs.
1517 namespace llvm {
1618
1719 // Explicit instantiations for the core proxy templates.
2123 LazyCallGraph &, CGSCCUpdateResult &>;
2224 template class InnerAnalysisManagerProxy;
2325 template class OuterAnalysisManagerProxy
24 LazyCallGraph::SCC>;
26 LazyCallGraph::SCC, LazyCallGraph &>;
2527 template class InnerAnalysisManagerProxy
26 LazyCallGraph::SCC>;
28 LazyCallGraph::SCC, LazyCallGraph &>;
2729 template class OuterAnalysisManagerProxy;
2830
2931 /// Explicitly specialize the pass manager run method to handle call graph
8183 dbgs() << "Finished CGSCC pass manager run.\n";
8284
8385 return PA;
86 }
87
88 bool CGSCCAnalysisManagerModuleProxy::Result::invalidate(
89 Module &M, const PreservedAnalyses &PA,
90 ModuleAnalysisManager::Invalidator &Inv) {
91 // If this proxy or the call graph is going to be invalidated, we also need
92 // to clear all the keys coming from that analysis.
93 //
94 // We also directly invalidate the FAM's module proxy if necessary, and if
95 // that proxy isn't preserved we can't preserve this proxy either. We rely on
96 // it to handle module -> function analysis invalidation in the face of
97 // structural changes and so if it's unavailable we conservatively clear the
98 // entire SCC layer as well rather than trying to do invaliadtion ourselves.
99 if (!PA.preserved() ||
100 Inv.invalidate(M, PA) ||
101 Inv.invalidate(M, PA)) {
102 InnerAM->clear();
103
104 // And the proxy itself should be marked as invalid so that we can observe
105 // the new call graph. This isn't strictly necessary because we cheat
106 // above, but is still useful.
107 return true;
108 }
109
110 // Ok, we have a graph, so we can propagate the invalidation down into it.
111 for (auto &RC : G->postorder_ref_sccs())
112 for (auto &C : RC)
113 InnerAM->invalidate(C, PA);
114
115 // Return false to indicate that this result is still a valid proxy.
116 return false;
117 }
118
119 template <>
120 CGSCCAnalysisManagerModuleProxy::Result
121 CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager &AM) {
122 // Force the Function analysis manager to also be available so that it can
123 // be accessed in an SCC analysis and proxied onward to function passes.
124 // FIXME: It is pretty awkward to just drop the result here and assert that
125 // we can find it again later.
126 (void)AM.getResult(M);
127
128 return Result(*InnerAM, AM.getResult(M));
129 }
130
131 AnalysisKey FunctionAnalysisManagerCGSCCProxy::Key;
132
133 FunctionAnalysisManagerCGSCCProxy::Result
134 FunctionAnalysisManagerCGSCCProxy::run(LazyCallGraph::SCC &C,
135 CGSCCAnalysisManager &AM,
136 LazyCallGraph &CG) {
137 // Collect the FunctionAnalysisManager from the Module layer and use that to
138 // build the proxy result.
139 //
140 // This allows us to rely on the FunctionAnalysisMangaerModuleProxy to
141 // invalidate the function analyses.
142 auto &MAM = AM.getResult(C, CG).getManager();
143 Module &M = *C.begin()->getFunction().getParent();
144 auto *FAMProxy = MAM.getCachedResult(M);
145 assert(FAMProxy && "The CGSCC pass manager requires that the FAM module "
146 "proxy is run on the module prior to entering the CGSCC "
147 "walk.");
148
149 // Note that we special-case invalidation handling of this proxy in the CGSCC
150 // analysis manager's Module proxy. This avoids the need to do anything
151 // special here to recompute all of this if ever the FAM's module proxy goes
152 // away.
153 return Result(FAMProxy->getManager());
154 }
155
156 bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate(
157 LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
158 CGSCCAnalysisManager::Invalidator &Inv) {
159 for (LazyCallGraph::Node &N : C)
160 FAM->invalidate(N.getFunction(), PA);
161
162 // This proxy doesn't need to handle invalidation itself. Instead, the
163 // module-level CGSCC proxy handles it above by ensuring that if the
164 // module-level FAM proxy becomes invalid the entire SCC layer, which
165 // includes this proxy, is cleared.
166 return false;
84167 }
85168
86169 } // End llvm namespace
1616
1717 using namespace llvm;
1818
19 // Explicit instantiations for core typedef'ed templates.
19 // Explicit template instantiations and specialization defininitions for core
20 // template typedefs.
2021 namespace llvm {
2122 template class PassManager;
2223 template class AnalysisManager;
2324 template class InnerAnalysisManagerProxy;
2425 template class OuterAnalysisManagerProxy;
26
27 template <>
28 bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
29 Function &F, const PreservedAnalyses &PA,
30 FunctionAnalysisManager::Invalidator &Inv) {
31 // If this proxy isn't marked as preserved, the set of Function objects in
32 // the module may have changed. We therefore can't call
33 // InnerAM->invalidate(), because any pointers to Functions it has may be
34 // stale.
35 if (!PA.preserved(LoopAnalysisManagerFunctionProxy::ID()))
36 InnerAM->clear();
37
38 // FIXME: Proper suppor for invalidation isn't yet implemented for the LPM.
39
40 // Return false to indicate that this result is still a valid proxy.
41 return false;
42 }
2543 }
2644
2745 PreservedAnalyses llvm::getLoopPassPreservedAnalyses() {
1212
1313 using namespace llvm;
1414
15 // Explicit template instantiations for core template typedefs.
15 // Explicit template instantiations and specialization defininitions for core
16 // template typedefs.
1617 namespace llvm {
1718 template class AllAnalysesOn;
1819 template class AllAnalysesOn;
2223 template class AnalysisManager;
2324 template class InnerAnalysisManagerProxy;
2425 template class OuterAnalysisManagerProxy;
26
27 template <>
28 bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
29 Module &M, const PreservedAnalyses &PA,
30 ModuleAnalysisManager::Invalidator &Inv) {
31 // If this proxy isn't marked as preserved, then even if the result remains
32 // valid, the key itself may no longer be valid, so we clear everything.
33 //
34 // Note that in order to preserve this proxy, a module pass must ensure that
35 // the FAM has been completely updated to handle the deletion of functions.
36 // Specifically, any FAM-cached results for those functions need to have been
37 // forcibly cleared. When preserved, this proxy will only invalidate results
38 // cached on functions *still in the module* at the end of the module pass.
39 if (!PA.preserved(FunctionAnalysisManagerModuleProxy::ID())) {
40 InnerAM->clear();
41 return true;
42 }
43
44 // Otherwise propagate the invalidation event to all the remaining IR units.
45 for (Function &F : M)
46 InnerAM->invalidate(F, PA);
47
48 // Return false to indicate that this result is still a valid proxy.
49 return false;
50 }
2551 }
2652
2753 AnalysisKey PreservedAnalyses::AllAnalysesKey;
768768 ModuleAnalysisManager &MAM) {
769769 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
770770 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
771 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
772771 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
773772 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
774773 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
7878 #define CGSCC_ANALYSIS(NAME, CREATE_PASS)
7979 #endif
8080 CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
81 CGSCC_ANALYSIS("fam-proxy", FunctionAnalysisManagerCGSCCProxy())
8182 #undef CGSCC_ANALYSIS
8283
8384 #ifndef CGSCC_PASS
1919 ; RUN: | FileCheck %s --check-prefix=CHECK-CGSCC-PASS
2020 ; CHECK-CGSCC-PASS: Starting llvm::Module pass manager run
2121 ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor
22 ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}>
22 ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}CGSCCAnalysisManager{{.*}}>
23 ; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}FunctionAnalysisManager{{.*}}>
2324 ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis
2425 ; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]
2526 ; CHECK-CGSCC-PASS-NEXT: Starting CGSCC pass manager run
377378 ; RUN: | FileCheck %s --check-prefix=CHECK-REPEAT-CGSCC-PASS
378379 ; CHECK-REPEAT-CGSCC-PASS: Starting llvm::Module pass manager run
379380 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor
380 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}>
381 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}CGSCCAnalysisManager{{.*}}>
382 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}FunctionAnalysisManager{{.*}}>
381383 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis
382384 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]
383385 ; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting CGSCC pass manager run
121121
122122 AnalysisKey TestImmutableFunctionAnalysis::Key;
123123
124 struct LambdaModulePass : public PassInfoMixin {
125 template
126 LambdaModulePass(T &&Arg) : Func(std::forward(Arg)) {}
127
128 PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) {
129 return Func(F, AM);
130 }
131
132 std::function Func;
133 };
134
124135 struct LambdaSCCPass : public PassInfoMixin {
125136 template LambdaSCCPass(T &&Arg) : Func(std::forward(Arg)) {}
126 // We have to explicitly define all the special member functions because MSVC
127 // refuses to generate them.
128 LambdaSCCPass(LambdaSCCPass &&Arg) : Func(std::move(Arg.Func)) {}
129 LambdaSCCPass &operator=(LambdaSCCPass &&RHS) {
130 Func = std::move(RHS.Func);
131 return *this;
132 }
133137
134138 PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
135139 LazyCallGraph &CG, CGSCCUpdateResult &UR) {
142146 };
143147
144148 struct LambdaFunctionPass : public PassInfoMixin {
145 template LambdaFunctionPass(T &&Arg) : Func(std::forward(Arg)) {}
146 // We have to explicitly define all the special member functions because MSVC
147 // refuses to generate them.
148 LambdaFunctionPass(LambdaFunctionPass &&Arg) : Func(std::move(Arg.Func)) {}
149 LambdaFunctionPass &operator=(LambdaFunctionPass &&RHS) {
150 Func = std::move(RHS.Func);
151 return *this;
152 }
149 template
150 LambdaFunctionPass(T &&Arg) : Func(std::forward(Arg)) {}
153151
154152 PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
155153 return Func(F, AM);
231229 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
232230 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
233231 MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM); });
234 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM); });
232 CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(); });
235233 CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM); });
236234 FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM); });
237235 FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM); });
256254 MPM.addPass(RequireAnalysisPass());
257255
258256 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
257 FunctionPassManager FPM1(/*DebugLogging*/ true);
258 int FunctionPassRunCount1 = 0;
259 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
260 ++FunctionPassRunCount1;
261 return PreservedAnalyses::none();
262 }));
263 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
264
259265 int SCCPassRunCount1 = 0;
260266 int AnalyzedInstrCount1 = 0;
261267 int AnalyzedSCCFunctionCount1 = 0;
288294 return PreservedAnalyses::all();
289295 }));
290296
291 FunctionPassManager FPM1(/*DebugLogging*/ true);
292 int FunctionPassRunCount1 = 0;
293 FPM1.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
294 ++FunctionPassRunCount1;
295 return PreservedAnalyses::all();
296 }));
297 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
297 FunctionPassManager FPM2(/*DebugLogging*/ true);
298 int FunctionPassRunCount2 = 0;
299 FPM2.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
300 ++FunctionPassRunCount2;
301 return PreservedAnalyses::none();
302 }));
303 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
304
298305 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
299306
300 MPM.run(*M, MAM);
307 FunctionPassManager FPM3(/*DebugLogging*/ true);
308 int FunctionPassRunCount3 = 0;
309 FPM3.addPass(LambdaFunctionPass([&](Function &, FunctionAnalysisManager &) {
310 ++FunctionPassRunCount3;
311 return PreservedAnalyses::none();
312 }));
313 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3)));
314
315 MPM.run(*M, MAM);
316
317 EXPECT_EQ(4, SCCPassRunCount1);
318 EXPECT_EQ(6, FunctionPassRunCount1);
319 EXPECT_EQ(6, FunctionPassRunCount2);
320 EXPECT_EQ(6, FunctionPassRunCount3);
301321
302322 EXPECT_EQ(1, ModuleAnalysisRuns);
303323 EXPECT_EQ(4, SCCAnalysisRuns);
304324 EXPECT_EQ(6, FunctionAnalysisRuns);
305325 EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
306326
307 EXPECT_EQ(4, SCCPassRunCount1);
308327 EXPECT_EQ(14, AnalyzedInstrCount1);
309328 EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
310329 EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
472491 EXPECT_FALSE(FoundModuleAnalysis3);
473492 }
474493
475 }
494 // Test that a Module pass which fails to preserve an SCC analysis in fact
495 // invalidates that analysis.
496 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) {
497 int SCCAnalysisRuns = 0;
498 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
499
500 ModulePassManager MPM(/*DebugLogging*/ true);
501
502 // First force the analysis to be run.
503 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
504 CGPM1.addPass(RequireAnalysisPass
505 CGSCCAnalysisManager, LazyCallGraph &,
506 CGSCCUpdateResult &>());
507 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
508
509 // Now run a module pass that preserves the LazyCallGraph and the proxy but
510 // not the SCC analysis.
511 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
512 PreservedAnalyses PA;
513 PA.preserve();
514 PA.preserve();
515 PA.preserve();
516 return PA;
517 }));
518
519 // And now a second CGSCC run which requires the SCC analysis again. This
520 // will trigger re-running it.
521 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
522 CGPM2.addPass(RequireAnalysisPass
523 CGSCCAnalysisManager, LazyCallGraph &,
524 CGSCCUpdateResult &>());
525 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
526
527 MPM.run(*M, MAM);
528 // Two runs and four SCCs.
529 EXPECT_EQ(2 * 4, SCCAnalysisRuns);
530 }
531
532 // Check that marking the SCC analysis preserved is sufficient to avoid
533 // invaliadtion. This should only run the analysis once for each SCC.
534 TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) {
535 int SCCAnalysisRuns = 0;
536 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
537
538 ModulePassManager MPM(/*DebugLogging*/ true);
539
540 // First force the analysis to be run.
541 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
542 CGPM1.addPass(RequireAnalysisPass
543 CGSCCAnalysisManager, LazyCallGraph &,
544 CGSCCUpdateResult &>());
545 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
546
547 // Now run a module pass that preserves each of the necessary components
548 // (but not everything).
549 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
550 PreservedAnalyses PA;
551 PA.preserve();
552 PA.preserve();
553 PA.preserve();
554 PA.preserve();
555 return PA;
556 }));
557
558 // And now a second CGSCC run which requires the SCC analysis again but find
559 // it in the cache.
560 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
561 CGPM2.addPass(RequireAnalysisPass
562 CGSCCAnalysisManager, LazyCallGraph &,
563 CGSCCUpdateResult &>());
564 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
565
566 MPM.run(*M, MAM);
567 // Four SCCs
568 EXPECT_EQ(4, SCCAnalysisRuns);
569 }
570
571 // Check that even when the analysis is preserved, if the SCC information isn't
572 // we still nuke things because the SCC keys could change.
573 TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange) {
574 int SCCAnalysisRuns = 0;
575 CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
576
577 ModulePassManager MPM(/*DebugLogging*/ true);
578
579 // First force the analysis to be run.
580 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
581 CGPM1.addPass(RequireAnalysisPass
582 CGSCCAnalysisManager, LazyCallGraph &,
583 CGSCCUpdateResult &>());
584 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
585
586 // Now run a module pass that preserves the analysis but not the call
587 // graph or proxy.
588 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
589 PreservedAnalyses PA;
590 PA.preserve();
591 return PA;
592 }));
593
594 // And now a second CGSCC run which requires the SCC analysis again.
595 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
596 CGPM2.addPass(RequireAnalysisPass
597 CGSCCAnalysisManager, LazyCallGraph &,
598 CGSCCUpdateResult &>());
599 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
600
601 MPM.run(*M, MAM);
602 // Two runs and four SCCs.
603 EXPECT_EQ(2 * 4, SCCAnalysisRuns);
604 }
605
606 // Test that an SCC pass which fails to preserve a Function analysis in fact
607 // invalidates that analysis.
608 TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) {
609 int FunctionAnalysisRuns = 0;
610 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
611
612 // Create a very simple module with a single function and SCC to make testing
613 // these issues much easier.
614 std::unique_ptr M = parseIR("declare void @g()\n"
615 "declare void @h()\n"
616 "define void @f() {\n"
617 "entry:\n"
618 " call void @g()\n"
619 " call void @h()\n"
620 " ret void\n"
621 "}\n");
622
623 CGSCCPassManager CGPM(/*DebugLogging*/ true);
624
625 // First force the analysis to be run.
626 FunctionPassManager FPM1(/*DebugLogging*/ true);
627 FPM1.addPass(RequireAnalysisPass());
628 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
629
630 // Now run a module pass that preserves the LazyCallGraph and proxy but not
631 // the SCC analysis.
632 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
633 LazyCallGraph &, CGSCCUpdateResult &) {
634 PreservedAnalyses PA;
635 PA.preserve();
636 return PA;
637 }));
638
639 // And now a second CGSCC run which requires the SCC analysis again. This
640 // will trigger re-running it.
641 FunctionPassManager FPM2(/*DebugLogging*/ true);
642 FPM2.addPass(RequireAnalysisPass());
643 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
644
645 ModulePassManager MPM(/*DebugLogging*/ true);
646 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
647 MPM.run(*M, MAM);
648 EXPECT_EQ(2, FunctionAnalysisRuns);
649 }
650
651 // Check that marking the SCC analysis preserved is sufficient. This should
652 // only run the analysis once the SCC.
653 TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) {
654 int FunctionAnalysisRuns = 0;
655 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
656
657 // Create a very simple module with a single function and SCC to make testing
658 // these issues much easier.
659 std::unique_ptr M = parseIR("declare void @g()\n"
660 "declare void @h()\n"
661 "define void @f() {\n"
662 "entry:\n"
663 " call void @g()\n"
664 " call void @h()\n"
665 " ret void\n"
666 "}\n");
667
668 CGSCCPassManager CGPM(/*DebugLogging*/ true);
669
670 // First force the analysis to be run.
671 FunctionPassManager FPM1(/*DebugLogging*/ true);
672 FPM1.addPass(RequireAnalysisPass());
673 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
674
675 // Now run a module pass that preserves each of the necessary components
676 // (but
677 // not everything).
678 CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C, CGSCCAnalysisManager &,
679 LazyCallGraph &, CGSCCUpdateResult &) {
680 PreservedAnalyses PA;
681 PA.preserve();
682 PA.preserve();
683 return PA;
684 }));
685
686 // And now a second CGSCC run which requires the SCC analysis again but find
687 // it in the cache.
688 FunctionPassManager FPM2(/*DebugLogging*/ true);
689 FPM2.addPass(RequireAnalysisPass());
690 CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
691
692 ModulePassManager MPM(/*DebugLogging*/ true);
693 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
694 MPM.run(*M, MAM);
695 EXPECT_EQ(1, FunctionAnalysisRuns);
696 }
697
698 // Note that there is no test for invalidating the call graph or other
699 // structure with an SCC pass because there is no mechanism to do that from
700 // withinsuch a pass. Instead, such a pass has to directly update the call
701 // graph structure.
702
703 // Test that a madule pass invalidates function analyses when the CGSCC proxies
704 // and pass manager.
705 TEST_F(CGSCCPassManagerTest,
706 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) {
707 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
708
709 int FunctionAnalysisRuns = 0;
710 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
711
712 ModulePassManager MPM(/*DebugLogging*/ true);
713
714 // First force the analysis to be run.
715 FunctionPassManager FPM1(/*DebugLogging*/ true);
716 FPM1.addPass(RequireAnalysisPass());
717 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
718 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
719 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
720
721 // Now run a module pass that preserves the LazyCallGraph and proxy but not
722 // the Function analysis.
723 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
724 PreservedAnalyses PA;
725 PA.preserve();
726 PA.preserve();
727 return PA;
728 }));
729
730 // And now a second CGSCC run which requires the SCC analysis again. This
731 // will trigger re-running it.
732 FunctionPassManager FPM2(/*DebugLogging*/ true);
733 FPM2.addPass(RequireAnalysisPass());
734 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
735 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
736 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
737
738 MPM.run(*M, MAM);
739 // Two runs and 6 functions.
740 EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
741 }
742
743 // Check that by marking the function pass and FAM proxy as preserved, this
744 // propagates all the way through.
745 TEST_F(CGSCCPassManagerTest,
746 TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) {
747 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
748
749 int FunctionAnalysisRuns = 0;
750 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
751
752 ModulePassManager MPM(/*DebugLogging*/ true);
753
754 // First force the analysis to be run.
755 FunctionPassManager FPM1(/*DebugLogging*/ true);
756 FPM1.addPass(RequireAnalysisPass());
757 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
758 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
759 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
760
761 // Now run a module pass that preserves the LazyCallGraph, the proxy, and
762 // the Function analysis.
763 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
764 PreservedAnalyses PA;
765 PA.preserve();
766 PA.preserve();
767 PA.preserve();
768 PA.preserve();
769 return PA;
770 }));
771
772 // And now a second CGSCC run which requires the SCC analysis again. This
773 // will trigger re-running it.
774 FunctionPassManager FPM2(/*DebugLogging*/ true);
775 FPM2.addPass(RequireAnalysisPass());
776 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
777 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
778 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
779
780 MPM.run(*M, MAM);
781 // One run and 6 functions.
782 EXPECT_EQ(6, FunctionAnalysisRuns);
783 }
784
785 // Check that if the lazy call graph itself isn't preserved we still manage to
786 // invalidate everything.
787 TEST_F(CGSCCPassManagerTest,
788 TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange) {
789 MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
790
791 int FunctionAnalysisRuns = 0;
792 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
793
794 ModulePassManager MPM(/*DebugLogging*/ true);
795
796 // First force the analysis to be run.
797 FunctionPassManager FPM1(/*DebugLogging*/ true);
798 FPM1.addPass(RequireAnalysisPass());
799 CGSCCPassManager CGPM1(/*DebugLogging*/ true);
800 CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
801 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
802
803 // Now run a module pass that preserves the LazyCallGraph but not the
804 // Function analysis.
805 MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
806 PreservedAnalyses PA;
807 return PA;
808 }));
809
810 // And now a second CGSCC run which requires the SCC analysis again. This
811 // will trigger re-running it.
812 FunctionPassManager FPM2(/*DebugLogging*/ true);
813 FPM2.addPass(RequireAnalysisPass());
814 CGSCCPassManager CGPM2(/*DebugLogging*/ true);
815 CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
816 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
817
818 MPM.run(*M, MAM);
819 // Two runs and 6 functions.
820 EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
821 }
822 }
8787 struct TestPreservingModulePass : PassInfoMixin {
8888 PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
8989 return PreservedAnalyses::all();
90 }
91 };
92
93 struct TestMinPreservingModulePass
94 : PassInfoMixin {
95 PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
96 PreservedAnalyses PA;
97
98 // Force running an analysis.
99 (void)AM.getResult(M);
100
101 PA.preserve();
102 return PA;
10390 }
10491 };
10592
214201 }
215202
216203 TEST_F(PassManagerTest, Basic) {
217 FunctionAnalysisManager FAM;
204 FunctionAnalysisManager FAM(/*DebugLogging*/ true);
218205 int FunctionAnalysisRuns = 0;
219206 FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns); });
220207
221 ModuleAnalysisManager MAM;
208 ModuleAnalysisManager MAM(/*DebugLogging*/ true);
222209 int ModuleAnalysisRuns = 0;
223210 MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns); });
224211 MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM); });
232219 int AnalyzedFunctionCount1 = 0;
233220 {
234221 // Pointless scoped copy to test move assignment.
235 ModulePassManager NestedMPM;
222 ModulePassManager NestedMPM(/*DebugLogging*/ true);
236223 FunctionPassManager FPM;
237224 {
238225 // Pointless scope to test move assignment.
239 FunctionPassManager NestedFPM;
226 FunctionPassManager NestedFPM(/*DebugLogging*/ true);
240227 NestedFPM.addPass(TestFunctionPass(
241228 FunctionPassRunCount1, AnalyzedInstrCount1, AnalyzedFunctionCount1));
242229 FPM = std::move(NestedFPM);
254241 int AnalyzedInstrCount2 = 0;
255242 int AnalyzedFunctionCount2 = 0;
256243 {
257 FunctionPassManager FPM;
244 FunctionPassManager FPM(/*DebugLogging*/ true);
258245 FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2,
259246 AnalyzedFunctionCount2));
260247 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
267254 int AnalyzedInstrCount3 = 0;
268255 int AnalyzedFunctionCount3 = 0;
269256 {
270 FunctionPassManager FPM;
257 FunctionPassManager FPM(/*DebugLogging*/ true);
271258 FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3,
272259 AnalyzedFunctionCount3));
273260 FPM.addPass(TestInvalidationFunctionPass("f"));
274261 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
275262 }
276263
277 // A fourth function pass manager but with a minimal intervening passes.
278 MPM.addPass(TestMinPreservingModulePass());
264 // A fourth function pass manager but with only preserving intervening
265 // passes but triggering the module analysis.
266 MPM.addPass(RequireAnalysisPass());
279267 int FunctionPassRunCount4 = 0;
280268 int AnalyzedInstrCount4 = 0;
281269 int AnalyzedFunctionCount4 = 0;
286274 MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
287275 }
288276
289 // A fifth function pass manager but which uses only cached results.
277 // A fifth function pass manager which invalidates one function first but
278 // uses only cached results.
290279 int FunctionPassRunCount5 = 0;
291280 int AnalyzedInstrCount5 = 0;
292281 int AnalyzedFunctionCount5 = 0;
293282 {
294 FunctionPassManager FPM;
283 FunctionPassManager FPM(/*DebugLogging*/ true);
295284 FPM.addPass(TestInvalidationFunctionPass("f"));
296285 FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5,
297286 AnalyzedFunctionCount5,
316305 EXPECT_EQ(0, AnalyzedFunctionCount3);
317306 EXPECT_EQ(3, FunctionPassRunCount4);
318307 EXPECT_EQ(5, AnalyzedInstrCount4);
319 EXPECT_EQ(0, AnalyzedFunctionCount4);
308 EXPECT_EQ(9, AnalyzedFunctionCount4);
320309 EXPECT_EQ(3, FunctionPassRunCount5);
321310 EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
322 EXPECT_EQ(0, AnalyzedFunctionCount5);
311 EXPECT_EQ(9, AnalyzedFunctionCount5);
323312
324313 // Validate the analysis counters:
325314 // first run over 3 functions, then module pass invalidates
326315 // second run over 3 functions, nothing invalidates
327316 // third run over 0 functions, but 1 function invalidated
328317 // fourth run over 1 function
318 // fifth run invalidates 1 function first, but runs over 0 functions
329319 EXPECT_EQ(7, FunctionAnalysisRuns);
330320
331321 EXPECT_EQ(1, ModuleAnalysisRuns);