| //===- CGSCCPassManager.h - Call graph pass management ----------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// \file |
| /// |
| /// This header provides classes for managing passes over SCCs of the call |
| /// graph. These passes form an important component of LLVM's interprocedural |
| /// optimizations. Because they operate on the SCCs of the call graph, and they |
| /// wtraverse the graph in post order, they can effectively do pair-wise |
| /// interprocedural optimizations for all call edges in the program. At each |
| /// call site edge, the callee has already been optimized as much as is |
| /// possible. This in turn allows very accurate analysis of it for IPO. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ANALYSIS_CGSCC_PASS_MANAGER_H |
| #define LLVM_ANALYSIS_CGSCC_PASS_MANAGER_H |
| |
| #include "llvm/IR/PassManager.h" |
| #include "llvm/Analysis/LazyCallGraph.h" |
| |
| namespace llvm { |
| |
| class CGSCCAnalysisManager; |
| |
| class CGSCCPassManager { |
| public: |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| CGSCCPassManager() {} |
| CGSCCPassManager(CGSCCPassManager &&Arg) : Passes(std::move(Arg.Passes)) {} |
| CGSCCPassManager &operator=(CGSCCPassManager &&RHS) { |
| Passes = std::move(RHS.Passes); |
| return *this; |
| } |
| |
| /// \brief Run all of the CGSCC passes in this pass manager over a SCC. |
| PreservedAnalyses run(LazyCallGraph::SCC *C, |
| CGSCCAnalysisManager *AM = nullptr); |
| |
| template <typename CGSCCPassT> void addPass(CGSCCPassT Pass) { |
| Passes.emplace_back(new CGSCCPassModel<CGSCCPassT>(std::move(Pass))); |
| } |
| |
| static StringRef name() { return "CGSCCPassManager"; } |
| |
| private: |
| // Pull in the concept type and model template specialized for SCCs. |
| typedef detail::PassConcept<LazyCallGraph::SCC *, CGSCCAnalysisManager> |
| CGSCCPassConcept; |
| template <typename PassT> |
| struct CGSCCPassModel |
| : detail::PassModel<LazyCallGraph::SCC *, CGSCCAnalysisManager, PassT> { |
| CGSCCPassModel(PassT Pass) |
| : detail::PassModel<LazyCallGraph::SCC *, CGSCCAnalysisManager, PassT>( |
| std::move(Pass)) {} |
| }; |
| |
| CGSCCPassManager(const CGSCCPassManager &) LLVM_DELETED_FUNCTION; |
| CGSCCPassManager &operator=(const CGSCCPassManager &) LLVM_DELETED_FUNCTION; |
| |
| std::vector<std::unique_ptr<CGSCCPassConcept>> Passes; |
| }; |
| |
| /// \brief A function analysis manager to coordinate and cache analyses run over |
| /// a module. |
| class CGSCCAnalysisManager : public detail::AnalysisManagerBase< |
| CGSCCAnalysisManager, LazyCallGraph::SCC *> { |
| friend class detail::AnalysisManagerBase<CGSCCAnalysisManager, |
| LazyCallGraph::SCC *>; |
| typedef detail::AnalysisManagerBase<CGSCCAnalysisManager, |
| LazyCallGraph::SCC *> BaseT; |
| typedef BaseT::ResultConceptT ResultConceptT; |
| typedef BaseT::PassConceptT PassConceptT; |
| |
| public: |
| // Most public APIs are inherited from the CRTP base class. |
| |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| CGSCCAnalysisManager() {} |
| CGSCCAnalysisManager(CGSCCAnalysisManager &&Arg) |
| : BaseT(std::move(static_cast<BaseT &>(Arg))), |
| CGSCCAnalysisResults(std::move(Arg.CGSCCAnalysisResults)) {} |
| CGSCCAnalysisManager &operator=(CGSCCAnalysisManager &&RHS) { |
| BaseT::operator=(std::move(static_cast<BaseT &>(RHS))); |
| CGSCCAnalysisResults = std::move(RHS.CGSCCAnalysisResults); |
| return *this; |
| } |
| |
| /// \brief Returns true if the analysis manager has an empty results cache. |
| bool empty() const; |
| |
| /// \brief Clear the function analysis result cache. |
| /// |
| /// This routine allows cleaning up when the set of functions itself has |
| /// potentially changed, and thus we can't even look up a a result and |
| /// invalidate it directly. Notably, this does *not* call invalidate |
| /// functions as there is nothing to be done for them. |
| void clear(); |
| |
| private: |
| CGSCCAnalysisManager(const CGSCCAnalysisManager &) LLVM_DELETED_FUNCTION; |
| CGSCCAnalysisManager & |
| operator=(const CGSCCAnalysisManager &) LLVM_DELETED_FUNCTION; |
| |
| /// \brief Get a function pass result, running the pass if necessary. |
| ResultConceptT &getResultImpl(void *PassID, LazyCallGraph::SCC *C); |
| |
| /// \brief Get a cached function pass result or return null. |
| ResultConceptT *getCachedResultImpl(void *PassID, |
| LazyCallGraph::SCC *C) const; |
| |
| /// \brief Invalidate a function pass result. |
| void invalidateImpl(void *PassID, LazyCallGraph::SCC *C); |
| |
| /// \brief Invalidate the results for a function.. |
| void invalidateImpl(LazyCallGraph::SCC *C, const PreservedAnalyses &PA); |
| |
| /// \brief List of function analysis pass IDs and associated concept pointers. |
| /// |
| /// Requires iterators to be valid across appending new entries and arbitrary |
| /// erases. Provides both the pass ID and concept pointer such that it is |
| /// half of a bijection and provides storage for the actual result concept. |
| typedef std::list< |
| std::pair<void *, std::unique_ptr<detail::AnalysisResultConcept< |
| LazyCallGraph::SCC *>>>> CGSCCAnalysisResultListT; |
| |
| /// \brief Map type from function pointer to our custom list type. |
| typedef DenseMap<LazyCallGraph::SCC *, CGSCCAnalysisResultListT> |
| CGSCCAnalysisResultListMapT; |
| |
| /// \brief Map from function to a list of function analysis results. |
| /// |
| /// Provides linear time removal of all analysis results for a function and |
| /// the ultimate storage for a particular cached analysis result. |
| CGSCCAnalysisResultListMapT CGSCCAnalysisResultLists; |
| |
| /// \brief Map type from a pair of analysis ID and function pointer to an |
| /// iterator into a particular result list. |
| typedef DenseMap<std::pair<void *, LazyCallGraph::SCC *>, |
| CGSCCAnalysisResultListT::iterator> CGSCCAnalysisResultMapT; |
| |
| /// \brief Map from an analysis ID and function to a particular cached |
| /// analysis result. |
| CGSCCAnalysisResultMapT CGSCCAnalysisResults; |
| }; |
| |
| /// \brief A module analysis which acts as a proxy for a CGSCC analysis |
| /// manager. |
| /// |
| /// This primarily proxies invalidation information from the module analysis |
| /// manager and module pass manager to a CGSCC analysis manager. You should |
| /// never use a CGSCC analysis manager from within (transitively) a module |
| /// pass manager unless your parent module pass has received a proxy result |
| /// object for it. |
| class CGSCCAnalysisManagerModuleProxy { |
| public: |
| class Result { |
| public: |
| explicit Result(CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {} |
| // We have to explicitly define all the special member functions because |
| // MSVC refuses to generate them. |
| Result(const Result &Arg) : CGAM(Arg.CGAM) {} |
| Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {} |
| Result &operator=(Result RHS) { |
| std::swap(CGAM, RHS.CGAM); |
| return *this; |
| } |
| ~Result(); |
| |
| /// \brief Accessor for the \c CGSCCAnalysisManager. |
| CGSCCAnalysisManager &getManager() { return *CGAM; } |
| |
| /// \brief Handler for invalidation of the module. |
| /// |
| /// If this analysis itself is preserved, then we assume that the call |
| /// graph of the module hasn't changed and thus we don't need to invalidate |
| /// *all* cached data associated with a \c SCC* in the \c |
| /// 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); |
| |
| private: |
| CGSCCAnalysisManager *CGAM; |
| }; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| explicit CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManager &CGAM) |
| : CGAM(&CGAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| CGSCCAnalysisManagerModuleProxy( |
| const CGSCCAnalysisManagerModuleProxy &Arg) |
| : CGAM(Arg.CGAM) {} |
| CGSCCAnalysisManagerModuleProxy(CGSCCAnalysisManagerModuleProxy &&Arg) |
| : CGAM(std::move(Arg.CGAM)) {} |
| CGSCCAnalysisManagerModuleProxy & |
| operator=(CGSCCAnalysisManagerModuleProxy RHS) { |
| std::swap(CGAM, RHS.CGAM); |
| return *this; |
| } |
| |
| /// \brief Run the analysis pass and create our proxy result object. |
| /// |
| /// This doesn't do any interesting work, it is primarily used to insert our |
| /// proxy result object into the module analysis cache so that we can proxy |
| /// invalidation to the CGSCC analysis manager. |
| /// |
| /// In debug builds, it will also assert that the analysis manager is empty |
| /// as no queries should arrive at the CGSCC analysis manager prior to |
| /// this analysis being requested. |
| Result run(Module *M); |
| |
| private: |
| static char PassID; |
| |
| CGSCCAnalysisManager *CGAM; |
| }; |
| |
| /// \brief A CGSCC analysis which acts as a proxy for a module analysis |
| /// manager. |
| /// |
| /// This primarily provides an accessor to a parent module analysis manager to |
| /// CGSCC passes. Only the const interface of the module analysis manager is |
| /// provided to indicate that once inside of a CGSCC analysis pass you |
| /// cannot request a module analysis to actually run. Instead, the user must |
| /// rely on the \c getCachedResult API. |
| /// |
| /// This proxy *doesn't* manage the invalidation in any way. That is handled by |
| /// the recursive return path of each layer of the pass manager and the |
| /// returned PreservedAnalysis set. |
| class ModuleAnalysisManagerCGSCCProxy { |
| public: |
| /// \brief Result proxy object for \c ModuleAnalysisManagerCGSCCProxy. |
| class Result { |
| public: |
| explicit Result(const ModuleAnalysisManager &MAM) : MAM(&MAM) {} |
| // We have to explicitly define all the special member functions because |
| // MSVC refuses to generate them. |
| Result(const Result &Arg) : MAM(Arg.MAM) {} |
| Result(Result &&Arg) : MAM(std::move(Arg.MAM)) {} |
| Result &operator=(Result RHS) { |
| std::swap(MAM, RHS.MAM); |
| return *this; |
| } |
| |
| const ModuleAnalysisManager &getManager() const { return *MAM; } |
| |
| /// \brief Handle invalidation by ignoring it, this pass is immutable. |
| bool invalidate(LazyCallGraph::SCC *) { return false; } |
| |
| private: |
| const ModuleAnalysisManager *MAM; |
| }; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| ModuleAnalysisManagerCGSCCProxy(const ModuleAnalysisManager &MAM) |
| : MAM(&MAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModuleAnalysisManagerCGSCCProxy( |
| const ModuleAnalysisManagerCGSCCProxy &Arg) |
| : MAM(Arg.MAM) {} |
| ModuleAnalysisManagerCGSCCProxy(ModuleAnalysisManagerCGSCCProxy &&Arg) |
| : MAM(std::move(Arg.MAM)) {} |
| ModuleAnalysisManagerCGSCCProxy & |
| operator=(ModuleAnalysisManagerCGSCCProxy RHS) { |
| std::swap(MAM, RHS.MAM); |
| return *this; |
| } |
| |
| /// \brief Run the analysis pass and create our proxy result object. |
| /// Nothing to see here, it just forwards the \c MAM reference into the |
| /// result. |
| Result run(LazyCallGraph::SCC *) { return Result(*MAM); } |
| |
| private: |
| static char PassID; |
| |
| const ModuleAnalysisManager *MAM; |
| }; |
| |
| /// \brief The core module pass which does a post-order walk of the SCCs and |
| /// runs a CGSCC pass over each one. |
| /// |
| /// Designed to allow composition of a CGSCCPass(Manager) and |
| /// a ModulePassManager. Note that this pass must be run with a module analysis |
| /// manager as it uses the LazyCallGraph analysis. It will also run the |
| /// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC |
| /// pass over the module to enable a \c FunctionAnalysisManager to be used |
| /// within this run safely. |
| template <typename CGSCCPassT> class ModuleToPostOrderCGSCCPassAdaptor { |
| public: |
| explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) |
| : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModuleToPostOrderCGSCCPassAdaptor( |
| const ModuleToPostOrderCGSCCPassAdaptor &Arg) |
| : Pass(Arg.Pass) {} |
| ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg) |
| : Pass(std::move(Arg.Pass)) {} |
| friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS, |
| ModuleToPostOrderCGSCCPassAdaptor &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| ModuleToPostOrderCGSCCPassAdaptor & |
| operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief Runs the CGSCC pass across every SCC in the module. |
| PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) { |
| assert(AM && "We need analyses to compute the call graph!"); |
| |
| // Setup the CGSCC analysis manager from its proxy. |
| CGSCCAnalysisManager &CGAM = |
| AM->getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager(); |
| |
| // Get the call graph for this module. |
| LazyCallGraph &CG = AM->getResult<LazyCallGraphAnalysis>(M); |
| |
| PreservedAnalyses PA = PreservedAnalyses::all(); |
| for (LazyCallGraph::SCC &C : CG.postorder_sccs()) { |
| PreservedAnalyses PassPA = Pass.run(&C, &CGAM); |
| |
| // We know that the CGSCC pass couldn't have invalidated any other |
| // SCC's analyses (that's the contract of a CGSCC pass), so |
| // directly handle the CGSCC analysis manager's invalidation here. |
| // FIXME: This isn't quite correct. We need to handle the case where the |
| // pass updated the CG, particularly some child of the current SCC, and |
| // invalidate its analyses. |
| CGAM.invalidate(&C, PassPA); |
| |
| // Then intersect the preserved set so that invalidation of module |
| // analyses will eventually occur when the module pass completes. |
| PA.intersect(std::move(PassPA)); |
| } |
| |
| // By definition we preserve the proxy. 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. |
| PA.preserve<CGSCCAnalysisManagerModuleProxy>(); |
| return PA; |
| } |
| |
| static StringRef name() { return "ModuleToPostOrderCGSCCPassAdaptor"; } |
| |
| private: |
| CGSCCPassT Pass; |
| }; |
| |
| /// \brief A function to deduce a function pass type and wrap it in the |
| /// templated adaptor. |
| template <typename CGSCCPassT> |
| ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT> |
| createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { |
| return std::move( |
| ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass))); |
| } |
| |
| /// \brief A CGSCC analysis which acts as a proxy for a function analysis |
| /// manager. |
| /// |
| /// This primarily proxies invalidation information from the CGSCC analysis |
| /// manager and CGSCC pass manager to a function analysis manager. You should |
| /// never use a function analysis manager from within (transitively) a CGSCC |
| /// pass manager unless your parent CGSCC pass has received a proxy result |
| /// object for it. |
| class FunctionAnalysisManagerCGSCCProxy { |
| public: |
| class Result { |
| public: |
| explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} |
| // We have to explicitly define all the special member functions because |
| // MSVC refuses to generate them. |
| Result(const Result &Arg) : FAM(Arg.FAM) {} |
| Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {} |
| Result &operator=(Result RHS) { |
| std::swap(FAM, RHS.FAM); |
| return *this; |
| } |
| ~Result(); |
| |
| /// \brief Accessor for the \c FunctionAnalysisManager. |
| FunctionAnalysisManager &getManager() { return *FAM; } |
| |
| /// \brief Handler for invalidation of the SCC. |
| /// |
| /// If this analysis itself is preserved, then we assume that the set of \c |
| /// Function objects in the \c SCC hasn't changed and thus we don't need |
| /// to invalidate *all* cached data associated with a \c Function* in the \c |
| /// FunctionAnalysisManager. |
| /// |
| /// Regardless of whether this analysis is marked as preserved, all of the |
| /// analyses in the \c FunctionAnalysisManager are potentially invalidated |
| /// based on the set of preserved analyses. |
| bool invalidate(LazyCallGraph::SCC *C, const PreservedAnalyses &PA); |
| |
| private: |
| FunctionAnalysisManager *FAM; |
| }; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| explicit FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManager &FAM) |
| : FAM(&FAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| FunctionAnalysisManagerCGSCCProxy( |
| const FunctionAnalysisManagerCGSCCProxy &Arg) |
| : FAM(Arg.FAM) {} |
| FunctionAnalysisManagerCGSCCProxy(FunctionAnalysisManagerCGSCCProxy &&Arg) |
| : FAM(std::move(Arg.FAM)) {} |
| FunctionAnalysisManagerCGSCCProxy & |
| operator=(FunctionAnalysisManagerCGSCCProxy RHS) { |
| std::swap(FAM, RHS.FAM); |
| return *this; |
| } |
| |
| /// \brief Run the analysis pass and create our proxy result object. |
| /// |
| /// This doesn't do any interesting work, it is primarily used to insert our |
| /// proxy result object into the module analysis cache so that we can proxy |
| /// invalidation to the function analysis manager. |
| /// |
| /// 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(LazyCallGraph::SCC *C); |
| |
| private: |
| static char PassID; |
| |
| FunctionAnalysisManager *FAM; |
| }; |
| |
| /// \brief A function analysis which acts as a proxy for a CGSCC analysis |
| /// manager. |
| /// |
| /// This primarily provides an accessor to a parent CGSCC analysis manager to |
| /// function passes. Only the const interface of the CGSCC analysis manager is |
| /// provided to indicate that once inside of a function analysis pass you |
| /// cannot request a CGSCC analysis to actually run. Instead, the user must |
| /// rely on the \c getCachedResult API. |
| /// |
| /// This proxy *doesn't* manage the invalidation in any way. That is handled by |
| /// the recursive return path of each layer of the pass manager and the |
| /// returned PreservedAnalysis set. |
| class CGSCCAnalysisManagerFunctionProxy { |
| public: |
| /// \brief Result proxy object for \c ModuleAnalysisManagerFunctionProxy. |
| class Result { |
| public: |
| explicit Result(const CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {} |
| // We have to explicitly define all the special member functions because |
| // MSVC refuses to generate them. |
| Result(const Result &Arg) : CGAM(Arg.CGAM) {} |
| Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {} |
| Result &operator=(Result RHS) { |
| std::swap(CGAM, RHS.CGAM); |
| return *this; |
| } |
| |
| const CGSCCAnalysisManager &getManager() const { return *CGAM; } |
| |
| /// \brief Handle invalidation by ignoring it, this pass is immutable. |
| bool invalidate(Function *) { return false; } |
| |
| private: |
| const CGSCCAnalysisManager *CGAM; |
| }; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| CGSCCAnalysisManagerFunctionProxy(const CGSCCAnalysisManager &CGAM) |
| : CGAM(&CGAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| CGSCCAnalysisManagerFunctionProxy( |
| const CGSCCAnalysisManagerFunctionProxy &Arg) |
| : CGAM(Arg.CGAM) {} |
| CGSCCAnalysisManagerFunctionProxy(CGSCCAnalysisManagerFunctionProxy &&Arg) |
| : CGAM(std::move(Arg.CGAM)) {} |
| CGSCCAnalysisManagerFunctionProxy & |
| operator=(CGSCCAnalysisManagerFunctionProxy RHS) { |
| std::swap(CGAM, RHS.CGAM); |
| return *this; |
| } |
| |
| /// \brief Run the analysis pass and create our proxy result object. |
| /// Nothing to see here, it just forwards the \c CGAM reference into the |
| /// result. |
| Result run(Function *) { return Result(*CGAM); } |
| |
| private: |
| static char PassID; |
| |
| const CGSCCAnalysisManager *CGAM; |
| }; |
| |
| /// \brief Adaptor that maps from a SCC to its functions. |
| /// |
| /// Designed to allow composition of a FunctionPass(Manager) and |
| /// a CGSCCPassManager. Note that if this pass is constructed with a pointer |
| /// to a \c CGSCCAnalysisManager it will run the |
| /// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function |
| /// pass over the SCC to enable a \c FunctionAnalysisManager to be used |
| /// within this run safely. |
| template <typename FunctionPassT> class CGSCCToFunctionPassAdaptor { |
| public: |
| explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass) |
| : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg) |
| : Pass(Arg.Pass) {} |
| CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg) |
| : Pass(std::move(Arg.Pass)) {} |
| friend void swap(CGSCCToFunctionPassAdaptor &LHS, CGSCCToFunctionPassAdaptor &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief Runs the function pass across every function in the module. |
| PreservedAnalyses run(LazyCallGraph::SCC *C, CGSCCAnalysisManager *AM) { |
| FunctionAnalysisManager *FAM = nullptr; |
| if (AM) |
| // Setup the function analysis manager from its proxy. |
| FAM = &AM->getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager(); |
| |
| PreservedAnalyses PA = PreservedAnalyses::all(); |
| for (LazyCallGraph::Node *N : *C) { |
| PreservedAnalyses PassPA = Pass.run(&N->getFunction(), FAM); |
| |
| // We know that the function pass couldn't have invalidated any other |
| // function's analyses (that's the contract of a function pass), so |
| // directly handle the function analysis manager's invalidation here. |
| if (FAM) |
| FAM->invalidate(&N->getFunction(), PassPA); |
| |
| // Then intersect the preserved set so that invalidation of module |
| // analyses will eventually occur when the module pass completes. |
| PA.intersect(std::move(PassPA)); |
| } |
| |
| // By definition we preserve the proxy. This precludes *any* invalidation |
| // of function analyses by the proxy, but that's OK because we've taken |
| // care to invalidate analyses in the function analysis manager |
| // incrementally above. |
| // FIXME: We need to update the call graph here to account for any deleted |
| // edges! |
| PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); |
| return PA; |
| } |
| |
| static StringRef name() { return "CGSCCToFunctionPassAdaptor"; } |
| |
| private: |
| FunctionPassT Pass; |
| }; |
| |
| /// \brief A function to deduce a function pass type and wrap it in the |
| /// templated adaptor. |
| template <typename FunctionPassT> |
| CGSCCToFunctionPassAdaptor<FunctionPassT> |
| createCGSCCToFunctionPassAdaptor(FunctionPassT Pass) { |
| return std::move(CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass))); |
| } |
| |
| } |
| |
| #endif |