[llvm] r194538 - Introduce an AnalysisManager which is like a pass manager but with a lot

Aaron Ballman aaron at aaronballman.com
Fri Nov 15 06:21:21 PST 2013


On Tue, Nov 12, 2013 at 8:12 PM, Chandler Carruth <chandlerc at gmail.com> wrote:
> Author: chandlerc
> Date: Tue Nov 12 19:12:08 2013
> New Revision: 194538
>
> URL: http://llvm.org/viewvc/llvm-project?rev=194538&view=rev
> Log:
> Introduce an AnalysisManager which is like a pass manager but with a lot
> more smarts in it. This is where most of the interesting logic that used
> to live in the implicit-scheduling-hackery of the old pass manager will
> live.
>
> Like the previous commits, note that this is a very early prototype!
> I expect substantial changes before this is ready to use.
>
> The core of the design is the following:
>
> - We have an AnalysisManager which can be used across a series of
>   passes over a module.
> - The code setting up a pass pipeline registers the analyses available
>   with the manager.
> - Individual transform passes can check than an analysis manager
>   provides the analyses they require in order to fail-fast.
> - There is *no* implicit registration or scheduling.
> - Analysis passes are different from other passes: they produce an
>   analysis result that is cached and made available via the analysis
>   manager.
> - Cached results are invalidated automatically by the pass managers.
> - When a transform pass requests an analysis result, either the analysis
>   is run to produce the result or a cached result is provided.
>
> There are a few aspects of this design that I *know* will change in
> subsequent commits:
> - Currently there is no "preservation" system, that needs to be added.
> - All of the analysis management should move up to the analysis library.
> - The analysis management needs to support at least SCC passes. Maybe
>   loop passes. Living in the analysis library will facilitate this.
> - Need support for analyses which are *both* module and function passes.
> - Need support for pro-actively running module analyses to have cached
>   results within a function pass manager.
> - Need a clear design for "immutable" passes.
> - Need support for requesting cached results when available and not
>   re-running the pass even if that would be necessary.
> - Need more thorough testing of all of this infrastructure.
>
> There are other aspects that I view as open questions I'm hoping to
> resolve as I iterate a bit on the infrastructure, and especially as
> I start writing actual passes against this.
> - Should we have separate management layers for function, module, and
>   SCC analyses? I think "yes", but I'm not yet ready to switch the code.
>   Adding SCC support will likely resolve this definitively.
> - How should the 'require' functionality work? Should *that* be the only
>   way to request results to ensure that passes always require things?
> - How should preservation work?
> - Probably some other things I'm forgetting. =]
>
> Look forward to more patches in shorter order now that this is in place.
>
> Added:
>     llvm/trunk/lib/IR/PassManager.cpp
> Modified:
>     llvm/trunk/include/llvm/IR/PassManager.h
>     llvm/trunk/lib/IR/CMakeLists.txt
>     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=194538&r1=194537&r2=194538&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/PassManager.h (original)
> +++ llvm/trunk/include/llvm/IR/PassManager.h Tue Nov 12 19:12:08 2013
> @@ -27,8 +27,12 @@
>  ///
>  //===----------------------------------------------------------------------===//
>
> +#include "llvm/ADT/DenseMap.h"
>  #include "llvm/ADT/polymorphic_ptr.h"
> +#include "llvm/Support/type_traits.h"
> +#include "llvm/IR/Function.h"
>  #include "llvm/IR/Module.h"
> +#include <list>
>  #include <vector>
>
>  namespace llvm {
> @@ -64,18 +68,17 @@ template <typename T, typename PassT> st
>
>  }
>
> +class AnalysisManager;
> +
>  class ModulePassManager {
>  public:
> -  ModulePassManager(Module *M) : M(M) {}
> +  ModulePassManager(Module *M, AnalysisManager *AM = 0) : M(M), AM(AM) {}
>
>    template <typename ModulePassT> void addPass(ModulePassT Pass) {
>      Passes.push_back(new ModulePassModel<ModulePassT>(llvm_move(Pass)));
>    }
>
> -  void run() {
> -    for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
> -      Passes[Idx]->run(M);
> -  }
> +  void run();
>
>  private:
>    // Pull in the concept type and model template specialized for modules.
> @@ -86,22 +89,19 @@ private:
>    };
>
>    Module *M;
> +  AnalysisManager *AM;
>    std::vector<polymorphic_ptr<ModulePassConcept> > Passes;
>  };
>
>  class FunctionPassManager {
>  public:
> +  FunctionPassManager(AnalysisManager *AM = 0) : AM(AM) {}
> +
>    template <typename FunctionPassT> void addPass(FunctionPassT Pass) {
>      Passes.push_back(new FunctionPassModel<FunctionPassT>(llvm_move(Pass)));
>    }
>
> -  bool run(Module *M) {
> -    bool Changed = false;
> -    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
> -      for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
> -        Changed |= Passes[Idx]->run(I);
> -    return Changed;
> -  }
> +  bool run(Module *M);
>
>  private:
>    // Pull in the concept type and model template specialized for functions.
> @@ -112,7 +112,289 @@ private:
>          : detail::PassModel<Function *, PassT>(Pass) {}
>    };
>
> +  AnalysisManager *AM;
>    std::vector<polymorphic_ptr<FunctionPassConcept> > Passes;
>  };
>
> +
> +/// \brief An analysis manager to coordinate and cache analyses run over
> +/// a module.
> +///
> +/// The analysis manager is typically used by passes in a pass pipeline
> +/// (consisting potentially of several individual pass managers) over a module
> +/// of IR. It provides registration of available analyses, declaring
> +/// requirements on support for specific analyses, running of an specific
> +/// analysis over a specific unit of IR to compute an analysis result, and
> +/// caching of the analysis results to reuse them across multiple passes.
> +///
> +/// It is the responsibility of callers to use the invalidation API to
> +/// invalidate analysis results when the IR they correspond to changes. The
> +/// \c ModulePassManager and \c FunctionPassManager do this automatically.
> +class AnalysisManager {
> +public:
> +  AnalysisManager(Module *M) : M(M) {}
> +
> +  /// \brief Get the result of an analysis pass for this module.
> +  ///
> +  /// If there is not a valid cached result in the manager already, this will
> +  /// re-run the analysis to produce a valid result.
> +  ///
> +  /// The module passed in must be the same module as the analysis manager was
> +  /// constructed around.
> +  template <typename PassT>
> +  const typename PassT::Result &getResult(Module *M) {
> +    const AnalysisResultConcept<Module> &ResultConcept =
> +        getResultImpl(PassT::ID(), M);
> +    typedef AnalysisResultModel<Module, typename PassT::Result> ResultModelT;
> +    return static_cast<const ResultModelT &>(ResultConcept).Result;
> +  }
> +
> +  /// \brief Get the result of an analysis pass for a function.
> +  ///
> +  /// If there is not a valid cached result in the manager already, this will
> +  /// re-run the analysis to produce a valid result.
> +  template <typename PassT>
> +  const typename PassT::Result &getResult(Function *F) {
> +    const AnalysisResultConcept<Function> &ResultConcept =
> +        getResultImpl(PassT::ID(), F);
> +    typedef AnalysisResultModel<Function, typename PassT::Result> ResultModelT;
> +    return static_cast<const ResultModelT &>(ResultConcept).Result;
> +  }
> +
> +  /// \brief Register an analysis pass with the manager.
> +  ///
> +  /// This provides an initialized and set-up analysis pass to the
> +  /// analysis
> +  /// manager. Whomever is setting up analysis passes must use this to
> +  /// populate
> +  /// the manager with all of the analysis passes available.
> +  template <typename PassT> void registerAnalysisPass(PassT Pass) {
> +    registerAnalysisPassImpl<PassT>(llvm_move(Pass));
> +  }
> +
> +  /// \brief Require that a particular analysis pass is provided by the manager.
> +  ///
> +  /// This allows transform passes to assert ther requirements during
> +  /// construction and fail fast if the analysis manager doesn't provide the
> +  /// needed facilities.
> +  ///
> +  /// We force the analysis manager to have these passes explicitly registered
> +  /// first to ensure that there is exactly one place in the code responsible
> +  /// for adding an analysis pass to the manager as all transforms will share
> +  /// a single pass within the manager and each may not be the canonical place
> +  /// to initialize such a pass.
> +  template <typename PassT> void requireAnalysisPass() {
> +    requireAnalysisPassImpl<PassT>();
> +  }
> +
> +  /// \brief Invalidate a specific analysis pass for an IR module.
> +  ///
> +  /// Note that the analysis result can disregard invalidation.
> +  template <typename PassT> void invalidate(Module *M) {
> +    invalidateImpl(PassT::ID(), M);
> +  }
> +
> +  /// \brief Invalidate a specific analysis pass for an IR function.
> +  ///
> +  /// Note that the analysis result can disregard invalidation.
> +  template <typename PassT> void invalidate(Function *F) {
> +    invalidateImpl(PassT::ID(), F);
> +  }
> +
> +  /// \brief Invalidate analyses cached for an IR Module.
> +  ///
> +  /// Note that specific analysis results can disregard invalidation by
> +  /// overriding their invalidate method.
> +  ///
> +  /// The module must be the module this analysis manager was constructed
> +  /// around.
> +  void invalidateAll(Module *M);
> +
> +  /// \brief Invalidate analyses cached for an IR Function.
> +  ///
> +  /// Note that specific analysis results can disregard invalidation by
> +  /// overriding the invalidate method.
> +  void invalidateAll(Function *F);
> +
> +private:
> +  /// \brief Abstract concept of an analysis result.
> +  ///
> +  /// This concept is parameterized over the IR unit that this result pertains
> +  /// to.
> +  template <typename IRUnitT> struct AnalysisResultConcept {
> +    virtual ~AnalysisResultConcept() {}
> +    virtual AnalysisResultConcept *clone() = 0;
> +
> +    /// \brief Method to try and mark a result as invalid.
> +    ///
> +    /// When the outer \c AnalysisManager 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;
> +  };
> +
> +  /// \brief Wrapper to model the analysis result concept.
> +  ///
> +  /// Can wrap any type which implements a suitable invalidate member and model
> +  /// the AnalysisResultConcept for the AnalysisManager.
> +  template <typename IRUnitT, typename ResultT>
> +  struct AnalysisResultModel : 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); }
> +
> +    ResultT Result;
> +  };
> +
> +  /// \brief Abstract concept of an analysis pass.
> +  ///
> +  /// This concept is parameterized over the IR unit that it can run over and
> +  /// produce an analysis result.
> +  template <typename IRUnitT> struct AnalysisPassConcept {
> +    virtual ~AnalysisPassConcept() {}
> +    virtual AnalysisPassConcept *clone() = 0;
> +
> +    /// \brief Method to run this analysis over a unit of IR.
> +    /// \returns The analysis result object to be queried by users, the caller
> +    /// takes ownership.
> +    virtual AnalysisResultConcept<IRUnitT> *run(IRUnitT *IR) = 0;
> +  };
> +
> +  /// \brief Wrapper to model the analysis pass concept.
> +  ///
> +  /// Can wrap any type which implements a suitable \c run method. The method
> +  /// must accept the IRUnitT as an argument and produce an object which can be
> +  /// wrapped in a \c AnalysisResultModel.
> +  template <typename PassT>
> +  struct AnalysisPassModel : AnalysisPassConcept<typename PassT::IRUnitT> {
> +    AnalysisPassModel(PassT Pass) : Pass(llvm_move(Pass)) {}
> +    virtual AnalysisPassModel *clone() { return new AnalysisPassModel(Pass); }
> +
> +    // FIXME: Replace PassT::IRUnitT with type traits when we use C++11.
> +    typedef typename PassT::IRUnitT IRUnitT;
> +
> +    // FIXME: Replace PassT::Result with type traits when we use C++11.
> +    typedef AnalysisResultModel<IRUnitT, typename PassT::Result> ResultModelT;
> +
> +    /// \brief The model delegates to the \c PassT::run method.
> +    ///
> +    /// The return is wrapped in an \c AnalysisResultModel.
> +    virtual ResultModelT *run(IRUnitT *IR) {
> +      return new ResultModelT(Pass.run(IR));
> +    }
> +
> +    PassT Pass;
> +  };
> +
> +
> +  /// \brief Get a module pass result, running the pass if necessary.
> +  const AnalysisResultConcept<Module> &getResultImpl(void *PassID, Module *M);
> +
> +  /// \brief Get a function pass result, running the pass if necessary.
> +  const AnalysisResultConcept<Function> &getResultImpl(void *PassID,
> +                                                       Function *F);
> +
> +  /// \brief Invalidate a module pass result.
> +  void invalidateImpl(void *PassID, Module *M);
> +
> +  /// \brief Invalidate a function pass result.
> +  void invalidateImpl(void *PassID, Function *F);
> +
> +
> +  /// \brief Module pass specific implementation of registration.
> +  template <typename PassT>
> +  typename enable_if<is_same<typename PassT::IRUnitT, Module> >::type
> +  registerAnalysisPassImpl(PassT Pass) {
> +    assert(!ModuleAnalysisPasses.count(PassT::ID()) &&
> +           "Registered the same analysis pass twice!");
> +    ModuleAnalysisPasses[PassT::ID()] =
> +        new AnalysisPassModel<PassT>(llvm_move(Pass));
> +  }
> +
> +  /// \brief Function pass specific implementation of registration.
> +  template <typename PassT>
> +  typename enable_if<is_same<typename PassT::IRUnitT, Function> >::type
> +  registerAnalysisPassImpl(PassT Pass) {
> +    assert(!FunctionAnalysisPasses.count(PassT::ID()) &&
> +           "Registered the same analysis pass twice!");
> +    FunctionAnalysisPasses[PassT::ID()] =
> +        new AnalysisPassModel<PassT>(llvm_move(Pass));
> +  }
> +
> +  /// \brief Module pass specific implementation of requirement declaration.
> +  template <typename PassT>
> +  typename enable_if<is_same<typename PassT::IRUnitT, Module> >::type
> +  requireAnalysisPassImpl() {
> +    assert(ModuleAnalysisPasses.count(PassT::ID()) &&
> +           "This analysis pass was not registered prior to being required");
> +  }
> +
> +  /// \brief Function pass specific implementation of requirement declaration.
> +  template <typename PassT>
> +  typename enable_if<is_same<typename PassT::IRUnitT, Function> >::type
> +  requireAnalysisPassImpl() {
> +    assert(FunctionAnalysisPasses.count(PassT::ID()) &&
> +           "This analysis pass was not registered prior to being required");
> +  }
> +
> +
> +  /// \brief Map type from module analysis pass ID to pass concept pointer.
> +  typedef DenseMap<void *, polymorphic_ptr<AnalysisPassConcept<Module> > >
> +  ModuleAnalysisPassMapT;
> +
> +  /// \brief Collection of module analysis passes, indexed by ID.
> +  ModuleAnalysisPassMapT ModuleAnalysisPasses;
> +
> +  /// \brief Map type from module analysis pass ID to pass result concept pointer.
> +  typedef DenseMap<void *, polymorphic_ptr<AnalysisResultConcept<Module> > >
> +  ModuleAnalysisResultMapT;
> +
> +  /// \brief Cache of computed module analysis results for this module.
> +  ModuleAnalysisResultMapT ModuleAnalysisResults;
> +
> +
> +  /// \brief Map type from function analysis pass ID to pass concept pointer.
> +  typedef DenseMap<void *, polymorphic_ptr<AnalysisPassConcept<Function> > >
> +  FunctionAnalysisPassMapT;
> +
> +  /// \brief Collection of function analysis passes, indexed by ID.
> +  FunctionAnalysisPassMapT FunctionAnalysisPasses;
> +
> +  /// \brief List of function analysis pass IDs and associated concept pointers.
> +  ///
> +  /// Requires iterators to be valid across appending new entries and arbitrary
> +  /// erases. Provides both the pass ID and concept pointer such that it is
> +  /// half of a bijection and provides storage for the actual result concept.
> +  typedef std::list<
> +      std::pair<void *, polymorphic_ptr<AnalysisResultConcept<Function> > > >
> +  FunctionAnalysisResultListT;
> +
> +  /// \brief Map type from function pointer to our custom list type.
> +  typedef DenseMap<Function *, FunctionAnalysisResultListT> FunctionAnalysisResultListMapT;
> +
> +  /// \brief Map from function to a list of function analysis results.
> +  ///
> +  /// Provides linear time removal of all analysis results for a function and
> +  /// the ultimate storage for a particular cached analysis result.
> +  FunctionAnalysisResultListMapT FunctionAnalysisResultLists;
> +
> +  /// \brief Map type from a pair of analysis ID and function pointer to an
> +  /// iterator into a particular result list.
> +  typedef DenseMap<std::pair<void *, Function *>,
> +                   FunctionAnalysisResultListT::iterator>
> +  FunctionAnalysisResultMapT;
> +
> +  /// \brief Map from an analysis ID and function to a particular cached
> +  /// analysis result.
> +  FunctionAnalysisResultMapT FunctionAnalysisResults;
> +
> +  /// \brief Module handle for the \c AnalysisManager.
> +  Module *M;
> +};
> +
>  }
>
> Modified: llvm/trunk/lib/IR/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/CMakeLists.txt?rev=194538&r1=194537&r2=194538&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/CMakeLists.txt (original)
> +++ llvm/trunk/lib/IR/CMakeLists.txt Tue Nov 12 19:12:08 2013
> @@ -27,6 +27,7 @@ add_llvm_library(LLVMCore
>    Metadata.cpp
>    Module.cpp
>    Pass.cpp
> +  PassManager.cpp
>    PassRegistry.cpp
>    PrintModulePass.cpp
>    Type.cpp
>
> Added: llvm/trunk/lib/IR/PassManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=194538&view=auto
> ==============================================================================
> --- llvm/trunk/lib/IR/PassManager.cpp (added)
> +++ llvm/trunk/lib/IR/PassManager.cpp Tue Nov 12 19:12:08 2013
> @@ -0,0 +1,155 @@
> +//===- PassManager.h - Infrastructure for managing & running IR passes ----===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/IR/PassManager.h"
> +#include "llvm/ADT/STLExtras.h"
> +
> +using namespace llvm;
> +
> +void ModulePassManager::run() {
> +  for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
> +    if (Passes[Idx]->run(M))
> +      if (AM) AM->invalidateAll(M);
> +}
> +
> +bool FunctionPassManager::run(Module *M) {
> +  bool Changed = false;
> +  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
> +    for (unsigned Idx = 0, Size = Passes.size(); Idx != Size; ++Idx)
> +      if (Passes[Idx]->run(I)) {
> +        Changed = true;
> +        if (AM) AM->invalidateAll(I);
> +      }
> +  return Changed;
> +}
> +
> +void AnalysisManager::invalidateAll(Function *F) {
> +  assert(F->getParent() == M && "Invalidating a function from another module!");
> +
> +  // First invalidate any module results we still have laying about.
> +  // FIXME: This is a total hack based on the fact that erasure doesn't
> +  // invalidate iteration for DenseMap.
> +  for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
> +                                          E = ModuleAnalysisResults.end();
> +       I != E; ++I)
> +    if (I->second->invalidate(M))
> +      ModuleAnalysisResults.erase(I);
> +
> +  // Now clear all the invalidated results associated specifically with this
> +  // function.
> +  SmallVector<void *, 8> InvalidatedPassIDs;
> +  FunctionAnalysisResultListT &ResultsList = FunctionAnalysisResultLists[F];
> +  for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
> +                                             E = ResultsList.end();
> +       I != E; ++I)
> +    if (I->second->invalidate(F)) {
> +      FunctionAnalysisResultListT::iterator Old = I--;

This is causing crashes in MSVC debug builds due to being an invalid
iterator operation. Specifically, when I == ResultsList.begin(),
attempting to decrement walks off the front of the iterator list.

Once I correct the issue locally, I get several new failing unit tests:

E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(189): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.
E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(193): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.
E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(189): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.
E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(193): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.
E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(189): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.
E:\llvm\llvm\unittests\IR\ValueMapTest.cpp(193): error: Value of:
Data.M->tryacquire()
  Actual: true
Expected: false
Mutex should already be locked.

> +      InvalidatedPassIDs.push_back(Old->first);
> +      ResultsList.erase(Old);
> +    }
> +  while (!InvalidatedPassIDs.empty())
> +    FunctionAnalysisResults.erase(
> +        std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
> +}
> +
> +void AnalysisManager::invalidateAll(Module *M) {
> +  // First invalidate any module results we still have laying about.
> +  // FIXME: This is a total hack based on the fact that erasure doesn't
> +  // invalidate iteration for DenseMap.
> +  for (ModuleAnalysisResultMapT::iterator I = ModuleAnalysisResults.begin(),
> +                                          E = ModuleAnalysisResults.end();
> +       I != E; ++I)
> +    if (I->second->invalidate(M))
> +      ModuleAnalysisResults.erase(I);
> +
> +  // Now walk all of the functions for which there are cached results, and
> +  // attempt to invalidate each of those as the entire module may have changed.
> +  // FIXME: How do we handle functions which have been deleted or RAUWed?
> +  SmallVector<void *, 8> InvalidatedPassIDs;
> +  for (FunctionAnalysisResultListMapT::iterator
> +           FI = FunctionAnalysisResultLists.begin(),
> +           FE = FunctionAnalysisResultLists.end();
> +       FI != FE; ++FI) {
> +    Function *F = FI->first;
> +    FunctionAnalysisResultListT &ResultsList = FI->second;
> +    for (FunctionAnalysisResultListT::iterator I = ResultsList.begin(),
> +                                               E = ResultsList.end();
> +         I != E; ++I)
> +      if (I->second->invalidate(F)) {
> +        FunctionAnalysisResultListT::iterator Old = I--;
> +        InvalidatedPassIDs.push_back(Old->first);
> +        ResultsList.erase(Old);
> +      }
> +    while (!InvalidatedPassIDs.empty())
> +      FunctionAnalysisResults.erase(
> +          std::make_pair(InvalidatedPassIDs.pop_back_val(), F));
> +  }
> +}
> +
> +const AnalysisManager::AnalysisResultConcept<Module> &
> +AnalysisManager::getResultImpl(void *PassID, Module *M) {
> +  assert(M == this->M && "Wrong module used when querying the AnalysisManager");
> +  ModuleAnalysisResultMapT::iterator RI;
> +  bool Inserted;
> +  llvm::tie(RI, Inserted) = ModuleAnalysisResults.insert(std::make_pair(
> +      PassID, polymorphic_ptr<AnalysisResultConcept<Module> >()));
> +
> +  if (Inserted) {
> +    // We don't have a cached result for this result. Look up the pass and run
> +    // it to produce a result, which we then add to the cache.
> +    ModuleAnalysisPassMapT::const_iterator PI =
> +        ModuleAnalysisPasses.find(PassID);
> +    assert(PI != ModuleAnalysisPasses.end() &&
> +           "Analysis passes must be registered prior to being queried!");
> +    RI->second = PI->second->run(M);
> +  }
> +
> +  return *RI->second;
> +}
> +
> +const AnalysisManager::AnalysisResultConcept<Function> &
> +AnalysisManager::getResultImpl(void *PassID, Function *F) {
> +  assert(F->getParent() == M && "Analyzing a function from another module!");
> +
> +  FunctionAnalysisResultMapT::iterator RI;
> +  bool Inserted;
> +  llvm::tie(RI, Inserted) = FunctionAnalysisResults.insert(std::make_pair(
> +      std::make_pair(PassID, F), FunctionAnalysisResultListT::iterator()));
> +
> +  if (Inserted) {
> +    // We don't have a cached result for this result. Look up the pass and run
> +    // it to produce a result, which we then add to the cache.
> +    FunctionAnalysisPassMapT::const_iterator PI =
> +        FunctionAnalysisPasses.find(PassID);
> +    assert(PI != FunctionAnalysisPasses.end() &&
> +           "Analysis passes must be registered prior to being queried!");
> +    FunctionAnalysisResultListT &ResultList = FunctionAnalysisResultLists[F];
> +    ResultList.push_back(std::make_pair(PassID, PI->second->run(F)));
> +    RI->second = llvm::prior(ResultList.end());
> +  }
> +
> +  return *RI->second->second;
> +}
> +
> +void AnalysisManager::invalidateImpl(void *PassID, Module *M) {
> +  assert(M == this->M && "Invalidating a pass over a different module!");
> +  ModuleAnalysisResults.erase(PassID);
> +}
> +
> +void AnalysisManager::invalidateImpl(void *PassID, Function *F) {
> +  assert(F->getParent() == M &&
> +         "Invalidating a pass over a function from another module!");
> +
> +  FunctionAnalysisResultMapT::iterator RI = FunctionAnalysisResults.find(std::make_pair(PassID, F));
> +  if (RI == FunctionAnalysisResults.end())
> +    return;
> +
> +  FunctionAnalysisResultLists[F].erase(RI->second);
> +}
> +
>
> Modified: llvm/trunk/unittests/IR/PassManagerTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/PassManagerTest.cpp?rev=194538&r1=194537&r2=194538&view=diff
> ==============================================================================
> --- llvm/trunk/unittests/IR/PassManagerTest.cpp (original)
> +++ llvm/trunk/unittests/IR/PassManagerTest.cpp Tue Nov 12 19:12:08 2013
> @@ -19,6 +19,36 @@ using namespace llvm;
>
>  namespace {
>
> +class TestAnalysisPass {
> +public:
> +  typedef Function IRUnitT;
> +
> +  struct Result {
> +    Result(int Count) : InstructionCount(Count) {}
> +    bool invalidate(Function *) { return true; }
> +    int InstructionCount;
> +  };
> +
> +  /// \brief Returns an opaque, unique ID for this pass type.
> +  static void *ID() { return (void *)&PassID; }
> +
> +  /// \brief Run the analysis pass over the function and return a result.
> +  Result run(Function *F) {
> +    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;
> +           ++II)
> +        ++Count;
> +    return Result(Count);
> +  }
> +
> +private:
> +  /// \brief Private static data to provide unique ID.
> +  static char PassID;
> +};
> +
> +char TestAnalysisPass::PassID;
> +
>  struct TestModulePass {
>    TestModulePass(int &RunCount) : RunCount(RunCount) {}
>
> @@ -31,14 +61,23 @@ struct TestModulePass {
>  };
>
>  struct TestFunctionPass {
> -  TestFunctionPass(int &RunCount) : RunCount(RunCount) {}
> +  TestFunctionPass(AnalysisManager &AM, int &RunCount, int &AnalyzedInstrCount)
> +      : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) {
> +    AM.requireAnalysisPass<TestAnalysisPass>();
> +  }
>
>    bool run(Function *F) {
>      ++RunCount;
> +
> +    const TestAnalysisPass::Result &AR = AM.getResult<TestAnalysisPass>(F);
> +    AnalyzedInstrCount += AR.InstructionCount;
> +
>      return true;
>    }
>
> +  AnalysisManager &AM;
>    int &RunCount;
> +  int &AnalyzedInstrCount;
>  };
>
>  Module *parseIR(const char *IR) {
> @@ -68,8 +107,11 @@ public:
>  };
>
>  TEST_F(PassManagerTest, Basic) {
> -  ModulePassManager MPM(M.get());
> -  FunctionPassManager FPM;
> +  AnalysisManager AM(M.get());
> +  AM.registerAnalysisPass(TestAnalysisPass());
> +
> +  ModulePassManager MPM(M.get(), &AM);
> +  FunctionPassManager FPM(&AM);
>
>    // Count the runs over a module.
>    int ModulePassRunCount = 0;
> @@ -77,12 +119,14 @@ TEST_F(PassManagerTest, Basic) {
>
>    // Count the runs over a Function.
>    int FunctionPassRunCount = 0;
> -  FPM.addPass(TestFunctionPass(FunctionPassRunCount));
> +  int AnalyzedInstrCount = 0;
> +  FPM.addPass(TestFunctionPass(AM, FunctionPassRunCount, AnalyzedInstrCount));
>    MPM.addPass(FPM);
>
>    MPM.run();
>    EXPECT_EQ(1, ModulePassRunCount);
>    EXPECT_EQ(3, FunctionPassRunCount);
> +  EXPECT_EQ(5, AnalyzedInstrCount);
>  }
>
>  }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

~Aaron



More information about the llvm-commits mailing list