[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