From 4d32e85359363d2a6b3898a4d33322155b74eb67 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 22 Nov 2013 23:38:07 +0000 Subject: [PM] Switch the downward invalidation to be incremental where only the one function's analyses are invalidated at a time. Also switch the preservation of the proxy to *fully* preserve the lower (function) analyses. Combined, this gets both upward and downward analysis invalidation to a point I'm happy with: - A function pass invalidates its function analyses, and its parent's module analyses. - A module pass invalidates all of its functions' analyses including the set of which functions are in the module. - A function pass can preserve a module analysis pass. - If all function passes preserve a module analysis pass, that preservation persists. If any doesn't the module analysis is invalidated. - A module pass can opt into managing *all* function analysis invalidation itself or *none*. - The conservative default is none, and the proxy takes the maximally conservative approach that works even if the set of functions has changed. - If a module pass opts into managing function analysis invalidation it has to propagate the invalidation itself, the proxy just does nothing. The only thing really missing is a way to query for a cached analysis or nothing at all. With this, function passes can more safely request a cached module analysis pass without fear of it accidentally running part way through. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195519 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/PassManager.h | 14 +++++++++++++- lib/IR/PassManager.cpp | 16 +++++----------- unittests/IR/PassManagerTest.cpp | 27 +++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/include/llvm/IR/PassManager.h b/include/llvm/IR/PassManager.h index 6604c1851c..4d0c09234b 100644 --- a/include/llvm/IR/PassManager.h +++ b/include/llvm/IR/PassManager.h @@ -709,10 +709,22 @@ public: PreservedAnalyses PA = PreservedAnalyses::all(); for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { PreservedAnalyses PassPA = Pass.run(I, FAM); + + // We know that the function pass couldn't have invalidated any other + // function's analyses (that's the contract of a function pass), so + // directly handle the function analysis manager's invalidation here. + if (FAM) + FAM->invalidate(I, PassPA); + + // Then intersect the preserved set so that invalidation of module + // analyses will eventually occur when the module pass completes. PA.intersect(llvm_move(PassPA)); } - // By definition we preserve the proxy. + // By definition we preserve the proxy. This precludes *any* invalidation + // of function analyses by the proxy, but that's OK because we've taken + // care to invalidate analyses in the function analysis manager + // incrementally above. PA.preserve(); return PA; } diff --git a/lib/IR/PassManager.cpp b/lib/IR/PassManager.cpp index fe16adcaeb..76210a31ed 100644 --- a/lib/IR/PassManager.cpp +++ b/lib/IR/PassManager.cpp @@ -147,18 +147,12 @@ FunctionAnalysisManagerModuleProxy::Result::~Result() { bool FunctionAnalysisManagerModuleProxy::Result::invalidate( Module *M, const PreservedAnalyses &PA) { - // If this proxy isn't marked as preserved, then it is has an invalid set of - // Function objects in the cache making it impossible to incrementally - // preserve them. Just clear the entire manager. - if (!PA.preserved(ID())) { + // If this proxy isn't marked as preserved, then we can't even invalidate + // individual function analyses, there may be an invalid set of Function + // objects in the cache making it impossible to incrementally preserve them. + // Just clear the entire manager. + if (!PA.preserved(ID())) FAM.clear(); - return false; - } - - // The set of functions was preserved some how, so just directly invalidate - // any analysis results not preserved. - for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) - FAM.invalidate(I, PA); // Return false to indicate that this result is still a valid proxy. return false; diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 8115da862d..801d8d86bf 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -93,6 +93,19 @@ struct TestFunctionPass { int &AnalyzedInstrCount; }; +// A test function pass that invalidates all function analyses for a function +// with a specific name. +struct TestInvalidationFunctionPass { + TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {} + + PreservedAnalyses run(Function *F) { + return F->getName() == Name ? PreservedAnalyses::none() + : PreservedAnalyses::all(); + } + + StringRef Name; +}; + Module *parseIR(const char *IR) { LLVMContext &C = getGlobalContext(); SMDiagnostic Err; @@ -147,12 +160,14 @@ TEST_F(PassManagerTest, Basic) { FPM2.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2)); MPM.addPass(createModuleToFunctionPassAdaptor(FPM2)); - // A third function pass manager but with only preserving intervening passes. + // A third function pass manager but with only preserving intervening passes + // and with a function pass that invalidates exactly one analysis. MPM.addPass(TestPreservingModulePass()); FunctionPassManager FPM3; int FunctionPassRunCount3 = 0; int AnalyzedInstrCount3 = 0; FPM3.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3)); + FPM3.addPass(TestInvalidationFunctionPass("f")); MPM.addPass(createModuleToFunctionPassAdaptor(FPM3)); // A fourth function pass manager but with a minimal intervening passes. @@ -168,7 +183,7 @@ TEST_F(PassManagerTest, Basic) { // Validate module pass counters. EXPECT_EQ(1, ModulePassRunCount); - // Validate both function pass counter sets. + // Validate all function pass counter sets are the same. EXPECT_EQ(3, FunctionPassRunCount1); EXPECT_EQ(5, AnalyzedInstrCount1); EXPECT_EQ(3, FunctionPassRunCount2); @@ -178,7 +193,11 @@ TEST_F(PassManagerTest, Basic) { EXPECT_EQ(3, FunctionPassRunCount4); EXPECT_EQ(5, AnalyzedInstrCount4); - // Validate the analysis counters. - EXPECT_EQ(9, AnalysisRuns); + // 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); } } -- cgit v1.2.3