[llvm] r195338 - [PM] Widen the interface for invalidate on an analysis result now that

Chandler Carruth chandlerc at gmail.com
Thu Nov 21 02:53:05 PST 2013


Author: chandlerc
Date: Thu Nov 21 04:53:05 2013
New Revision: 195338

URL: http://llvm.org/viewvc/llvm-project?rev=195338&view=rev
Log:
[PM] Widen the interface for invalidate on an analysis result now that
it is completely optional, and sink the logic for handling the preserved
analysis set into it.

This allows us to implement the delegation logic desired in the proxy
module analysis for the function analysis manager where if the proxy
itself is preserved we assume the set of functions hasn't changed and we
do a fine grained invalidation by walking the functions in the module
and running the invalidate for them all at the manager level and letting
it try to invalidate any passes.

This in turn makes it blindingly obvious why we should hoist the
invalidate trait and have two collections of results. That allows
handling invalidation for almost all analyses without indirect calls and
it allows short circuiting when the preserved set is all.

Modified:
    llvm/trunk/include/llvm/IR/PassManager.h
    llvm/trunk/lib/IR/PassManager.cpp
    llvm/trunk/unittests/IR/PassManagerTest.cpp

Modified: llvm/trunk/include/llvm/IR/PassManager.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/PassManager.h?rev=195338&r1=195337&r2=195338&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/PassManager.h (original)
+++ llvm/trunk/include/llvm/IR/PassManager.h Thu Nov 21 04:53:05 2013
@@ -185,11 +185,15 @@ template <typename IRUnitT> struct Analy
 
   /// \brief Method to try and mark a result as invalid.
   ///
-  /// When the outer \c AnalysisManager detects a change in some underlying
+  /// When the outer analysis manager detects a change in some underlying
   /// unit of the IR, it will call this method on all of the results cached.
   ///
-  /// \returns true if the result should indeed be invalidated (the default).
-  virtual bool invalidate(IRUnitT *IR) = 0;
+  /// This method also receives a set of preserved analyses which can be used
+  /// to avoid invalidation because the pass which changed the underlying IR
+  /// took care to update or preserve the analysis result in some way.
+  ///
+  /// \returns true if the result is indeed invalid (the default).
+  virtual bool invalidate(IRUnitT *IR, const PreservedAnalyses &PA) = 0;
 };
 
 /// \brief Wrapper to model the analysis result concept.
@@ -198,19 +202,22 @@ template <typename IRUnitT> struct Analy
 /// implementation so that the actual analysis result doesn't need to provide
 /// an invalidation handler. It is only selected when the invalidation handler
 /// is not part of the ResultT's interface.
-template <typename IRUnitT, typename ResultT, bool HasInvalidateHandler = false>
+template <typename IRUnitT, typename PassT, typename ResultT,
+          bool HasInvalidateHandler = false>
 struct AnalysisResultModel : AnalysisResultConcept<IRUnitT> {
   AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
   virtual AnalysisResultModel *clone() {
     return new AnalysisResultModel(Result);
   }
 
-  /// \brief The model returns true to allow the invalidation.
+  /// \brief The model bases invalidation soley on being in the preserved set.
   //
   // FIXME: We should actually use two different concepts for analysis results
   // rather than two different models, and avoid the indirect function call for
   // ones that use the trivial behavior.
-  virtual bool invalidate(IRUnitT *) { return true; }
+  virtual bool invalidate(IRUnitT *, const PreservedAnalyses &PA) {
+    return !PA.preserved(PassT::ID());
+  }
 
   ResultT Result;
 };
@@ -219,15 +226,18 @@ struct AnalysisResultModel : AnalysisRes
 ///
 /// Can wrap any type which implements a suitable invalidate member and model
 /// the AnalysisResultConcept for the AnalysisManager.
-template <typename IRUnitT, typename ResultT>
-struct AnalysisResultModel<IRUnitT, ResultT, true> : AnalysisResultConcept<IRUnitT> {
+template <typename IRUnitT, typename PassT, typename ResultT>
+struct AnalysisResultModel<IRUnitT, PassT, ResultT,
+                           true> : AnalysisResultConcept<IRUnitT> {
   AnalysisResultModel(ResultT Result) : Result(llvm_move(Result)) {}
   virtual AnalysisResultModel *clone() {
     return new AnalysisResultModel(Result);
   }
 
   /// \brief The model delegates to the \c ResultT method.
-  virtual bool invalidate(IRUnitT *IR) { return Result.invalidate(IR); }
+  virtual bool invalidate(IRUnitT *IR, const PreservedAnalyses &PA) {
+    return Result.invalidate(IR, PA);
+  }
 
   ResultT Result;
 };
@@ -237,7 +247,10 @@ struct AnalysisResultModel<IRUnitT, Resu
 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
   typedef char SmallType;
   struct BigType { char a, b; };
-  template <typename T, bool (T::*)(IRUnitT *)> struct Checker;
+
+  template <typename T, bool (T::*)(IRUnitT *, const PreservedAnalyses &)>
+  struct Checker;
+
   template <typename T> static SmallType f(Checker<T, &T::invalidate> *);
   template <typename T> static BigType f(...);
 
@@ -274,7 +287,7 @@ struct AnalysisPassModel : AnalysisPassC
 
   // FIXME: Replace PassT::Result with type traits when we use C++11.
   typedef AnalysisResultModel<
-      IRUnitT, typename PassT::Result,
+      IRUnitT, PassT, typename PassT::Result,
       ResultHasInvalidateMethod<IRUnitT, typename PassT::Result>::Value>
           ResultModelT;
 
@@ -363,7 +376,7 @@ public:
     const detail::AnalysisResultConcept<Module> &ResultConcept =
         getResultImpl(PassT::ID(), M);
     typedef detail::AnalysisResultModel<
-        Module, typename PassT::Result,
+        Module, PassT, typename PassT::Result,
         detail::ResultHasInvalidateMethod<
             Module, typename PassT::Result>::Value> ResultModelT;
     return static_cast<const ResultModelT &>(ResultConcept).Result;
@@ -447,7 +460,7 @@ public:
     const detail::AnalysisResultConcept<Function> &ResultConcept =
         getResultImpl(PassT::ID(), F);
     typedef detail::AnalysisResultModel<
-        Function, typename PassT::Result,
+        Function, PassT, typename PassT::Result,
         detail::ResultHasInvalidateMethod<
             Function, typename PassT::Result>::Value> ResultModelT;
     return static_cast<const ResultModelT &>(ResultConcept).Result;
@@ -591,7 +604,16 @@ public:
   ~Result();
 
   /// \brief Handler for invalidation of the module.
-  bool invalidate(Module *M);
+  ///
+  /// If this analysis itself is preserved, then we assume that the set of \c
+  /// Function objects in the \c Module hasn't changed and thus we don't need
+  /// to invalidate *all* cached data associated with a \c Function* in the \c
+  /// FunctionAnalysisManager.
+  ///
+  /// Regardless of whether this analysis is marked as preserved, all of the
+  /// analyses in the \c FunctionAnalysisManager are potentially invalidated
+  /// based on the set of preserved analyses.
+  bool invalidate(Module *M, const PreservedAnalyses &PA);
 
 private:
   FunctionAnalysisManager &FAM;
@@ -623,6 +645,9 @@ public:
       PreservedAnalyses PassPA = Pass.run(I);
       PA.intersect(llvm_move(PassPA));
     }
+    
+    // By definition we preserve the proxy.
+    PA.preserve<FunctionAnalysisModuleProxy>();
     return PA;
   }
 

Modified: llvm/trunk/lib/IR/PassManager.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=195338&r1=195337&r2=195338&view=diff
==============================================================================
--- llvm/trunk/lib/IR/PassManager.cpp (original)
+++ llvm/trunk/lib/IR/PassManager.cpp Thu Nov 21 04:53:05 2013
@@ -29,7 +29,7 @@ void ModuleAnalysisManager::invalidate(M
   for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
                                           E = ModuleAnalysisResults.end();
        I != E; ++I)
-    if (!PA.preserved(I->first) && I->second->invalidate(M))
+    if (I->second->invalidate(M, PA))
       ModuleAnalysisResults.erase(I);
 }
 
@@ -76,7 +76,7 @@ void FunctionAnalysisManager::invalidate
   for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
                                              E = ResultsList.end();
        I != E;)
-    if (!PA.preserved(I->first) && I->second->invalidate(F)) {
+    if (I->second->invalidate(F, PA)) {
       InvalidatedPassIDs.push_back(I->first);
       I = ResultsList.erase(I);
     } else {
@@ -145,11 +145,19 @@ FunctionAnalysisModuleProxy::Result::~Re
   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();
+bool FunctionAnalysisModuleProxy::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())) {
+    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;

Modified: llvm/trunk/unittests/IR/PassManagerTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/PassManagerTest.cpp?rev=195338&r1=195337&r2=195338&view=diff
==============================================================================
--- llvm/trunk/unittests/IR/PassManagerTest.cpp (original)
+++ llvm/trunk/unittests/IR/PassManagerTest.cpp Thu Nov 21 04:53:05 2013
@@ -64,6 +64,20 @@ struct TestModulePass {
   int &RunCount;
 };
 
+struct TestPreservingModulePass {
+  PreservedAnalyses run(Module *M) {
+    return PreservedAnalyses::all();
+  }
+};
+
+struct TestMinPreservingModulePass {
+  PreservedAnalyses run(Module *M) {
+    PreservedAnalyses PA;
+    PA.preserve<FunctionAnalysisModuleProxy>();
+    return PA;
+  }
+};
+
 struct TestFunctionPass {
   TestFunctionPass(FunctionAnalysisManager &AM, int &RunCount,
                    int &AnalyzedInstrCount)
@@ -137,6 +151,22 @@ TEST_F(PassManagerTest, Basic) {
   FPM2.addPass(TestFunctionPass(FAM, FunctionPassRunCount2, AnalyzedInstrCount2));
   MPM.addPass(createModuleToFunctionPassAdaptor(FPM2, &MAM));
 
+  // A third function pass manager but with only preserving intervening passes.
+  MPM.addPass(TestPreservingModulePass());
+  FunctionPassManager FPM3(&FAM);
+  int FunctionPassRunCount3 = 0;
+  int AnalyzedInstrCount3 = 0;
+  FPM3.addPass(TestFunctionPass(FAM, FunctionPassRunCount3, AnalyzedInstrCount3));
+  MPM.addPass(createModuleToFunctionPassAdaptor(FPM3, &MAM));
+
+  // A fourth function pass manager but with a minimal intervening passes.
+  MPM.addPass(TestMinPreservingModulePass());
+  FunctionPassManager FPM4(&FAM);
+  int FunctionPassRunCount4 = 0;
+  int AnalyzedInstrCount4 = 0;
+  FPM4.addPass(TestFunctionPass(FAM, FunctionPassRunCount4, AnalyzedInstrCount4));
+  MPM.addPass(createModuleToFunctionPassAdaptor(FPM4, &MAM));
+
   MPM.run(M.get());
 
   // Validate module pass counters.
@@ -147,8 +177,12 @@ TEST_F(PassManagerTest, Basic) {
   EXPECT_EQ(5, AnalyzedInstrCount1);
   EXPECT_EQ(3, FunctionPassRunCount2);
   EXPECT_EQ(5, AnalyzedInstrCount2);
+  EXPECT_EQ(3, FunctionPassRunCount3);
+  EXPECT_EQ(5, AnalyzedInstrCount3);
+  EXPECT_EQ(3, FunctionPassRunCount4);
+  EXPECT_EQ(5, AnalyzedInstrCount4);
 
   // Validate the analysis counters.
-  EXPECT_EQ(6, AnalysisRuns);
+  EXPECT_EQ(9, AnalysisRuns);
 }
 }





More information about the llvm-commits mailing list