summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/IR/PassManager.h44
-rw-r--r--lib/IR/PassManager.cpp2
-rw-r--r--unittests/IR/PassManagerTest.cpp77
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);
}
}