From b88831b204bcc1645097dafee64efa2b6a91df2d Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sat, 23 Nov 2013 00:38:42 +0000 Subject: [PATCH] [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 --- include/llvm/IR/PassManager.h | 48 ++++++++++++++++++++++++++++++++ lib/IR/PassManager.cpp | 13 +++++++++ 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 4d0c09234b7..d6e97419def 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -460,6 +460,26 @@ public: return static_cast(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 + 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 *ResultConcept = + getCachedResultImpl(PassT::ID(), M); + if (!ResultConcept) + return 0; + + 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 @@ -495,6 +515,10 @@ private: const detail::AnalysisResultConcept &getResultImpl(void *PassID, Module *M); + /// \brief Get a cached module pass result or return null. + const detail::AnalysisResultConcept * + 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(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 + 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 *ResultConcept = + getCachedResultImpl(PassT::ID(), F); + if (!ResultConcept) + return 0; + + 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 @@ -583,6 +627,10 @@ private: const detail::AnalysisResultConcept &getResultImpl(void *PassID, Function *F); + /// \brief Get a cached function pass result or return null. + const detail::AnalysisResultConcept * + 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 76210a31ed7..bbfc304e6dd 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 * +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 * +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 801d8d86bfc..cbfc3d25756 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(M); + (void)R; // FIXME: We should test this better by querying an actual analysis + // pass in interesting ways. + PA.preserve(); 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(F); - AnalyzedInstrCount += AR.InstructionCount; + if (OnlyUseCachedResults) { + // Hack to force the use of the cached interface. + if (const TestAnalysisPass::Result *AR = + AM->getCachedResult(F)) + AnalyzedInstrCount += AR->InstructionCount; + } else { + // Typical path just runs the analysis as needed. + const TestAnalysisPass::Result &AR = AM->getResult(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 -- 2.34.1