[llvm] r289317 - [PM] Support invalidation of inner analysis managers from a pass over the outer IR unit.

Galina Kistanova via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 20 16:18:02 PST 2016


Hello Chandler,

This commit added warning to some builders:

PassManager.h(803): warning C4661: 'bool
llvm::InnerAnalysisManagerProxy<llvm::FunctionAnalysisManager,llvm::LazyCallGraph::SCC,llvm::LazyCallGraph
&>::Result::invalidate(IRUnitT &,const llvm::PreservedAnalyses
&,llvm::AnalysisManager<IRUnitT,llvm::LazyCallGraph &>::Invalidator &)': no
suitable definition provided for explicit template instantiation request

http://lab.llvm.org:8011/builders/llvm-clang-lld-x86_64-scei-ps4-windows10pro-fast/builds/2937

Please have a look at this?

Thanks

Galina


On Fri, Dec 9, 2016 at 10:34 PM, Chandler Carruth via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: chandlerc
> Date: Sat Dec 10 00:34:44 2016
> New Revision: 289317
>
> URL: http://llvm.org/viewvc/llvm-project?rev=289317&view=rev
> Log:
> [PM] Support invalidation of inner analysis managers from a pass over the
> outer IR unit.
>
> Summary:
> This never really got implemented, and was very hard to test before
> a lot of the refactoring changes to make things more robust. But now we
> can test it thoroughly and cleanly, especially at the CGSCC level.
>
> The core idea is that when an inner analysis manager proxy receives the
> invalidation event for the outer IR unit, it needs to walk the inner IR
> units and propagate it to the inner analysis manager for each of those
> units. For example, each function in the SCC needs to get an
> invalidation event when the SCC gets one.
>
> The function / module interaction is somewhat boring here. This really
> becomes interesting in the face of analysis-backed IR units. This patch
> effectively handles all of the CGSCC layer's needs -- both invalidating
> SCC analysis and invalidating function analysis when an SCC gets
> invalidated.
>
> However, this second aspect doesn't really handle the
> LoopAnalysisManager well at this point. That one will need some change
> of design in order to fully integrate, because unlike the call graph,
> the entire function behind a LoopAnalysis's results can vanish out from
> under us, and we won't even have a cached API to access. I'd like to try
> to separate solving the loop problems into a subsequent patch though in
> order to keep this more focused so I've adapted them to the API and
> updated the tests that immediately fail, but I've not added the level of
> testing and validation at that layer that I have at the CGSCC layer.
>
> An important aspect of this change is that the proxy for the
> FunctionAnalysisManager at the SCC pass layer doesn't work like the
> other proxies for an inner IR unit as it doesn't directly manage the
> FunctionAnalysisManager and invalidation or clearing of it. This would
> create an ever worsening problem of dual ownership of this
> responsibility, split between the module-level FAM proxy and this
> SCC-level FAM proxy. Instead, this patch changes the SCC-level FAM proxy
> to work in terms of the module-level proxy and defer to it to handle
> much of the updates. It only does SCC-specific invalidation. This will
> become more important in subsequent patches that support more complex
> invalidaiton scenarios.
>
> Reviewers: jlebar
>
> Subscribers: mehdi_amini, mcrosier, mzolotukhin, llvm-commits
>
> Differential Revision: https://reviews.llvm.org/D27197
>
> Modified:
>     llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h
>     llvm/trunk/include/llvm/Analysis/LoopPassManager.h
>     llvm/trunk/include/llvm/IR/PassManager.h
>     llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
>     llvm/trunk/lib/Analysis/LoopPassManager.cpp
>     llvm/trunk/lib/IR/PassManager.cpp
>     llvm/trunk/lib/Passes/PassBuilder.cpp
>     llvm/trunk/lib/Passes/PassRegistry.def
>     llvm/trunk/test/Other/new-pass-manager.ll
>     llvm/trunk/unittests/Analysis/CGSCCPassManagerTest.cpp
>     llvm/trunk/unittests/IR/PassManagerTest.cpp
>
> Modified: llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/
> CGSCCPassManager.h?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h (original)
> +++ llvm/trunk/include/llvm/Analysis/CGSCCPassManager.h Sat Dec 10
> 00:34:44 2016
> @@ -145,13 +145,51 @@ struct RequireAnalysisPass<AnalysisT, La
>    }
>  };
>
> -extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager,
> Module>;
>  /// A proxy from a \c CGSCCAnalysisManager to a \c Module.
>  typedef InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>
>      CGSCCAnalysisManagerModuleProxy;
>
> -extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
> -                                                LazyCallGraph::SCC>;
> +/// We need a specialized result for the \c CGSCCAnalysisManagerModuleProxy
> so
> +/// it can have access to the call graph in order to walk all the SCCs
> when
> +/// invalidating things.
> +template <> class CGSCCAnalysisManagerModuleProxy::Result {
> +public:
> +  explicit Result(CGSCCAnalysisManager &InnerAM, LazyCallGraph &G)
> +      : InnerAM(&InnerAM), G(&G) {}
> +
> +  /// \brief Accessor for the analysis manager.
> +  CGSCCAnalysisManager &getManager() { return *InnerAM; }
> +
> +  /// \brief Handler for invalidation of the Module.
> +  ///
> +  /// If the proxy analysis itself is preserved, then we assume that the
> set of
> +  /// SCCs in the Module hasn't changed. Thus any pointers to SCCs in the
> +  /// CGSCCAnalysisManager are still valid, and we don't need to call \c
> clear
> +  /// on the CGSCCAnalysisManager.
> +  ///
> +  /// Regardless of whether this analysis is marked as preserved, all of
> the
> +  /// analyses in the \c CGSCCAnalysisManager are potentially invalidated
> based
> +  /// on the set of preserved analyses.
> +  bool invalidate(Module &M, const PreservedAnalyses &PA,
> +                  ModuleAnalysisManager::Invalidator &Inv);
> +
> +private:
> +  CGSCCAnalysisManager *InnerAM;
> +  LazyCallGraph *G;
> +};
> +
> +/// Provide a specialized run method for the \c
> CGSCCAnalysisManagerModuleProxy
> +/// so it can pass the lazy call graph to the result.
> +template <>
> +CGSCCAnalysisManagerModuleProxy::Result
> +CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager
> &AM);
> +
> +// Ensure the \c CGSCCAnalysisManagerModuleProxy is provided as an extern
> +// template.
> +extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager,
> Module>;
> +
> +extern template class OuterAnalysisManagerProxy<
> +    ModuleAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;
>  /// A proxy from a \c ModuleAnalysisManager to an \c SCC.
>  typedef OuterAnalysisManagerProxy<ModuleAnalysisManager,
> LazyCallGraph::SCC,
>                                    LazyCallGraph &>
> @@ -387,12 +425,12 @@ public:
>        } while (!RCWorklist.empty());
>      }
>
> -    // By definition we preserve the proxy. We also preserve all analyses
> on
> -    // SCCs. This precludes *any* invalidation of CGSCC analyses by the
> proxy,
> -    // but that's OK because we've taken care to invalidate analyses in
> the
> -    // CGSCC analysis manager incrementally above.
> +    // By definition we preserve the call garph, all SCC analyses, and the
> +    // analysis proxies by handling them above and in any nested pass
> managers.
> +    PA.preserve<LazyCallGraphAnalysis>();
>      PA.preserve<AllAnalysesOn<LazyCallGraph::SCC>>();
>      PA.preserve<CGSCCAnalysisManagerModuleProxy>();
> +    PA.preserve<FunctionAnalysisManagerModuleProxy>();
>      return PA;
>    }
>
> @@ -409,12 +447,43 @@ createModuleToPostOrderCGSCCPassAdaptor(
>    return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass),
> DebugLogging);
>  }
>
> -extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
> -                                                LazyCallGraph::SCC>;
>  /// A proxy from a \c FunctionAnalysisManager to an \c SCC.
> -typedef InnerAnalysisManagerProxy<FunctionAnalysisManager,
> LazyCallGraph::SCC,
> -                                  LazyCallGraph &>
> -    FunctionAnalysisManagerCGSCCProxy;
> +///
> +/// When a module pass runs and triggers invalidation, both the CGSCC and
> +/// Function analysis manager proxies on the module get an invalidation
> event.
> +/// We don't want to fully duplicate responsibility for most of the
> +/// invalidation logic. Instead, this layer is only responsible for
> SCC-local
> +/// invalidation events. We work with the module's
> FunctionAnalysisManager to
> +/// invalidate function analyses.
> +class FunctionAnalysisManagerCGSCCProxy
> +    : public AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy> {
> +public:
> +  class Result {
> +  public:
> +    explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
> +
> +    /// \brief Accessor for the analysis manager.
> +    FunctionAnalysisManager &getManager() { return *FAM; }
> +
> +    bool invalidate(LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
> +                    CGSCCAnalysisManager::Invalidator &Inv);
> +
> +  private:
> +    FunctionAnalysisManager *FAM;
> +  };
> +
> +  /// Computes the \c FunctionAnalysisManager and stores it in the result
> proxy.
> +  Result run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
> LazyCallGraph &);
> +
> +private:
> +  friend AnalysisInfoMixin<FunctionAnalysisManagerCGSCCProxy>;
> +  static AnalysisKey Key;
> +};
> +
> +// Ensure the \c FunctionAnalysisManagerCGSCCProxy is provided as an
> extern
> +// template.
> +extern template class InnerAnalysisManagerProxy<
> +    FunctionAnalysisManager, LazyCallGraph::SCC, LazyCallGraph &>;
>
>  extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager,
> Function>;
>  /// A proxy from a \c CGSCCAnalysisManager to a \c Function.
>
> Modified: llvm/trunk/include/llvm/Analysis/LoopPassManager.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/
> llvm/Analysis/LoopPassManager.h?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/include/llvm/Analysis/LoopPassManager.h (original)
> +++ llvm/trunk/include/llvm/Analysis/LoopPassManager.h Sat Dec 10
> 00:34:44 2016
> @@ -38,11 +38,21 @@ extern template class AnalysisManager<Lo
>  /// pass manager infrastructure.
>  typedef AnalysisManager<Loop> LoopAnalysisManager;
>
> -extern template class InnerAnalysisManagerProxy<LoopAnalysisManager,
> Function>;
>  /// A proxy from a \c LoopAnalysisManager to a \c Function.
>  typedef InnerAnalysisManagerProxy<LoopAnalysisManager, Function>
>      LoopAnalysisManagerFunctionProxy;
>
> +/// Specialization of the invalidate method for the \c
> +/// LoopAnalysisManagerFunctionProxy's result.
> +template <>
> +bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
> +    Function &F, const PreservedAnalyses &PA,
> +    FunctionAnalysisManager::Invalidator &Inv);
> +
> +// Ensure the \c LoopAnalysisManagerFunctionProxy is provided as an
> extern
> +// template.
> +extern template class InnerAnalysisManagerProxy<LoopAnalysisManager,
> Function>;
> +
>  extern template class OuterAnalysisManagerProxy<FunctionAnalysisManager,
> Loop>;
>  /// A proxy from a \c FunctionAnalysisManager to a \c Loop.
>  typedef OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>
>
> Modified: llvm/trunk/include/llvm/IR/PassManager.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/
> llvm/IR/PassManager.h?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/include/llvm/IR/PassManager.h (original)
> +++ llvm/trunk/include/llvm/IR/PassManager.h Sat Dec 10 00:34:44 2016
> @@ -750,63 +750,61 @@ class InnerAnalysisManagerProxy
>  public:
>    class Result {
>    public:
> -    explicit Result(AnalysisManagerT &AM) : AM(&AM) {}
> -    Result(Result &&Arg) : AM(std::move(Arg.AM)) {
> +    explicit Result(AnalysisManagerT &InnerAM) : InnerAM(&InnerAM) {}
> +    Result(Result &&Arg) : InnerAM(std::move(Arg.InnerAM)) {
>        // We have to null out the analysis manager in the moved-from state
>        // because we are taking ownership of the responsibilty to clear the
>        // analysis state.
> -      Arg.AM = nullptr;
> +      Arg.InnerAM = nullptr;
>      }
>      Result &operator=(Result &&RHS) {
> -      AM = RHS.AM;
> +      InnerAM = RHS.InnerAM;
>        // We have to null out the analysis manager in the moved-from state
>        // because we are taking ownership of the responsibilty to clear the
>        // analysis state.
> -      RHS.AM = nullptr;
> +      RHS.InnerAM = nullptr;
>        return *this;
>      }
>      ~Result() {
> -      // AM is cleared in a moved from state where there is nothing to do.
> -      if (!AM)
> +      // InnerAM is cleared in a moved from state where there is nothing
> to do.
> +      if (!InnerAM)
>          return;
>
>        // Clear out the analysis manager if we're being destroyed -- it
> means we
>        // didn't even see an invalidate call when we got invalidated.
> -      AM->clear();
> +      InnerAM->clear();
>      }
>
>      /// \brief Accessor for the analysis manager.
> -    AnalysisManagerT &getManager() { return *AM; }
> +    AnalysisManagerT &getManager() { return *InnerAM; }
>
> -    /// \brief Handler for invalidation of the module.
> +    /// \brief Handler for invalidation of the outer IR unit.
>      ///
>      /// 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.
> +    /// IR units that the inner analysis manager controls hasn't changed
> and
> +    /// thus we don't need to invalidate *all* cached data associated
> with any
> +    /// \c IRUnitT* in the \c AnalysisManagerT.
>      ///
>      /// 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.
> +    /// analyses in the \c AnalysisManagerT are potentially invalidated
> (for
> +    /// the relevant inner set of their IR units) based on the set of
> preserved
> +    /// analyses.
> +    ///
> +    /// Because this needs to understand the mapping from one IR unit to
> an
> +    /// inner IR unit, this method isn't defined in the primary template.
> +    /// Instead, each specialization of this template will need to
> provide an
> +    /// explicit specialization of this method to handle that particular
> pair
> +    /// of IR unit and inner AnalysisManagerT.
>      bool invalidate(
>          IRUnitT &IR, const PreservedAnalyses &PA,
> -        typename AnalysisManager<IRUnitT, ExtraArgTs...>::Invalidator &) {
> -      // 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(InnerAnalysisManagerProxy::ID()))
> -        AM->clear();
> -
> -      // Return false to indicate that this result is still a valid proxy.
> -      return false;
> -    }
> +        typename AnalysisManager<IRUnitT, ExtraArgTs...>::Invalidator
> &Inv);
>
>    private:
> -    AnalysisManagerT *AM;
> +    AnalysisManagerT *InnerAM;
>    };
>
> -  explicit InnerAnalysisManagerProxy(AnalysisManagerT &AM) : AM(&AM) {}
> +  explicit InnerAnalysisManagerProxy(AnalysisManagerT &InnerAM)
> +      : InnerAM(&InnerAM) {}
>
>    /// \brief Run the analysis pass and create our proxy result object.
>    ///
> @@ -817,9 +815,9 @@ public:
>    /// In debug builds, it will also assert that the analysis manager is
> empty
>    /// as no queries should arrive at the function analysis manager prior
> to
>    /// this analysis being requested.
> -  Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &,
> +  Result run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
>               ExtraArgTs...) {
> -    return Result(*AM);
> +    return Result(*InnerAM);
>    }
>
>  private:
> @@ -827,19 +825,29 @@ private:
>        InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT>>;
>    static AnalysisKey Key;
>
> -  AnalysisManagerT *AM;
> +  AnalysisManagerT *InnerAM;
>  };
>
>  template <typename AnalysisManagerT, typename IRUnitT, typename...
> ExtraArgTs>
>  AnalysisKey
>      InnerAnalysisManagerProxy<AnalysisManagerT, IRUnitT,
> ExtraArgTs...>::Key;
>
> -extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
> -                                                Module>;
>  /// Provide the \c FunctionAnalysisManager to \c Module proxy.
>  typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, Module>
>      FunctionAnalysisManagerModuleProxy;
>
> +/// Specialization of the invalidate method for the \c
> +/// FunctionAnalysisManagerModuleProxy's result.
> +template <>
> +bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
> +    Module &M, const PreservedAnalyses &PA,
> +    ModuleAnalysisManager::Invalidator &Inv);
> +
> +// Ensure the \c FunctionAnalysisManagerModuleProxy is provided as an
> extern
> +// template.
> +extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
> +                                                Module>;
> +
>  /// \brief A function analysis which acts as a proxy for a module analysis
>  /// manager.
>  ///
>
> Modified: llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/
> Analysis/CGSCCPassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Analysis/CGSCCPassManager.cpp (original)
> +++ llvm/trunk/lib/Analysis/CGSCCPassManager.cpp Sat Dec 10 00:34:44 2016
> @@ -13,6 +13,8 @@
>
>  using namespace llvm;
>
> +// Explicit template instantiations and specialization defininitions for
> core
> +// template typedefs.
>  namespace llvm {
>
>  // Explicit instantiations for the core proxy templates.
> @@ -22,9 +24,9 @@ template class PassManager<LazyCallGraph
>                             LazyCallGraph &, CGSCCUpdateResult &>;
>  template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>;
>  template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
> -                                         LazyCallGraph::SCC>;
> +                                         LazyCallGraph::SCC,
> LazyCallGraph &>;
>  template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
> -                                         LazyCallGraph::SCC>;
> +                                         LazyCallGraph::SCC,
> LazyCallGraph &>;
>  template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>;
>
>  /// Explicitly specialize the pass manager run method to handle call graph
> @@ -84,6 +86,87 @@ PassManager<LazyCallGraph::SCC, CGSCCAna
>    return PA;
>  }
>
> +bool CGSCCAnalysisManagerModuleProxy::Result::invalidate(
> +    Module &M, const PreservedAnalyses &PA,
> +    ModuleAnalysisManager::Invalidator &Inv) {
> +  // If this proxy or the call graph is going to be invalidated, we also
> need
> +  // to clear all the keys coming from that analysis.
> +  //
> +  // We also directly invalidate the FAM's module proxy if necessary, and
> if
> +  // that proxy isn't preserved we can't preserve this proxy either. We
> rely on
> +  // it to handle module -> function analysis invalidation in the face of
> +  // structural changes and so if it's unavailable we conservatively
> clear the
> +  // entire SCC layer as well rather than trying to do invaliadtion
> ourselves.
> +  if (!PA.preserved<CGSCCAnalysisManagerModuleProxy>() ||
> +      Inv.invalidate<LazyCallGraphAnalysis>(M, PA) ||
> +      Inv.invalidate<FunctionAnalysisManagerModuleProxy>(M, PA)) {
> +    InnerAM->clear();
> +
> +    // And the proxy itself should be marked as invalid so that we can
> observe
> +    // the new call graph. This isn't strictly necessary because we cheat
> +    // above, but is still useful.
> +    return true;
> +  }
> +
> +  // Ok, we have a graph, so we can propagate the invalidation down into
> it.
> +  for (auto &RC : G->postorder_ref_sccs())
> +    for (auto &C : RC)
> +      InnerAM->invalidate(C, PA);
> +
> +  // Return false to indicate that this result is still a valid proxy.
> +  return false;
> +}
> +
> +template <>
> +CGSCCAnalysisManagerModuleProxy::Result
> +CGSCCAnalysisManagerModuleProxy::run(Module &M, ModuleAnalysisManager
> &AM) {
> +  // Force the Function analysis manager to also be available so that it
> can
> +  // be accessed in an SCC analysis and proxied onward to function passes.
> +  // FIXME: It is pretty awkward to just drop the result here and assert
> that
> +  // we can find it again later.
> +  (void)AM.getResult<FunctionAnalysisManagerModuleProxy>(M);
> +
> +  return Result(*InnerAM, AM.getResult<LazyCallGraphAnalysis>(M));
> +}
> +
> +AnalysisKey FunctionAnalysisManagerCGSCCProxy::Key;
> +
> +FunctionAnalysisManagerCGSCCProxy::Result
> +FunctionAnalysisManagerCGSCCProxy::run(LazyCallGraph::SCC &C,
> +                                       CGSCCAnalysisManager &AM,
> +                                       LazyCallGraph &CG) {
> +  // Collect the FunctionAnalysisManager from the Module layer and use
> that to
> +  // build the proxy result.
> +  //
> +  // This allows us to rely on the FunctionAnalysisMangaerModuleProxy to
> +  // invalidate the function analyses.
> +  auto &MAM = AM.getResult<ModuleAnalysisManagerCGSCCProxy>(C,
> CG).getManager();
> +  Module &M = *C.begin()->getFunction().getParent();
> +  auto *FAMProxy = MAM.getCachedResult<FunctionAnalysisManagerModuleP
> roxy>(M);
> +  assert(FAMProxy && "The CGSCC pass manager requires that the FAM module
> "
> +                     "proxy is run on the module prior to entering the
> CGSCC "
> +                     "walk.");
> +
> +  // Note that we special-case invalidation handling of this proxy in the
> CGSCC
> +  // analysis manager's Module proxy. This avoids the need to do anything
> +  // special here to recompute all of this if ever the FAM's module proxy
> goes
> +  // away.
> +  return Result(FAMProxy->getManager());
> +}
> +
> +bool FunctionAnalysisManagerCGSCCProxy::Result::invalidate(
> +    LazyCallGraph::SCC &C, const PreservedAnalyses &PA,
> +    CGSCCAnalysisManager::Invalidator &Inv) {
> +  for (LazyCallGraph::Node &N : C)
> +    FAM->invalidate(N.getFunction(), PA);
> +
> +  // This proxy doesn't need to handle invalidation itself. Instead, the
> +  // module-level CGSCC proxy handles it above by ensuring that if the
> +  // module-level FAM proxy becomes invalid the entire SCC layer, which
> +  // includes this proxy, is cleared.
> +  return false;
> +}
> +
>  } // End llvm namespace
>
>  namespace {
>
> Modified: llvm/trunk/lib/Analysis/LoopPassManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/
> Analysis/LoopPassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Analysis/LoopPassManager.cpp (original)
> +++ llvm/trunk/lib/Analysis/LoopPassManager.cpp Sat Dec 10 00:34:44 2016
> @@ -17,12 +17,30 @@
>
>  using namespace llvm;
>
> -// Explicit instantiations for core typedef'ed templates.
> +// Explicit template instantiations and specialization defininitions for
> core
> +// template typedefs.
>  namespace llvm {
>  template class PassManager<Loop>;
>  template class AnalysisManager<Loop>;
>  template class InnerAnalysisManagerProxy<LoopAnalysisManager, Function>;
>  template class OuterAnalysisManagerProxy<FunctionAnalysisManager, Loop>;
> +
> +template <>
> +bool LoopAnalysisManagerFunctionProxy::Result::invalidate(
> +    Function &F, const PreservedAnalyses &PA,
> +    FunctionAnalysisManager::Invalidator &Inv) {
> +  // If this proxy isn't marked as preserved, the set of Function objects
> in
> +  // the module may have changed. We therefore can't call
> +  // InnerAM->invalidate(), because any pointers to Functions it has may
> be
> +  // stale.
> +  if (!PA.preserved(LoopAnalysisManagerFunctionProxy::ID()))
> +    InnerAM->clear();
> +
> +  // FIXME: Proper suppor for invalidation isn't yet implemented for the
> LPM.
> +
> +  // Return false to indicate that this result is still a valid proxy.
> +  return false;
> +}
>  }
>
>  PreservedAnalyses llvm::getLoopPassPreservedAnalyses() {
>
> Modified: llvm/trunk/lib/IR/PassManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/
> PassManager.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/IR/PassManager.cpp (original)
> +++ llvm/trunk/lib/IR/PassManager.cpp Sat Dec 10 00:34:44 2016
> @@ -13,7 +13,8 @@
>
>  using namespace llvm;
>
> -// Explicit template instantiations for core template typedefs.
> +// Explicit template instantiations and specialization defininitions for
> core
> +// template typedefs.
>  namespace llvm {
>  template class AllAnalysesOn<Module>;
>  template class AllAnalysesOn<Function>;
> @@ -23,6 +24,31 @@ template class AnalysisManager<Module>;
>  template class AnalysisManager<Function>;
>  template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
> Module>;
>  template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
> Function>;
> +
> +template <>
> +bool FunctionAnalysisManagerModuleProxy::Result::invalidate(
> +    Module &M, const PreservedAnalyses &PA,
> +    ModuleAnalysisManager::Invalidator &Inv) {
> +  // If this proxy isn't marked as preserved, then even if the result
> remains
> +  // valid, the key itself may no longer be valid, so we clear everything.
> +  //
> +  // Note that in order to preserve this proxy, a module pass must ensure
> that
> +  // the FAM has been completely updated to handle the deletion of
> functions.
> +  // Specifically, any FAM-cached results for those functions need to
> have been
> +  // forcibly cleared. When preserved, this proxy will only invalidate
> results
> +  // cached on functions *still in the module* at the end of the module
> pass.
> +  if (!PA.preserved(FunctionAnalysisManagerModuleProxy::ID())) {
> +    InnerAM->clear();
> +    return true;
> +  }
> +
> +  // Otherwise propagate the invalidation event to all the remaining IR
> units.
> +  for (Function &F : M)
> +    InnerAM->invalidate(F, PA);
> +
> +  // Return false to indicate that this result is still a valid proxy.
> +  return false;
> +}
>  }
>
>  AnalysisKey PreservedAnalyses::AllAnalysesKey;
>
> Modified: llvm/trunk/lib/Passes/PassBuilder.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/
> PassBuilder.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Passes/PassBuilder.cpp (original)
> +++ llvm/trunk/lib/Passes/PassBuilder.cpp Sat Dec 10 00:34:44 2016
> @@ -769,7 +769,6 @@ void PassBuilder::crossRegisterProxies(L
>                                         ModuleAnalysisManager &MAM) {
>    MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM);
> });
>    MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM);
> });
> -  CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM);
> });
>    CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM);
> });
>    FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM);
> });
>    FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM);
> });
>
> Modified: llvm/trunk/lib/Passes/PassRegistry.def
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Passes/
> PassRegistry.def?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/lib/Passes/PassRegistry.def (original)
> +++ llvm/trunk/lib/Passes/PassRegistry.def Sat Dec 10 00:34:44 2016
> @@ -79,6 +79,7 @@ MODULE_PASS("verify", VerifierPass())
>  #define CGSCC_ANALYSIS(NAME, CREATE_PASS)
>  #endif
>  CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
> +CGSCC_ANALYSIS("fam-proxy", FunctionAnalysisManagerCGSCCProxy())
>  #undef CGSCC_ANALYSIS
>
>  #ifndef CGSCC_PASS
>
> Modified: llvm/trunk/test/Other/new-pass-manager.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/
> new-pass-manager.ll?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/test/Other/new-pass-manager.ll (original)
> +++ llvm/trunk/test/Other/new-pass-manager.ll Sat Dec 10 00:34:44 2016
> @@ -20,7 +20,8 @@
>  ; RUN:     | FileCheck %s --check-prefix=CHECK-CGSCC-PASS
>  ; CHECK-CGSCC-PASS: Starting llvm::Module pass manager run
>  ; CHECK-CGSCC-PASS-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor
> -; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*
> }}>
> +; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*
> }}CGSCCAnalysisManager{{.*}}>
> +; CHECK-CGSCC-PASS-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*
> }}FunctionAnalysisManager{{.*}}>
>  ; CHECK-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis
>  ; CHECK-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC: [(foo)]
>  ; CHECK-CGSCC-PASS-NEXT: Starting CGSCC pass manager run
> @@ -378,7 +379,8 @@
>  ; RUN:     | FileCheck %s --check-prefix=CHECK-REPEAT-CGSCC-PASS
>  ; CHECK-REPEAT-CGSCC-PASS: Starting llvm::Module pass manager run
>  ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running pass:
> ModuleToPostOrderCGSCCPassAdaptor
> -; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis:
> InnerAnalysisManagerProxy<{{.*}}>
> +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis:
> InnerAnalysisManagerProxy<{{.*}}CGSCCAnalysisManager{{.*}}>
> +; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis:
> InnerAnalysisManagerProxy<{{.*}}FunctionAnalysisManager{{.*}}>
>  ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running analysis: LazyCallGraphAnalysis
>  ; CHECK-REPEAT-CGSCC-PASS-NEXT: Running an SCC pass across the RefSCC:
> [(foo)]
>  ; CHECK-REPEAT-CGSCC-PASS-NEXT: Starting CGSCC pass manager run
>
> Modified: llvm/trunk/unittests/Analysis/CGSCCPassManagerTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/
> Analysis/CGSCCPassManagerTest.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/unittests/Analysis/CGSCCPassManagerTest.cpp (original)
> +++ llvm/trunk/unittests/Analysis/CGSCCPassManagerTest.cpp Sat Dec 10
> 00:34:44 2016
> @@ -122,15 +122,19 @@ private:
>
>  AnalysisKey TestImmutableFunctionAnalysis::Key;
>
> +struct LambdaModulePass : public PassInfoMixin<LambdaModulePass> {
> +  template <typename T>
> +  LambdaModulePass(T &&Arg) : Func(std::forward<T>(Arg)) {}
> +
> +  PreservedAnalyses run(Module &F, ModuleAnalysisManager &AM) {
> +    return Func(F, AM);
> +  }
> +
> +  std::function<PreservedAnalyses(Module &, ModuleAnalysisManager &)>
> Func;
> +};
> +
>  struct LambdaSCCPass : public PassInfoMixin<LambdaSCCPass> {
>    template <typename T> LambdaSCCPass(T &&Arg) :
> Func(std::forward<T>(Arg)) {}
> -  // We have to explicitly define all the special member functions
> because MSVC
> -  // refuses to generate them.
> -  LambdaSCCPass(LambdaSCCPass &&Arg) : Func(std::move(Arg.Func)) {}
> -  LambdaSCCPass &operator=(LambdaSCCPass &&RHS) {
> -    Func = std::move(RHS.Func);
> -    return *this;
> -  }
>
>    PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM,
>                          LazyCallGraph &CG, CGSCCUpdateResult &UR) {
> @@ -143,14 +147,8 @@ struct LambdaSCCPass : public PassInfoMi
>  };
>
>  struct LambdaFunctionPass : public PassInfoMixin<LambdaFunctionPass> {
> -  template <typename T> LambdaFunctionPass(T &&Arg) :
> Func(std::forward<T>(Arg)) {}
> -  // We have to explicitly define all the special member functions
> because MSVC
> -  // refuses to generate them.
> -  LambdaFunctionPass(LambdaFunctionPass &&Arg) :
> Func(std::move(Arg.Func)) {}
> -  LambdaFunctionPass &operator=(LambdaFunctionPass &&RHS) {
> -    Func = std::move(RHS.Func);
> -    return *this;
> -  }
> +  template <typename T>
> +  LambdaFunctionPass(T &&Arg) : Func(std::forward<T>(Arg)) {}
>
>    PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) {
>      return Func(F, AM);
> @@ -232,7 +230,7 @@ public:
>      MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
>      MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM);
> });
>      MAM.registerPass([&] { return CGSCCAnalysisManagerModuleProxy(CGAM);
> });
> -    CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy(FAM);
> });
> +    CGAM.registerPass([&] { return FunctionAnalysisManagerCGSCCProxy();
> });
>      CGAM.registerPass([&] { return ModuleAnalysisManagerCGSCCProxy(MAM);
> });
>      FAM.registerPass([&] { return CGSCCAnalysisManagerFunctionProxy(CGAM);
> });
>      FAM.registerPass([&] { return ModuleAnalysisManagerFunctionProxy(MAM);
> });
> @@ -257,6 +255,14 @@ TEST_F(CGSCCPassManagerTest, Basic) {
>    MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
>
>    CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  int FunctionPassRunCount1 = 0;
> +  FPM1.addPass(LambdaFunctionPass([&](Function &,
> FunctionAnalysisManager &) {
> +    ++FunctionPassRunCount1;
> +    return PreservedAnalyses::none();
> +  }));
> +  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +
>    int SCCPassRunCount1 = 0;
>    int AnalyzedInstrCount1 = 0;
>    int AnalyzedSCCFunctionCount1 = 0;
> @@ -289,23 +295,36 @@ TEST_F(CGSCCPassManagerTest, Basic) {
>          return PreservedAnalyses::all();
>        }));
>
> -  FunctionPassManager FPM1(/*DebugLogging*/ true);
> -  int FunctionPassRunCount1 = 0;
> -  FPM1.addPass(LambdaFunctionPass([&](Function &,
> FunctionAnalysisManager &) {
> -    ++FunctionPassRunCount1;
> -    return PreservedAnalyses::all();
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  int FunctionPassRunCount2 = 0;
> +  FPM2.addPass(LambdaFunctionPass([&](Function &,
> FunctionAnalysisManager &) {
> +    ++FunctionPassRunCount2;
> +    return PreservedAnalyses::none();
>    }));
> -  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +
>    MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
>
> +  FunctionPassManager FPM3(/*DebugLogging*/ true);
> +  int FunctionPassRunCount3 = 0;
> +  FPM3.addPass(LambdaFunctionPass([&](Function &,
> FunctionAnalysisManager &) {
> +    ++FunctionPassRunCount3;
> +    return PreservedAnalyses::none();
> +  }));
> +  MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM3)));
> +
>    MPM.run(*M, MAM);
>
> +  EXPECT_EQ(4, SCCPassRunCount1);
> +  EXPECT_EQ(6, FunctionPassRunCount1);
> +  EXPECT_EQ(6, FunctionPassRunCount2);
> +  EXPECT_EQ(6, FunctionPassRunCount3);
> +
>    EXPECT_EQ(1, ModuleAnalysisRuns);
>    EXPECT_EQ(4, SCCAnalysisRuns);
>    EXPECT_EQ(6, FunctionAnalysisRuns);
>    EXPECT_EQ(6, ImmutableFunctionAnalysisRuns);
>
> -  EXPECT_EQ(4, SCCPassRunCount1);
>    EXPECT_EQ(14, AnalyzedInstrCount1);
>    EXPECT_EQ(6, AnalyzedSCCFunctionCount1);
>    EXPECT_EQ(4 * 6, AnalyzedModuleFunctionCount1);
> @@ -473,4 +492,332 @@ TEST_F(CGSCCPassManagerTest, TestFunctio
>    EXPECT_FALSE(FoundModuleAnalysis3);
>  }
>
> +// Test that a Module pass which fails to preserve an SCC analysis in fact
> +// invalidates that analysis.
> +TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysis) {
> +  int SCCAnalysisRuns = 0;
> +  CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves the LazyCallGraph and the proxy
> but
> +  // not the SCC analysis.
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    PA.preserve<CGSCCAnalysisManagerModuleProxy>();
> +    PA.preserve<FunctionAnalysisManagerModuleProxy>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> This
> +  // will trigger re-running it.
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // Two runs and four SCCs.
> +  EXPECT_EQ(2 * 4, SCCAnalysisRuns);
> +}
> +
> +// Check that marking the SCC analysis preserved is sufficient to avoid
> +// invaliadtion. This should only run the analysis once for each SCC.
> +TEST_F(CGSCCPassManagerTest, TestModulePassCanPreserveSCCAnalysis) {
> +  int SCCAnalysisRuns = 0;
> +  CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves each of the necessary components
> +  // (but not everything).
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    PA.preserve<CGSCCAnalysisManagerModuleProxy>();
> +    PA.preserve<FunctionAnalysisManagerModuleProxy>();
> +    PA.preserve<TestSCCAnalysis>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again but
> find
> +  // it in the cache.
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // Four SCCs
> +  EXPECT_EQ(4, SCCAnalysisRuns);
> +}
> +
> +// Check that even when the analysis is preserved, if the SCC information
> isn't
> +// we still nuke things because the SCC keys could change.
> +TEST_F(CGSCCPassManagerTest, TestModulePassInvalidatesSCCAnalysisOnCGChange)
> {
> +  int SCCAnalysisRuns = 0;
> +  CGAM.registerPass([&] { return TestSCCAnalysis(SCCAnalysisRuns); });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves the analysis but not the call
> +  // graph or proxy.
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<TestSCCAnalysis>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(RequireAnalysisPass<TestSCCAnalysis, LazyCallGraph::SCC,
> +                                    CGSCCAnalysisManager, LazyCallGraph &,
> +                                    CGSCCUpdateResult &>());
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // Two runs and four SCCs.
> +  EXPECT_EQ(2 * 4, SCCAnalysisRuns);
> +}
> +
> +// Test that an SCC pass which fails to preserve a Function analysis in
> fact
> +// invalidates that analysis.
> +TEST_F(CGSCCPassManagerTest, TestSCCPassInvalidatesFunctionAnalysis) {
> +  int FunctionAnalysisRuns = 0;
> +  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
> +
> +  // Create a very simple module with a single function and SCC to make
> testing
> +  // these issues much easier.
> +  std::unique_ptr<Module> M = parseIR("declare void @g()\n"
> +                                      "declare void @h()\n"
> +                                      "define void @f() {\n"
> +                                      "entry:\n"
> +                                      "  call void @g()\n"
> +                                      "  call void @h()\n"
> +                                      "  ret void\n"
> +                                      "}\n");
> +
> +  CGSCCPassManager CGPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +
> +  // Now run a module pass that preserves the LazyCallGraph and proxy but
> not
> +  // the SCC analysis.
> +  CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C,
> CGSCCAnalysisManager &,
> +                                 LazyCallGraph &, CGSCCUpdateResult &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> This
> +  // will trigger re-running it.
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
> +  MPM.run(*M, MAM);
> +  EXPECT_EQ(2, FunctionAnalysisRuns);
> +}
> +
> +// Check that marking the SCC analysis preserved is sufficient. This
> should
> +// only run the analysis once the SCC.
> +TEST_F(CGSCCPassManagerTest, TestSCCPassCanPreserveFunctionAnalysis) {
> +  int FunctionAnalysisRuns = 0;
> +  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
> +
> +  // Create a very simple module with a single function and SCC to make
> testing
> +  // these issues much easier.
> +  std::unique_ptr<Module> M = parseIR("declare void @g()\n"
> +                                      "declare void @h()\n"
> +                                      "define void @f() {\n"
> +                                      "entry:\n"
> +                                      "  call void @g()\n"
> +                                      "  call void @h()\n"
> +                                      "  ret void\n"
> +                                      "}\n");
> +
> +  CGSCCPassManager CGPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +
> +  // Now run a module pass that preserves each of the necessary components
> +  // (but
> +  // not everything).
> +  CGPM.addPass(LambdaSCCPass([&](LazyCallGraph::SCC &C,
> CGSCCAnalysisManager &,
> +                                 LazyCallGraph &, CGSCCUpdateResult &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    PA.preserve<TestFunctionAnalysis>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again but
> find
> +  // it in the cache.
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
> +  MPM.run(*M, MAM);
> +  EXPECT_EQ(1, FunctionAnalysisRuns);
> +}
> +
> +// Note that there is no test for invalidating the call graph or other
> +// structure with an SCC pass because there is no mechanism to do that
> from
> +// withinsuch a pass. Instead, such a pass has to directly update the call
> +// graph structure.
> +
> +// Test that a madule pass invalidates function analyses when the CGSCC
> proxies
> +// and pass manager.
> +TEST_F(CGSCCPassManagerTest,
> +       TestModulePassInvalidatesFunctionAnalysisNestedInCGSCC) {
> +  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
> +
> +  int FunctionAnalysisRuns = 0;
> +  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves the LazyCallGraph and proxy but
> not
> +  // the Function analysis.
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    PA.preserve<CGSCCAnalysisManagerModuleProxy>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> This
> +  // will trigger re-running it.
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // Two runs and 6 functions.
> +  EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
> +}
> +
> +// Check that by marking the function pass and FAM proxy as preserved,
> this
> +// propagates all the way through.
> +TEST_F(CGSCCPassManagerTest,
> +       TestModulePassCanPreserveFunctionAnalysisNestedInCGSCC) {
> +  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
> +
> +  int FunctionAnalysisRuns = 0;
> +  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves the LazyCallGraph, the proxy,
> and
> +  // the Function analysis.
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    PA.preserve<LazyCallGraphAnalysis>();
> +    PA.preserve<CGSCCAnalysisManagerModuleProxy>();
> +    PA.preserve<FunctionAnalysisManagerModuleProxy>();
> +    PA.preserve<TestFunctionAnalysis>();
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> This
> +  // will trigger re-running it.
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // One run and 6 functions.
> +  EXPECT_EQ(6, FunctionAnalysisRuns);
> +}
> +
> +// Check that if the lazy call graph itself isn't preserved we still
> manage to
> +// invalidate everything.
> +TEST_F(CGSCCPassManagerTest,
> +       TestModulePassInvalidatesFunctionAnalysisNestedInCGSCCOnCGChange)
> {
> +  MAM.registerPass([&] { return LazyCallGraphAnalysis(); });
> +
> +  int FunctionAnalysisRuns = 0;
> +  FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
> +
> +  ModulePassManager MPM(/*DebugLogging*/ true);
> +
> +  // First force the analysis to be run.
> +  FunctionPassManager FPM1(/*DebugLogging*/ true);
> +  FPM1.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM1(/*DebugLogging*/ true);
> +  CGPM1.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM1)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM1)));
> +
> +  // Now run a module pass that preserves the LazyCallGraph but not the
> +  // Function analysis.
> +  MPM.addPass(LambdaModulePass([&](Module &M, ModuleAnalysisManager &) {
> +    PreservedAnalyses PA;
> +    return PA;
> +  }));
> +
> +  // And now a second CGSCC run which requires the SCC analysis again.
> This
> +  // will trigger re-running it.
> +  FunctionPassManager FPM2(/*DebugLogging*/ true);
> +  FPM2.addPass(RequireAnalysisPass<TestFunctionAnalysis, Function>());
> +  CGSCCPassManager CGPM2(/*DebugLogging*/ true);
> +  CGPM2.addPass(createCGSCCToFunctionPassAdaptor(std::move(FPM2)));
> +  MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM2)));
> +
> +  MPM.run(*M, MAM);
> +  // Two runs and 6 functions.
> +  EXPECT_EQ(2 * 6, FunctionAnalysisRuns);
> +}
>  }
>
> Modified: llvm/trunk/unittests/IR/PassManagerTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/
> IR/PassManagerTest.cpp?rev=289317&r1=289316&r2=289317&view=diff
> ============================================================
> ==================
> --- llvm/trunk/unittests/IR/PassManagerTest.cpp (original)
> +++ llvm/trunk/unittests/IR/PassManagerTest.cpp Sat Dec 10 00:34:44 2016
> @@ -91,19 +91,6 @@ struct TestPreservingModulePass : PassIn
>    }
>  };
>
> -struct TestMinPreservingModulePass
> -    : PassInfoMixin<TestMinPreservingModulePass> {
> -  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
> -    PreservedAnalyses PA;
> -
> -    // Force running an analysis.
> -    (void)AM.getResult<TestModuleAnalysis>(M);
> -
> -    PA.preserve<FunctionAnalysisManagerModuleProxy>();
> -    return PA;
> -  }
> -};
> -
>  struct TestFunctionPass : PassInfoMixin<TestFunctionPass> {
>    TestFunctionPass(int &RunCount, int &AnalyzedInstrCount,
>                     int &AnalyzedFunctionCount,
> @@ -215,11 +202,11 @@ TEST_F(PassManagerTest, BasicPreservedAn
>  }
>
>  TEST_F(PassManagerTest, Basic) {
> -  FunctionAnalysisManager FAM;
> +  FunctionAnalysisManager FAM(/*DebugLogging*/ true);
>    int FunctionAnalysisRuns = 0;
>    FAM.registerPass([&] { return TestFunctionAnalysis(FunctionAnalysisRuns);
> });
>
> -  ModuleAnalysisManager MAM;
> +  ModuleAnalysisManager MAM(/*DebugLogging*/ true);
>    int ModuleAnalysisRuns = 0;
>    MAM.registerPass([&] { return TestModuleAnalysis(ModuleAnalysisRuns);
> });
>    MAM.registerPass([&] { return FunctionAnalysisManagerModuleProxy(FAM);
> });
> @@ -233,11 +220,11 @@ TEST_F(PassManagerTest, Basic) {
>    int AnalyzedFunctionCount1 = 0;
>    {
>      // Pointless scoped copy to test move assignment.
> -    ModulePassManager NestedMPM;
> +    ModulePassManager NestedMPM(/*DebugLogging*/ true);
>      FunctionPassManager FPM;
>      {
>        // Pointless scope to test move assignment.
> -      FunctionPassManager NestedFPM;
> +      FunctionPassManager NestedFPM(/*DebugLogging*/ true);
>        NestedFPM.addPass(TestFunctionPass(
>            FunctionPassRunCount1, AnalyzedInstrCount1,
> AnalyzedFunctionCount1));
>        FPM = std::move(NestedFPM);
> @@ -255,7 +242,7 @@ TEST_F(PassManagerTest, Basic) {
>    int AnalyzedInstrCount2 = 0;
>    int AnalyzedFunctionCount2 = 0;
>    {
> -    FunctionPassManager FPM;
> +    FunctionPassManager FPM(/*DebugLogging*/ true);
>      FPM.addPass(TestFunctionPass(FunctionPassRunCount2,
> AnalyzedInstrCount2,
>                                   AnalyzedFunctionCount2));
>      MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
> @@ -268,15 +255,16 @@ TEST_F(PassManagerTest, Basic) {
>    int AnalyzedInstrCount3 = 0;
>    int AnalyzedFunctionCount3 = 0;
>    {
> -    FunctionPassManager FPM;
> +    FunctionPassManager FPM(/*DebugLogging*/ true);
>      FPM.addPass(TestFunctionPass(FunctionPassRunCount3,
> AnalyzedInstrCount3,
>                                   AnalyzedFunctionCount3));
>      FPM.addPass(TestInvalidationFunctionPass("f"));
>      MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
>    }
>
> -  // A fourth function pass manager but with a minimal intervening passes.
> -  MPM.addPass(TestMinPreservingModulePass());
> +  // A fourth function pass manager but with only preserving intervening
> +  // passes but triggering the module analysis.
> +  MPM.addPass(RequireAnalysisPass<TestModuleAnalysis, Module>());
>    int FunctionPassRunCount4 = 0;
>    int AnalyzedInstrCount4 = 0;
>    int AnalyzedFunctionCount4 = 0;
> @@ -287,12 +275,13 @@ TEST_F(PassManagerTest, Basic) {
>      MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
>    }
>
> -  // A fifth function pass manager but which uses only cached results.
> +  // A fifth function pass manager which invalidates one function first
> but
> +  // uses only cached results.
>    int FunctionPassRunCount5 = 0;
>    int AnalyzedInstrCount5 = 0;
>    int AnalyzedFunctionCount5 = 0;
>    {
> -    FunctionPassManager FPM;
> +    FunctionPassManager FPM(/*DebugLogging*/ true);
>      FPM.addPass(TestInvalidationFunctionPass("f"));
>      FPM.addPass(TestFunctionPass(FunctionPassRunCount5,
> AnalyzedInstrCount5,
>                                   AnalyzedFunctionCount5,
> @@ -317,16 +306,17 @@ TEST_F(PassManagerTest, Basic) {
>    EXPECT_EQ(0, AnalyzedFunctionCount3);
>    EXPECT_EQ(3, FunctionPassRunCount4);
>    EXPECT_EQ(5, AnalyzedInstrCount4);
> -  EXPECT_EQ(0, AnalyzedFunctionCount4);
> +  EXPECT_EQ(9, AnalyzedFunctionCount4);
>    EXPECT_EQ(3, FunctionPassRunCount5);
>    EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached.
> -  EXPECT_EQ(0, AnalyzedFunctionCount5);
> +  EXPECT_EQ(9, 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
> +  //   fifth run invalidates 1 function first, but runs over 0 functions
>    EXPECT_EQ(7, FunctionAnalysisRuns);
>
>    EXPECT_EQ(1, ModuleAnalysisRuns);
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20161220/982a39f2/attachment.html>


More information about the llvm-commits mailing list