std::vector<polymorphic_ptr<FunctionPassConcept> > Passes;
};
-/// \brief Trivial adaptor that maps from a module to its functions.
-///
-/// Designed to allow composition of a FunctionPass(Manager) and a
-/// ModulePassManager.
-template <typename FunctionPassT>
-class ModuleToFunctionPassAdaptor {
-public:
- explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass)
- : Pass(llvm_move(Pass)) {}
-
- /// \brief Runs the function pass across every function in the module.
- PreservedAnalyses run(Module *M) {
- PreservedAnalyses PA = PreservedAnalyses::all();
- for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
- PreservedAnalyses PassPA = Pass.run(I);
- PA.intersect(llvm_move(PassPA));
- }
- return PA;
- }
-
-private:
- FunctionPassT Pass;
-};
-
-/// \brief A function to deduce a function pass type and wrap it in the
-/// templated adaptor.
-template <typename FunctionPassT>
-ModuleToFunctionPassAdaptor<FunctionPassT>
-createModuleToFunctionPassAdaptor(FunctionPassT Pass) {
- return ModuleToFunctionPassAdaptor<FunctionPassT>(llvm_move(Pass));
-}
-
/// \brief A module analysis pass manager with lazy running and caching of
/// results.
class ModuleAnalysisManager {
/// PreservedAnalyses set.
void invalidate(Function *F, const PreservedAnalyses &PA);
+ /// \brief Returns true if the analysis manager has an empty results cache.
+ bool empty() const;
+
+ /// \brief Clear the function analysis result cache.
+ ///
+ /// This routine allows cleaning up when the set of functions itself has
+ /// potentially changed, and thus we can't even look up a a result and
+ /// invalidate it directly. Notably, this does *not* call invalidate
+ /// functions as there is nothing to be done for them.
+ void clear();
+
private:
/// \brief Get a function pass result, running the pass if necessary.
const detail::AnalysisResultConcept<Function> &getResultImpl(void *PassID,
FunctionAnalysisResultMapT FunctionAnalysisResults;
};
+/// \brief A module analysis which acts as a proxy for a function analysis
+/// manager.
+///
+/// This primarily proxies invalidation information from the module analysis
+/// manager and module pass manager to a function analysis manager. You should
+/// never use a function analysis manager from within (transitively) a module
+/// pass manager unless your parent module pass has received a proxy result
+/// object for it.
+///
+/// FIXME: It might be really nice to "enforce" this (softly) by making this
+/// proxy the API path to access a function analysis manager within a module
+/// pass.
+class FunctionAnalysisModuleProxy {
+public:
+ typedef Module IRUnitT;
+ class Result;
+
+ static void *ID() { return (void *)&PassID; }
+
+ FunctionAnalysisModuleProxy(FunctionAnalysisManager &FAM) : FAM(FAM) {}
+
+ /// \brief Run the analysis pass and create our proxy result object.
+ ///
+ /// This doesn't do any interesting work, it is primarily used to insert our
+ /// proxy result object into the module analysis cache so that we can proxy
+ /// invalidation to the function analysis manager.
+ ///
+ /// In debug builds, it will also assert that the analysis manager is empty
+ /// as no queries should arrive at the function analysis manager prior to
+ /// this analysis being requested.
+ Result run(Module *M);
+
+private:
+ static char PassID;
+
+ FunctionAnalysisManager &FAM;
+};
+
+/// \brief The result proxy object for the \c FunctionAnalysisModuleProxy.
+///
+/// See its documentation for more information.
+class FunctionAnalysisModuleProxy::Result {
+public:
+ Result(FunctionAnalysisManager &FAM) : FAM(FAM) {}
+ ~Result();
+
+ /// \brief Handler for invalidation of the module.
+ bool invalidate(Module *M);
+
+private:
+ FunctionAnalysisManager &FAM;
+};
+
+/// \brief Trivial adaptor that maps from a module to its functions.
+///
+/// Designed to allow composition of a FunctionPass(Manager) and a
+/// ModulePassManager. Note that if this pass is constructed with a pointer to
+/// a \c ModuleAnalysisManager it will run the \c FunctionAnalysisModuleProxy
+/// analysis prior to running the function pass over the module to enable a \c
+/// FunctionAnalysisManager to be used within this run safely.
+template <typename FunctionPassT>
+class ModuleToFunctionPassAdaptor {
+public:
+ explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass,
+ ModuleAnalysisManager *MAM = 0)
+ : Pass(llvm_move(Pass)), MAM(MAM) {}
+
+ /// \brief Runs the function pass across every function in the module.
+ PreservedAnalyses run(Module *M) {
+ if (MAM)
+ // Pull in the analysis proxy so that the function analysis manager is
+ // appropriately set up.
+ (void)MAM->getResult<FunctionAnalysisModuleProxy>(M);
+
+ PreservedAnalyses PA = PreservedAnalyses::all();
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
+ PreservedAnalyses PassPA = Pass.run(I);
+ PA.intersect(llvm_move(PassPA));
+ }
+ return PA;
+ }
+
+private:
+ FunctionPassT Pass;
+ ModuleAnalysisManager *MAM;
+};
+
+/// \brief A function to deduce a function pass type and wrap it in the
+/// templated adaptor.
+///
+/// \param MAM is an optional \c ModuleAnalysisManager which (if provided) will
+/// be queried for a \c FunctionAnalysisModuleProxy to enable the function
+/// pass(es) to safely interact with a \c FunctionAnalysisManager.
+template <typename FunctionPassT>
+ModuleToFunctionPassAdaptor<FunctionPassT>
+createModuleToFunctionPassAdaptor(FunctionPassT Pass,
+ ModuleAnalysisManager *MAM = 0) {
+ return ModuleToFunctionPassAdaptor<FunctionPassT>(llvm_move(Pass), MAM);
+}
+
}
std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
}
+bool FunctionAnalysisManager::empty() const {
+ assert(FunctionAnalysisResults.empty() ==
+ FunctionAnalysisResultLists.empty() &&
+ "The storage and index of analysis results disagree on how many there "
+ "are!");
+ return FunctionAnalysisResults.empty();
+}
+
+void FunctionAnalysisManager::clear() {
+ FunctionAnalysisResults.clear();
+ FunctionAnalysisResultLists.clear();
+}
+
const detail::AnalysisResultConcept<Function> &
FunctionAnalysisManager::getResultImpl(void *PassID, Function *F) {
FunctionAnalysisResultMapT::iterator RI;
FunctionAnalysisResultLists[F].erase(RI->second);
}
+
+char FunctionAnalysisModuleProxy::PassID;
+
+FunctionAnalysisModuleProxy::Result
+FunctionAnalysisModuleProxy::run(Module *M) {
+ assert(FAM.empty() && "Function analyses ran prior to the module proxy!");
+ return Result(FAM);
+}
+
+FunctionAnalysisModuleProxy::Result::~Result() {
+ // Clear out the analysis manager if we're being destroyed -- it means we
+ // didn't even see an invalidate call when we got invalidated.
+ FAM.clear();
+}
+
+bool FunctionAnalysisModuleProxy::Result::invalidate(Module *M) {
+ // FIXME: We should pull the preserved analysis set into the invalidation
+ // handler so that we can detect when there is no need to clear the entire
+ // function analysis manager.
+ FAM.clear();
+
+ // Return false to indicate that this result is still a valid proxy.
+ return false;
+}
/// \brief Returns an opaque, unique ID for this pass type.
static void *ID() { return (void *)&PassID; }
+ TestAnalysisPass(int &Runs) : Runs(Runs) {}
+
/// \brief Run the analysis pass over the function and return a result.
Result run(Function *F) {
+ ++Runs;
int Count = 0;
for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE; ++BBI)
for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE;
private:
/// \brief Private static data to provide unique ID.
static char PassID;
+
+ int &Runs;
};
char TestAnalysisPass::PassID;
const TestAnalysisPass::Result &AR = AM.getResult<TestAnalysisPass>(F);
AnalyzedInstrCount += AR.InstructionCount;
- return PreservedAnalyses::none();
+ return PreservedAnalyses::all();
}
FunctionAnalysisManager &AM;
};
TEST_F(PassManagerTest, Basic) {
- FunctionAnalysisManager AM;
- AM.registerPass(TestAnalysisPass());
+ FunctionAnalysisManager FAM;
+ int AnalysisRuns = 0;
+ FAM.registerPass(TestAnalysisPass(AnalysisRuns));
+
+ ModuleAnalysisManager MAM;
+ MAM.registerPass(FunctionAnalysisModuleProxy(FAM));
+
+ ModulePassManager MPM(&MAM);
- ModulePassManager MPM;
- FunctionPassManager FPM(&AM);
+ // Count the runs over a Function.
+ FunctionPassManager FPM1(&FAM);
+ int FunctionPassRunCount1 = 0;
+ int AnalyzedInstrCount1 = 0;
+ FPM1.addPass(TestFunctionPass(FAM, FunctionPassRunCount1, AnalyzedInstrCount1));
+ MPM.addPass(createModuleToFunctionPassAdaptor(FPM1, &MAM));
// Count the runs over a module.
int ModulePassRunCount = 0;
MPM.addPass(TestModulePass(ModulePassRunCount));
- // Count the runs over a Function.
- int FunctionPassRunCount = 0;
- int AnalyzedInstrCount = 0;
- FPM.addPass(TestFunctionPass(AM, FunctionPassRunCount, AnalyzedInstrCount));
- MPM.addPass(createModuleToFunctionPassAdaptor(FPM));
+ // Count the runs over a Function in a separate manager.
+ FunctionPassManager FPM2(&FAM);
+ int FunctionPassRunCount2 = 0;
+ int AnalyzedInstrCount2 = 0;
+ FPM2.addPass(TestFunctionPass(FAM, FunctionPassRunCount2, AnalyzedInstrCount2));
+ MPM.addPass(createModuleToFunctionPassAdaptor(FPM2, &MAM));
MPM.run(M.get());
+
+ // Validate module pass counters.
EXPECT_EQ(1, ModulePassRunCount);
- EXPECT_EQ(3, FunctionPassRunCount);
- EXPECT_EQ(5, AnalyzedInstrCount);
+
+ // Validate both function pass counter sets.
+ EXPECT_EQ(3, FunctionPassRunCount1);
+ EXPECT_EQ(5, AnalyzedInstrCount1);
+ EXPECT_EQ(3, FunctionPassRunCount2);
+ EXPECT_EQ(5, AnalyzedInstrCount2);
+
+ // Validate the analysis counters.
+ EXPECT_EQ(6, AnalysisRuns);
}
}