diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2013-11-23 00:38:42 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2013-11-23 00:38:42 +0000 |
commit | b88831b204bcc1645097dafee64efa2b6a91df2d (patch) | |
tree | 2323e483a8524cb8b208e0e043b851910b4f82e2 | |
parent | 43d67d01e2e32c51ec974e4f5c67343c6bf524a1 (diff) | |
download | llvm-b88831b204bcc1645097dafee64efa2b6a91df2d.tar.gz llvm-b88831b204bcc1645097dafee64efa2b6a91df2d.tar.bz2 llvm-b88831b204bcc1645097dafee64efa2b6a91df2d.tar.xz |
[PM] Add support to the analysis managers to query explicitly for cached
results.
This is the last piece of infrastructure needed to effectively support
querying *up* the analysis layers. The next step will be to introduce
a proxy which provides access to those layers with appropriate use of
const to direct queries to the safe interface.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195525 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/IR/PassManager.h | 48 | ||||
-rw-r--r-- | lib/IR/PassManager.cpp | 13 | ||||
-rw-r--r-- | unittests/IR/PassManagerTest.cpp | 39 |
3 files changed, 95 insertions, 5 deletions
diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 4d0c09234b..d6e97419de 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -460,6 +460,26 @@ public: return static_cast<const ResultModelT &>(ResultConcept).Result; } + /// \brief Get the cached result of an analysis pass for this module. + /// + /// This method never runs the analysis. + /// + /// \returns null if there is no cached result. + template <typename PassT> + const typename PassT::Result *getCachedResult(Module *M) const { + assert(ModuleAnalysisPasses.count(PassT::ID()) && + "This analysis pass was not registered prior to being queried"); + + const detail::AnalysisResultConcept<Module *> *ResultConcept = + getCachedResultImpl(PassT::ID(), M); + if (!ResultConcept) + return 0; + + typedef detail::AnalysisResultModel<Module *, PassT, typename PassT::Result> + ResultModelT; + return &static_cast<const ResultModelT *>(ResultConcept)->Result; + } + /// \brief Register an analysis pass with the manager. /// /// This provides an initialized and set-up analysis pass to the @@ -495,6 +515,10 @@ private: const detail::AnalysisResultConcept<Module *> &getResultImpl(void *PassID, Module *M); + /// \brief Get a cached module pass result or return null. + const detail::AnalysisResultConcept<Module *> * + getCachedResultImpl(void *PassID, Module *M) const; + /// \brief Invalidate a module pass result. void invalidateImpl(void *PassID, Module *M); @@ -537,6 +561,26 @@ public: return static_cast<const ResultModelT &>(ResultConcept).Result; } + /// \brief Get the cached result of an analysis pass for a function if + /// available. + /// + /// Does not run the analysis ever. + /// \returns null if a cached result is not available. + template <typename PassT> + const typename PassT::Result *getCachedResult(Function *F) { + assert(FunctionAnalysisPasses.count(PassT::ID()) && + "This analysis pass was not registered prior to being queried"); + + const detail::AnalysisResultConcept<Function *> *ResultConcept = + getCachedResultImpl(PassT::ID(), F); + if (!ResultConcept) + return 0; + + typedef detail::AnalysisResultModel<Function *, PassT, + typename PassT::Result> ResultModelT; + return &static_cast<const ResultModelT *>(ResultConcept)->Result; + } + /// \brief Register an analysis pass with the manager. /// /// This provides an initialized and set-up analysis pass to the @@ -583,6 +627,10 @@ private: const detail::AnalysisResultConcept<Function *> &getResultImpl(void *PassID, Function *F); + /// \brief Get a cached function pass result or return null. + const detail::AnalysisResultConcept<Function *> * + getCachedResultImpl(void *PassID, Function *F) const; + /// \brief Invalidate a function pass result. void invalidateImpl(void *PassID, Function *F); diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index 76210a31ed..bbfc304e6d 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -53,6 +53,12 @@ ModuleAnalysisManager::getResultImpl(void *PassID, Module *M) { return *RI->second; } +const detail::AnalysisResultConcept<Module *> * +ModuleAnalysisManager::getCachedResultImpl(void *PassID, Module *M) const { + ModuleAnalysisResultMapT::const_iterator RI = ModuleAnalysisResults.find(PassID); + return RI == ModuleAnalysisResults.end() ? 0 : &*RI->second; +} + void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) { ModuleAnalysisResults.erase(PassID); } @@ -122,6 +128,13 @@ FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) { return *RI->second->second; } +const detail::AnalysisResultConcept<Function *> * +FunctionAnalysisManager::getCachedResultImpl(void *PassID, Function *F) const { + FunctionAnalysisResultMapT::const_iterator RI = + FunctionAnalysisResults.find(std::make_pair(PassID, F)); + return RI == FunctionAnalysisResults.end() ? 0 : &*RI->second->second; +} + void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) { FunctionAnalysisResultMapT::iterator RI = FunctionAnalysisResults.find(std::make_pair(PassID, F)); diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 801d8d86bf..cbfc3d2575 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -69,28 +69,46 @@ struct TestPreservingModulePass { }; struct TestMinPreservingModulePass { - PreservedAnalyses run(Module *M) { + PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) { PreservedAnalyses PA; + + // Check that we can get cached result objects for modules. + const FunctionAnalysisManagerModuleProxy::Result *R = + AM->getCachedResult<FunctionAnalysisManagerModuleProxy>(M); + (void)R; // FIXME: We should test this better by querying an actual analysis + // pass in interesting ways. + PA.preserve<FunctionAnalysisManagerModuleProxy>(); return PA; } }; struct TestFunctionPass { - TestFunctionPass(int &RunCount, int &AnalyzedInstrCount) - : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} + TestFunctionPass(int &RunCount, int &AnalyzedInstrCount, + bool OnlyUseCachedResults = false) + : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), + OnlyUseCachedResults(OnlyUseCachedResults) {} PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) { ++RunCount; - const TestAnalysisPass::Result &AR = AM->getResult<TestAnalysisPass>(F); - AnalyzedInstrCount += AR.InstructionCount; + if (OnlyUseCachedResults) { + // Hack to force the use of the cached interface. + if (const TestAnalysisPass::Result *AR = + AM->getCachedResult<TestAnalysisPass>(F)) + AnalyzedInstrCount += AR->InstructionCount; + } else { + // Typical path just runs the analysis as needed. + const TestAnalysisPass::Result &AR = AM->getResult<TestAnalysisPass>(F); + AnalyzedInstrCount += AR.InstructionCount; + } return PreservedAnalyses::all(); } int &RunCount; int &AnalyzedInstrCount; + bool OnlyUseCachedResults; }; // A test function pass that invalidates all function analyses for a function @@ -178,6 +196,15 @@ TEST_F(PassManagerTest, Basic) { FPM4.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM4)); + // A fifth function pass manager but which uses only cached results. + FunctionPassManager FPM5; + int FunctionPassRunCount5 = 0; + int AnalyzedInstrCount5 = 0; + FPM5.addPass(TestInvalidationFunctionPass("f")); + FPM5.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, + /*OnlyUseCachedResults=*/true)); + MPM.addPass(createModuleToFunctionPassAdaptor(FPM5)); + MPM.run(M.get(), &MAM); // Validate module pass counters. @@ -192,6 +219,8 @@ TEST_F(PassManagerTest, Basic) { EXPECT_EQ(5, AnalyzedInstrCount3); EXPECT_EQ(3, FunctionPassRunCount4); EXPECT_EQ(5, AnalyzedInstrCount4); + EXPECT_EQ(3, FunctionPassRunCount5); + EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached. // Validate the analysis counters: // first run over 3 functions, then module pass invalidates |