[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.

llvm-svn: 195525
This commit is contained in:
Chandler Carruth 2013-11-23 00:38:42 +00:00
parent 36129a953d
commit de9afd845b
3 changed files with 95 additions and 5 deletions

View File

@ -460,6 +460,26 @@ public:
return static_cast<const ResultModelT &>(ResultConcept).Result; 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. /// \brief Register an analysis pass with the manager.
/// ///
/// This provides an initialized and set-up analysis pass to the /// This provides an initialized and set-up analysis pass to the
@ -495,6 +515,10 @@ private:
const detail::AnalysisResultConcept<Module *> &getResultImpl(void *PassID, const detail::AnalysisResultConcept<Module *> &getResultImpl(void *PassID,
Module *M); 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. /// \brief Invalidate a module pass result.
void invalidateImpl(void *PassID, Module *M); void invalidateImpl(void *PassID, Module *M);
@ -537,6 +561,26 @@ public:
return static_cast<const ResultModelT &>(ResultConcept).Result; 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. /// \brief Register an analysis pass with the manager.
/// ///
/// This provides an initialized and set-up analysis pass to the /// This provides an initialized and set-up analysis pass to the
@ -583,6 +627,10 @@ private:
const detail::AnalysisResultConcept<Function *> &getResultImpl(void *PassID, const detail::AnalysisResultConcept<Function *> &getResultImpl(void *PassID,
Function *F); 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. /// \brief Invalidate a function pass result.
void invalidateImpl(void *PassID, Function *F); void invalidateImpl(void *PassID, Function *F);

View File

@ -53,6 +53,12 @@ ModuleAnalysisManager::getResultImpl(void *PassID, Module *M) {
return *RI->second; 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) { void ModuleAnalysisManager::invalidateImpl(void *PassID, Module *M) {
ModuleAnalysisResults.erase(PassID); ModuleAnalysisResults.erase(PassID);
} }
@ -122,6 +128,13 @@ FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) {
return *RI->second->second; 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) { void FunctionAnalysisManager::invalidateImpl(void *PassID, Function *F) {
FunctionAnalysisResultMapT::iterator RI = FunctionAnalysisResultMapT::iterator RI =
FunctionAnalysisResults.find(std::make_pair(PassID, F)); FunctionAnalysisResults.find(std::make_pair(PassID, F));

View File

@ -69,28 +69,46 @@ struct TestPreservingModulePass {
}; };
struct TestMinPreservingModulePass { struct TestMinPreservingModulePass {
PreservedAnalyses run(Module *M) { PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) {
PreservedAnalyses PA; 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>(); PA.preserve<FunctionAnalysisManagerModuleProxy>();
return PA; return PA;
} }
}; };
struct TestFunctionPass { struct TestFunctionPass {
TestFunctionPass(int &RunCount, int &AnalyzedInstrCount) TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,
: RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {} bool OnlyUseCachedResults = false)
: RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount),
OnlyUseCachedResults(OnlyUseCachedResults) {}
PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) { PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) {
++RunCount; ++RunCount;
const TestAnalysisPass::Result &AR = AM->getResult<TestAnalysisPass>(F); if (OnlyUseCachedResults) {
AnalyzedInstrCount += AR.InstructionCount; // 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(); return PreservedAnalyses::all();
} }
int &RunCount; int &RunCount;
int &AnalyzedInstrCount; int &AnalyzedInstrCount;
bool OnlyUseCachedResults;
}; };
// A test function pass that invalidates all function analyses for a function // 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)); FPM4.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4));
MPM.addPass(createModuleToFunctionPassAdaptor(FPM4)); 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); MPM.run(M.get(), &MAM);
// Validate module pass counters. // Validate module pass counters.
@ -192,6 +219,8 @@ TEST_F(PassManagerTest, Basic) {
EXPECT_EQ(5, AnalyzedInstrCount3); EXPECT_EQ(5, AnalyzedInstrCount3);
EXPECT_EQ(3, FunctionPassRunCount4); EXPECT_EQ(3, FunctionPassRunCount4);
EXPECT_EQ(5, AnalyzedInstrCount4); EXPECT_EQ(5, AnalyzedInstrCount4);
EXPECT_EQ(3, FunctionPassRunCount5);
EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
// Validate the analysis counters: // Validate the analysis counters:
// first run over 3 functions, then module pass invalidates // first run over 3 functions, then module pass invalidates