diff options
-rw-r--r-- | include/llvm/IR/PassManager.h | 44 | ||||
-rw-r--r-- | lib/IR/PassManager.cpp | 2 | ||||
-rw-r--r-- | unittests/IR/PassManagerTest.cpp | 77 |
3 files changed, 111 insertions, 12 deletions
diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index d6e97419de..3c9414986e 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -733,6 +733,50 @@ private: FunctionAnalysisManager &FAM; }; +/// \brief A function analysis which acts as a proxy for a module analysis +/// manager. +/// +/// This primarily provides an accessor to a parent module analysis manager to +/// function passes. Only the const interface of the module analysis manager is +/// provided to indicate that once inside of a function analysis pass you +/// cannot request a module analysis to actually run. Instead, the user must +/// rely on the \c getCachedResult API. +/// +/// This proxy *doesn't* manage the invalidation in any way. That is handled by +/// the recursive return path of each layer of the pass manager and the +/// returned PreservedAnalysis set. +class ModuleAnalysisManagerFunctionProxy { +public: + /// \brief Result proxy object for \c ModuleAnalysisManagerFunctionProxy. + class Result { + public: + Result(const ModuleAnalysisManager &MAM) : MAM(MAM) {} + + const ModuleAnalysisManager &getManager() const { return MAM; } + + /// \brief Handle invalidation by ignoring it, this pass is immutable. + bool invalidate(Function *) { return false; } + + private: + const ModuleAnalysisManager &MAM; + }; + + static void *ID() { return (void *)&PassID; } + + ModuleAnalysisManagerFunctionProxy(const ModuleAnalysisManager &MAM) + : MAM(MAM) {} + + /// \brief Run the analysis pass and create our proxy result object. + /// Nothing to see here, it just forwards the \c MAM reference into the + /// result. + Result run(Function *) { return Result(MAM); } + +private: + static char PassID; + + const ModuleAnalysisManager &MAM; +}; + /// \brief Trivial adaptor that maps from a module to its functions. /// /// Designed to allow composition of a FunctionPass(Manager) and diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index bbfc304e6d..05aea0743a 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -170,3 +170,5 @@ bool FunctionAnalysisManagerModuleProxy::Result::invalidate( // Return false to indicate that this result is still a valid proxy. return false; } + +char ModuleAnalysisManagerFunctionProxy::PassID; diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index b3a9b7422a..a8e899141d 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -51,6 +51,33 @@ private: char TestFunctionAnalysis::PassID; +class TestModuleAnalysis { +public: + struct Result { + Result(int Count) : FunctionCount(Count) {} + int FunctionCount; + }; + + static void *ID() { return (void * )&PassID; } + + TestModuleAnalysis(int &Runs) : Runs(Runs) {} + + Result run(Module *M, ModuleAnalysisManager *AM) { + ++Runs; + int Count = 0; + for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) + ++Count; + return Result(Count); + } + +private: + static char PassID; + + int &Runs; +}; + +char TestModuleAnalysis::PassID; + struct TestModulePass { TestModulePass(int &RunCount) : RunCount(RunCount) {} @@ -72,11 +99,8 @@ struct TestMinPreservingModulePass { 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. + // Force running an analysis. + (void)AM->getResult<TestModuleAnalysis>(M); PA.preserve<FunctionAnalysisManagerModuleProxy>(); return PA; @@ -85,13 +109,21 @@ struct TestMinPreservingModulePass { struct TestFunctionPass { TestFunctionPass(int &RunCount, int &AnalyzedInstrCount, + int &AnalyzedFunctionCount, bool OnlyUseCachedResults = false) : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), + AnalyzedFunctionCount(AnalyzedFunctionCount), OnlyUseCachedResults(OnlyUseCachedResults) {} PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM) { ++RunCount; + const ModuleAnalysisManager &MAM = + AM->getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); + if (const TestModuleAnalysis::Result *TMA = + MAM.getCachedResult<TestModuleAnalysis>(F->getParent())) + AnalyzedFunctionCount += TMA->FunctionCount; + if (OnlyUseCachedResults) { // Hack to force the use of the cached interface. if (const TestFunctionAnalysis::Result *AR = @@ -108,6 +140,7 @@ struct TestFunctionPass { int &RunCount; int &AnalyzedInstrCount; + int &AnalyzedFunctionCount; bool OnlyUseCachedResults; }; @@ -152,11 +185,14 @@ public: TEST_F(PassManagerTest, Basic) { FunctionAnalysisManager FAM; - int AnalysisRuns = 0; - FAM.registerPass(TestFunctionAnalysis(AnalysisRuns)); + int FunctionAnalysisRuns = 0; + FAM.registerPass(TestFunctionAnalysis(FunctionAnalysisRuns)); ModuleAnalysisManager MAM; + int ModuleAnalysisRuns = 0; + MAM.registerPass(TestModuleAnalysis(ModuleAnalysisRuns)); MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); + FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); ModulePassManager MPM; @@ -164,7 +200,9 @@ TEST_F(PassManagerTest, Basic) { FunctionPassManager FPM1; int FunctionPassRunCount1 = 0; int AnalyzedInstrCount1 = 0; - FPM1.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1)); + int AnalyzedFunctionCount1 = 0; + FPM1.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1, + AnalyzedFunctionCount1)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM1)); // Count the runs over a module. @@ -175,7 +213,9 @@ TEST_F(PassManagerTest, Basic) { FunctionPassManager FPM2; int FunctionPassRunCount2 = 0; int AnalyzedInstrCount2 = 0; - FPM2.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2)); + int AnalyzedFunctionCount2 = 0; + FPM2.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2, + AnalyzedFunctionCount2)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM2)); // A third function pass manager but with only preserving intervening passes @@ -184,7 +224,9 @@ TEST_F(PassManagerTest, Basic) { FunctionPassManager FPM3; int FunctionPassRunCount3 = 0; int AnalyzedInstrCount3 = 0; - FPM3.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3)); + int AnalyzedFunctionCount3 = 0; + FPM3.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, + AnalyzedFunctionCount3)); FPM3.addPass(TestInvalidationFunctionPass("f")); MPM.addPass(createModuleToFunctionPassAdaptor(FPM3)); @@ -193,15 +235,19 @@ TEST_F(PassManagerTest, Basic) { FunctionPassManager FPM4; int FunctionPassRunCount4 = 0; int AnalyzedInstrCount4 = 0; - FPM4.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4)); + int AnalyzedFunctionCount4 = 0; + FPM4.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4, + AnalyzedFunctionCount4)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM4)); // A fifth function pass manager but which uses only cached results. FunctionPassManager FPM5; int FunctionPassRunCount5 = 0; int AnalyzedInstrCount5 = 0; + int AnalyzedFunctionCount5 = 0; FPM5.addPass(TestInvalidationFunctionPass("f")); FPM5.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, + AnalyzedFunctionCount5, /*OnlyUseCachedResults=*/true)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM5)); @@ -213,20 +259,27 @@ TEST_F(PassManagerTest, Basic) { // Validate all function pass counter sets are the same. EXPECT_EQ(3, FunctionPassRunCount1); EXPECT_EQ(5, AnalyzedInstrCount1); + EXPECT_EQ(0, AnalyzedFunctionCount1); EXPECT_EQ(3, FunctionPassRunCount2); EXPECT_EQ(5, AnalyzedInstrCount2); + EXPECT_EQ(0, AnalyzedFunctionCount2); EXPECT_EQ(3, FunctionPassRunCount3); EXPECT_EQ(5, AnalyzedInstrCount3); + EXPECT_EQ(0, AnalyzedFunctionCount3); EXPECT_EQ(3, FunctionPassRunCount4); EXPECT_EQ(5, AnalyzedInstrCount4); + EXPECT_EQ(0, AnalyzedFunctionCount4); EXPECT_EQ(3, FunctionPassRunCount5); EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached. + EXPECT_EQ(0, AnalyzedFunctionCount5); // Validate the analysis counters: // first run over 3 functions, then module pass invalidates // second run over 3 functions, nothing invalidates // third run over 0 functions, but 1 function invalidated // fourth run over 1 function - EXPECT_EQ(7, AnalysisRuns); + EXPECT_EQ(7, FunctionAnalysisRuns); + + EXPECT_EQ(1, ModuleAnalysisRuns); } } |