diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 833547a23ac..4a64f20c49a 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -74,20 +74,99 @@ template struct PassModel : PassConcept { PassT Pass; }; +/// \brief Abstract concept of an analysis result. +/// +/// This concept is parameterized over the IR unit that this result pertains +/// to. +template struct AnalysisResultConcept { + virtual ~AnalysisResultConcept() {} + virtual AnalysisResultConcept *clone() = 0; + + /// \brief Method to try and mark a result as invalid. + /// + /// When the outer \c AnalysisManager detects a change in some underlying + /// unit of the IR, it will call this method on all of the results cached. + /// + /// \returns true if the result should indeed be invalidated (the default). + virtual bool invalidate(IRUnitT *IR) = 0; +}; + +/// \brief Wrapper to model the analysis result concept. +/// +/// Can wrap any type which implements a suitable invalidate member and model +/// the AnalysisResultConcept for the AnalysisManager. +template +struct AnalysisResultModel : AnalysisResultConcept { + AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {} + virtual AnalysisResultModel *clone() { + return new AnalysisResultModel(Result); + } + + /// \brief The model delegates to the \c ResultT method. + virtual bool invalidate(IRUnitT *IR) { return Result.invalidate(IR); } + + ResultT Result; +}; + +/// \brief Abstract concept of an analysis pass. +/// +/// This concept is parameterized over the IR unit that it can run over and +/// produce an analysis result. +template struct AnalysisPassConcept { + virtual ~AnalysisPassConcept() {} + virtual AnalysisPassConcept *clone() = 0; + + /// \brief Method to run this analysis over a unit of IR. + /// \returns The analysis result object to be queried by users, the caller + /// takes ownership. + virtual AnalysisResultConcept *run(IRUnitT *IR) = 0; +}; + +/// \brief Wrapper to model the analysis pass concept. +/// +/// Can wrap any type which implements a suitable \c run method. The method +/// must accept the IRUnitT as an argument and produce an object which can be +/// wrapped in a \c AnalysisResultModel. +template +struct AnalysisPassModel : AnalysisPassConcept { + AnalysisPassModel(PassT Pass) : Pass(llvm_move(Pass)) {} + virtual AnalysisPassModel *clone() { return new AnalysisPassModel(Pass); } + + // FIXME: Replace PassT::IRUnitT with type traits when we use C++11. + typedef typename PassT::IRUnitT IRUnitT; + + // FIXME: Replace PassT::Result with type traits when we use C++11. + typedef AnalysisResultModel ResultModelT; + + /// \brief The model delegates to the \c PassT::run method. + /// + /// The return is wrapped in an \c AnalysisResultModel. + virtual ResultModelT *run(IRUnitT *IR) { + return new ResultModelT(Pass.run(IR)); + } + + PassT Pass; +}; + } -class AnalysisManager; +class ModuleAnalysisManager; class ModulePassManager { public: - ModulePassManager(Module *M, AnalysisManager *AM = 0) : M(M), AM(AM) {} + explicit ModulePassManager(ModuleAnalysisManager *AM = 0) : AM(AM) {} + + /// \brief Run all of the module passes in this module pass manager over + /// a module. + /// + /// This method should only be called for a single module as there is the + /// expectation that the lifetime of a pass is bounded to that of a module. + void run(Module *M); template void addPass(ModulePassT Pass) { Passes.push_back(new ModulePassModel(llvm_move(Pass))); } - void run(); - private: // Pull in the concept type and model template specialized for modules. typedef detail::PassConcept ModulePassConcept; @@ -96,14 +175,15 @@ private: ModulePassModel(PassT Pass) : detail::PassModel(Pass) {} }; - Module *M; - AnalysisManager *AM; + ModuleAnalysisManager *AM; std::vector > Passes; }; +class FunctionAnalysisManager; + class FunctionPassManager { public: - FunctionPassManager(AnalysisManager *AM = 0) : AM(AM) {} + explicit FunctionPassManager(FunctionAnalysisManager *AM = 0) : AM(AM) {} template void addPass(FunctionPassT Pass) { Passes.push_back(new FunctionPassModel(llvm_move(Pass))); @@ -120,58 +200,30 @@ private: : detail::PassModel(Pass) {} }; - AnalysisManager *AM; + FunctionAnalysisManager *AM; std::vector > Passes; }; - -/// \brief An analysis manager to coordinate and cache analyses run over -/// a module. -/// -/// The analysis manager is typically used by passes in a pass pipeline -/// (consisting potentially of several individual pass managers) over a module -/// of IR. It provides registration of available analyses, declaring -/// requirements on support for specific analyses, running of an specific -/// analysis over a specific unit of IR to compute an analysis result, and -/// caching of the analysis results to reuse them across multiple passes. -/// -/// It is the responsibility of callers to use the invalidation API to -/// invalidate analysis results when the IR they correspond to changes. The -/// \c ModulePassManager and \c FunctionPassManager do this automatically. -class AnalysisManager { +/// \brief A module analysis pass manager with lazy running and caching of +/// results. +class ModuleAnalysisManager { public: - AnalysisManager(Module *M) : M(M) {} + ModuleAnalysisManager() {} /// \brief Get the result of an analysis pass for this module. /// /// If there is not a valid cached result in the manager already, this will /// re-run the analysis to produce a valid result. - /// - /// The module passed in must be the same module as the analysis manager was - /// constructed around. - template - const typename PassT::Result &getResult(Module *M) { + template const typename PassT::Result &getResult(Module *M) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Module."); assert(ModuleAnalysisPasses.count(PassT::ID()) && "This analysis pass was not registered prior to being queried"); - const AnalysisResultConcept &ResultConcept = + const detail::AnalysisResultConcept &ResultConcept = getResultImpl(PassT::ID(), M); - typedef AnalysisResultModel ResultModelT; - return static_cast(ResultConcept).Result; - } - - /// \brief Get the result of an analysis pass for a function. - /// - /// If there is not a valid cached result in the manager already, this will - /// re-run the analysis to produce a valid result. - template - const typename PassT::Result &getResult(Function *F) { - assert(FunctionAnalysisPasses.count(PassT::ID()) && - "This analysis pass was not registered prior to being queried"); - - const AnalysisResultConcept &ResultConcept = - getResultImpl(PassT::ID(), F); - typedef AnalysisResultModel ResultModelT; + typedef detail::AnalysisResultModel + ResultModelT; return static_cast(ResultConcept).Result; } @@ -182,24 +234,26 @@ public: /// manager. Whomever is setting up analysis passes must use this to /// populate /// the manager with all of the analysis passes available. - template void registerAnalysisPass(PassT Pass) { - registerAnalysisPassImpl(llvm_move(Pass)); + template void registerPass(PassT Pass) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Module."); + assert(!ModuleAnalysisPasses.count(PassT::ID()) && + "Registered the same analysis pass twice!"); + ModuleAnalysisPasses[PassT::ID()] = + new detail::AnalysisPassModel(llvm_move(Pass)); } /// \brief Invalidate a specific analysis pass for an IR module. /// /// Note that the analysis result can disregard invalidation. template void invalidate(Module *M) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Module."); + assert(ModuleAnalysisPasses.count(PassT::ID()) && + "This analysis pass was not registered prior to being invalidated"); invalidateImpl(PassT::ID(), M); } - /// \brief Invalidate a specific analysis pass for an IR function. - /// - /// Note that the analysis result can disregard invalidation. - template void invalidate(Function *F) { - invalidateImpl(PassT::ID(), F); - } - /// \brief Invalidate analyses cached for an IR Module. /// /// Note that specific analysis results can disregard invalidation by @@ -209,6 +263,82 @@ public: /// around. void invalidateAll(Module *M); +private: + /// \brief Get a module pass result, running the pass if necessary. + const detail::AnalysisResultConcept &getResultImpl(void *PassID, + Module *M); + + /// \brief Invalidate a module pass result. + void invalidateImpl(void *PassID, Module *M); + + /// \brief Map type from module analysis pass ID to pass concept pointer. + typedef DenseMap > > + ModuleAnalysisPassMapT; + + /// \brief Collection of module analysis passes, indexed by ID. + ModuleAnalysisPassMapT ModuleAnalysisPasses; + + /// \brief Map type from module analysis pass ID to pass result concept pointer. + typedef DenseMap > > + ModuleAnalysisResultMapT; + + /// \brief Cache of computed module analysis results for this module. + ModuleAnalysisResultMapT ModuleAnalysisResults; +}; + +/// \brief A function analysis manager to coordinate and cache analyses run over +/// a module. +class FunctionAnalysisManager { +public: + FunctionAnalysisManager() {} + + /// \brief Get the result of an analysis pass for a function. + /// + /// If there is not a valid cached result in the manager already, this will + /// re-run the analysis to produce a valid result. + template + const typename PassT::Result &getResult(Function *F) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Function."); + assert(FunctionAnalysisPasses.count(PassT::ID()) && + "This analysis pass was not registered prior to being queried"); + + const detail::AnalysisResultConcept &ResultConcept = + getResultImpl(PassT::ID(), F); + typedef detail::AnalysisResultModel + ResultModelT; + return static_cast(ResultConcept).Result; + } + + /// \brief Register an analysis pass with the manager. + /// + /// This provides an initialized and set-up analysis pass to the + /// analysis + /// manager. Whomever is setting up analysis passes must use this to + /// populate + /// the manager with all of the analysis passes available. + template void registerPass(PassT Pass) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Function."); + assert(!FunctionAnalysisPasses.count(PassT::ID()) && + "Registered the same analysis pass twice!"); + FunctionAnalysisPasses[PassT::ID()] = + new detail::AnalysisPassModel(llvm_move(Pass)); + } + + /// \brief Invalidate a specific analysis pass for an IR module. + /// + /// Note that the analysis result can disregard invalidation. + template void invalidate(Function *F) { + LLVM_STATIC_ASSERT((is_same::value), + "The analysis pass must be over a Function."); + assert(FunctionAnalysisPasses.count(PassT::ID()) && + "This analysis pass was not registered prior to being invalidated"); + invalidateImpl(PassT::ID(), F); + } + /// \brief Invalidate analyses cached for an IR Function. /// /// Note that specific analysis results can disregard invalidation by @@ -216,134 +346,17 @@ public: void invalidateAll(Function *F); private: - /// \brief Abstract concept of an analysis result. - /// - /// This concept is parameterized over the IR unit that this result pertains - /// to. - template struct AnalysisResultConcept { - virtual ~AnalysisResultConcept() {} - virtual AnalysisResultConcept *clone() = 0; - - /// \brief Method to try and mark a result as invalid. - /// - /// When the outer \c AnalysisManager detects a change in some underlying - /// unit of the IR, it will call this method on all of the results cached. - /// - /// \returns true if the result should indeed be invalidated (the default). - virtual bool invalidate(IRUnitT *IR) = 0; - }; - - /// \brief Wrapper to model the analysis result concept. - /// - /// Can wrap any type which implements a suitable invalidate member and model - /// the AnalysisResultConcept for the AnalysisManager. - template - struct AnalysisResultModel : AnalysisResultConcept { - AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {} - virtual AnalysisResultModel *clone() { - return new AnalysisResultModel(Result); - } - - /// \brief The model delegates to the \c ResultT method. - virtual bool invalidate(IRUnitT *IR) { return Result.invalidate(IR); } - - ResultT Result; - }; - - /// \brief Abstract concept of an analysis pass. - /// - /// This concept is parameterized over the IR unit that it can run over and - /// produce an analysis result. - template struct AnalysisPassConcept { - virtual ~AnalysisPassConcept() {} - virtual AnalysisPassConcept *clone() = 0; - - /// \brief Method to run this analysis over a unit of IR. - /// \returns The analysis result object to be queried by users, the caller - /// takes ownership. - virtual AnalysisResultConcept *run(IRUnitT *IR) = 0; - }; - - /// \brief Wrapper to model the analysis pass concept. - /// - /// Can wrap any type which implements a suitable \c run method. The method - /// must accept the IRUnitT as an argument and produce an object which can be - /// wrapped in a \c AnalysisResultModel. - template - struct AnalysisPassModel : AnalysisPassConcept { - AnalysisPassModel(PassT Pass) : Pass(llvm_move(Pass)) {} - virtual AnalysisPassModel *clone() { return new AnalysisPassModel(Pass); } - - // FIXME: Replace PassT::IRUnitT with type traits when we use C++11. - typedef typename PassT::IRUnitT IRUnitT; - - // FIXME: Replace PassT::Result with type traits when we use C++11. - typedef AnalysisResultModel ResultModelT; - - /// \brief The model delegates to the \c PassT::run method. - /// - /// The return is wrapped in an \c AnalysisResultModel. - virtual ResultModelT *run(IRUnitT *IR) { - return new ResultModelT(Pass.run(IR)); - } - - PassT Pass; - }; - - - /// \brief Get a module pass result, running the pass if necessary. - const AnalysisResultConcept &getResultImpl(void *PassID, Module *M); - /// \brief Get a function pass result, running the pass if necessary. - const AnalysisResultConcept &getResultImpl(void *PassID, - Function *F); - - /// \brief Invalidate a module pass result. - void invalidateImpl(void *PassID, Module *M); + const detail::AnalysisResultConcept &getResultImpl(void *PassID, + Function *F); /// \brief Invalidate a function pass result. void invalidateImpl(void *PassID, Function *F); - - /// \brief Module pass specific implementation of registration. - template - typename enable_if >::type - registerAnalysisPassImpl(PassT Pass) { - assert(!ModuleAnalysisPasses.count(PassT::ID()) && - "Registered the same analysis pass twice!"); - ModuleAnalysisPasses[PassT::ID()] = - new AnalysisPassModel(llvm_move(Pass)); - } - - /// \brief Function pass specific implementation of registration. - template - typename enable_if >::type - registerAnalysisPassImpl(PassT Pass) { - assert(!FunctionAnalysisPasses.count(PassT::ID()) && - "Registered the same analysis pass twice!"); - FunctionAnalysisPasses[PassT::ID()] = - new AnalysisPassModel(llvm_move(Pass)); - } - - - /// \brief Map type from module analysis pass ID to pass concept pointer. - typedef DenseMap > > - ModuleAnalysisPassMapT; - - /// \brief Collection of module analysis passes, indexed by ID. - ModuleAnalysisPassMapT ModuleAnalysisPasses; - - /// \brief Map type from module analysis pass ID to pass result concept pointer. - typedef DenseMap > > - ModuleAnalysisResultMapT; - - /// \brief Cache of computed module analysis results for this module. - ModuleAnalysisResultMapT ModuleAnalysisResults; - - /// \brief Map type from function analysis pass ID to pass concept pointer. - typedef DenseMap > > - FunctionAnalysisPassMapT; + typedef DenseMap > > + FunctionAnalysisPassMapT; /// \brief Collection of function analysis passes, indexed by ID. FunctionAnalysisPassMapT FunctionAnalysisPasses; @@ -353,12 +366,13 @@ private: /// Requires iterators to be valid across appending new entries and arbitrary /// erases. Provides both the pass ID and concept pointer such that it is /// half of a bijection and provides storage for the actual result concept. - typedef std::list< - std::pair > > > - FunctionAnalysisResultListT; + typedef std::list > > > + FunctionAnalysisResultListT; /// \brief Map type from function pointer to our custom list type. - typedef DenseMap FunctionAnalysisResultListMapT; + typedef DenseMap + FunctionAnalysisResultListMapT; /// \brief Map from function to a list of function analysis results. /// @@ -370,14 +384,11 @@ private: /// iterator into a particular result list. typedef DenseMap, FunctionAnalysisResultListT::iterator> - FunctionAnalysisResultMapT; + FunctionAnalysisResultMapT; /// \brief Map from an analysis ID and function to a particular cached /// analysis result. FunctionAnalysisResultMapT FunctionAnalysisResults; - - /// \brief Module handle for the \c AnalysisManager. - Module *M; }; } diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index 966af7debc7..b53a2b9671d 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -12,10 +12,45 @@ using namespace llvm; -void ModulePassManager::run() { +void ModulePassManager::run(Module *M) { for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) if (Passes[Idx]->run(M)) - if (AM) AM->invalidateAll(M); + if (AM) + AM->invalidateAll(M); +} + +void ModuleAnalysisManager::invalidateAll(Module *M) { + // FIXME: This is a total hack based on the fact that erasure doesn't + // invalidate iteration for DenseMap. + for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), + E = ModuleAnalysisResults.end(); + I != E; ++I) + if (I->second->invalidate(M)) + ModuleAnalysisResults.erase(I); +} + +const detail::AnalysisResultConcept & +ModuleAnalysisManager::getResultImpl(void *PassID, Module *M) { + ModuleAnalysisResultMapT::iterator RI; + bool Inserted; + llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair( + PassID, polymorphic_ptr >())); + + if (Inserted) { + // We don't have a cached result for this result. Look up the pass and run + // it to produce a result, which we then add to the cache. + ModuleAnalysisPassMapT::const_iterator PI = + ModuleAnalysisPasses.find(PassID); + assert(PI != ModuleAnalysisPasses.end() && + "Analysis passes must be registered prior to being queried!"); + RI->second = PI->second->run(M); + } + + return *RI->second; +} + +void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) { + ModuleAnalysisResults.erase(PassID); } bool FunctionPassManager::run(Module *M) { @@ -24,24 +59,14 @@ bool FunctionPassManager::run(Module *M) { for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx) if (Passes[Idx]->run(I)) { Changed = true; - if (AM) AM->invalidateAll(I); + if (AM) + AM->invalidateAll(I); } return Changed; } -void AnalysisManager::invalidateAll(Function *F) { - assert(F->getParent() == M && "Invalidating a function from another module!"); - - // First invalidate any module results we still have laying about. - // FIXME: This is a total hack based on the fact that erasure doesn't - // invalidate iteration for DenseMap. - for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), - E = ModuleAnalysisResults.end(); - I != E; ++I) - if (I->second->invalidate(M)) - ModuleAnalysisResults.erase(I); - - // Now clear all the invalidated results associated specifically with this +void FunctionAnalysisManager::invalidateAll(Function *F) { + // Clear all the invalidated results associated specifically with this // function. SmallVector InvalidatedPassIDs; FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[F]; @@ -59,66 +84,8 @@ void AnalysisManager::invalidateAll(Function *F) { std::make_pair(InvalidatedPassIDs.pop_back_val(), F)); } -void AnalysisManager::invalidateAll(Module *M) { - // First invalidate any module results we still have laying about. - // FIXME: This is a total hack based on the fact that erasure doesn't - // invalidate iteration for DenseMap. - for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(), - E = ModuleAnalysisResults.end(); - I != E; ++I) - if (I->second->invalidate(M)) - ModuleAnalysisResults.erase(I); - - // Now walk all of the functions for which there are cached results, and - // attempt to invalidate each of those as the entire module may have changed. - // FIXME: How do we handle functions which have been deleted or RAUWed? - SmallVector InvalidatedPassIDs; - for (FunctionAnalysisResultListMapT::iterator - FI = FunctionAnalysisResultLists.begin(), - FE = FunctionAnalysisResultLists.end(); - FI != FE; ++FI) { - Function *F = FI->first; - FunctionAnalysisResultListT &ResultsList = FI->second; - for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(), - E = ResultsList.end(); - I != E;) - if (I->second->invalidate(F)) { - InvalidatedPassIDs.push_back(I->first); - I = ResultsList.erase(I); - } else { - ++I; - } - while (!InvalidatedPassIDs.empty()) - FunctionAnalysisResults.erase( - std::make_pair(InvalidatedPassIDs.pop_back_val(), F)); - } -} - -const AnalysisManager::AnalysisResultConcept & -AnalysisManager::getResultImpl(void *PassID, Module *M) { - assert(M == this->M && "Wrong module used when querying the AnalysisManager"); - ModuleAnalysisResultMapT::iterator RI; - bool Inserted; - llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair( - PassID, polymorphic_ptr >())); - - if (Inserted) { - // We don't have a cached result for this result. Look up the pass and run - // it to produce a result, which we then add to the cache. - ModuleAnalysisPassMapT::const_iterator PI = - ModuleAnalysisPasses.find(PassID); - assert(PI != ModuleAnalysisPasses.end() && - "Analysis passes must be registered prior to being queried!"); - RI->second = PI->second->run(M); - } - - return *RI->second; -} - -const AnalysisManager::AnalysisResultConcept & -AnalysisManager::getResultImpl(void *PassID, Function *F) { - assert(F->getParent() == M && "Analyzing a function from another module!"); - +const detail::AnalysisResultConcept & +FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) { FunctionAnalysisResultMapT::iterator RI; bool Inserted; llvm::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair( @@ -139,15 +106,7 @@ AnalysisManager::getResultImpl(void *PassID, Function *F) { return *RI->second->second; } -void AnalysisManager::invalidateImpl(void *PassID, Module *M) { - assert(M == this->M && "Invalidating a pass over a different module!"); - ModuleAnalysisResults.erase(PassID); -} - -void AnalysisManager::invalidateImpl(void *PassID, Function *F) { - assert(F->getParent() == M && - "Invalidating a pass over a function from another module!"); - +void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) { FunctionAnalysisResultMapT::iterator RI = FunctionAnalysisResults.find(std::make_pair(PassID, F)); if (RI == FunctionAnalysisResults.end()) diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 7b60e3899a0..cf7b6e47488 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -61,9 +61,9 @@ struct TestModulePass { }; struct TestFunctionPass { - TestFunctionPass(AnalysisManager &AM, int &RunCount, int &AnalyzedInstrCount) - : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) { - } + TestFunctionPass(FunctionAnalysisManager &AM, int &RunCount, + int &AnalyzedInstrCount) + : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} bool run(Function *F) { ++RunCount; @@ -74,7 +74,7 @@ struct TestFunctionPass { return true; } - AnalysisManager &AM; + FunctionAnalysisManager &AM; int &RunCount; int &AnalyzedInstrCount; }; @@ -106,10 +106,10 @@ public: }; TEST_F(PassManagerTest, Basic) { - AnalysisManager AM(M.get()); - AM.registerAnalysisPass(TestAnalysisPass()); + FunctionAnalysisManager AM; + AM.registerPass(TestAnalysisPass()); - ModulePassManager MPM(M.get(), &AM); + ModulePassManager MPM; FunctionPassManager FPM(&AM); // Count the runs over a module. @@ -122,10 +122,9 @@ TEST_F(PassManagerTest, Basic) { FPM.addPass(TestFunctionPass(AM, FunctionPassRunCount, AnalyzedInstrCount)); MPM.addPass(FPM); - MPM.run(); + MPM.run(M.get()); EXPECT_EQ(1, ModulePassRunCount); EXPECT_EQ(3, FunctionPassRunCount); EXPECT_EQ(5, AnalyzedInstrCount); } - }