forked from OSchip/llvm-project
[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:
parent
36129a953d
commit
de9afd845b
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue