| //===- PassManager.h - Pass management infrastructure -----------*- 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 defines various interfaces for pass management in LLVM. There |
| /// is no "pass" interface in LLVM per se. Instead, an instance of any class |
| /// which supports a method to 'run' it over a unit of IR can be used as |
| /// a pass. A pass manager is generally a tool to collect a sequence of passes |
| /// which run over a particular IR construct, and run each of them in sequence |
| /// over each such construct in the containing IR construct. As there is no |
| /// containing IR construct for a Module, a manager for passes over modules |
| /// forms the base case which runs its managed passes in sequence over the |
| /// single module provided. |
| /// |
| /// The core IR library provides managers for running passes over |
| /// modules and functions. |
| /// |
| /// * FunctionPassManager can run over a Module, runs each pass over |
| /// a Function. |
| /// * ModulePassManager must be directly run, runs each pass over the Module. |
| /// |
| /// Note that the implementations of the pass managers use concept-based |
| /// polymorphism as outlined in the "Value Semantics and Concept-based |
| /// Polymorphism" talk (or its abbreviated sibling "Inheritance Is The Base |
| /// Class of Evil") by Sean Parent: |
| /// * http://github.com/sean-parent/sean-parent.github.com/wiki/Papers-and-Presentations |
| /// * http://www.youtube.com/watch?v=_BpMYeUFXv8 |
| /// * http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_IR_PASS_MANAGER_H |
| #define LLVM_IR_PASS_MANAGER_H |
| |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallPtrSet.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/type_traits.h" |
| #include <list> |
| #include <memory> |
| #include <vector> |
| |
| namespace llvm { |
| |
| class Module; |
| class Function; |
| |
| /// \brief An abstract set of preserved analyses following a transformation pass |
| /// run. |
| /// |
| /// When a transformation pass is run, it can return a set of analyses whose |
| /// results were preserved by that transformation. The default set is "none", |
| /// and preserving analyses must be done explicitly. |
| /// |
| /// There is also an explicit all state which can be used (for example) when |
| /// the IR is not mutated at all. |
| class PreservedAnalyses { |
| public: |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| PreservedAnalyses() {} |
| PreservedAnalyses(const PreservedAnalyses &Arg) |
| : PreservedPassIDs(Arg.PreservedPassIDs) {} |
| PreservedAnalyses(PreservedAnalyses &&Arg) |
| : PreservedPassIDs(std::move(Arg.PreservedPassIDs)) {} |
| friend void swap(PreservedAnalyses &LHS, PreservedAnalyses &RHS) { |
| using std::swap; |
| swap(LHS.PreservedPassIDs, RHS.PreservedPassIDs); |
| } |
| PreservedAnalyses &operator=(PreservedAnalyses RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief Convenience factory function for the empty preserved set. |
| static PreservedAnalyses none() { return PreservedAnalyses(); } |
| |
| /// \brief Construct a special preserved set that preserves all passes. |
| static PreservedAnalyses all() { |
| PreservedAnalyses PA; |
| PA.PreservedPassIDs.insert((void *)AllPassesID); |
| return PA; |
| } |
| |
| /// \brief Mark a particular pass as preserved, adding it to the set. |
| template <typename PassT> void preserve() { |
| if (!areAllPreserved()) |
| PreservedPassIDs.insert(PassT::ID()); |
| } |
| |
| /// \brief Intersect this set with another in place. |
| /// |
| /// This is a mutating operation on this preserved set, removing all |
| /// preserved passes which are not also preserved in the argument. |
| void intersect(const PreservedAnalyses &Arg) { |
| if (Arg.areAllPreserved()) |
| return; |
| if (areAllPreserved()) { |
| PreservedPassIDs = Arg.PreservedPassIDs; |
| return; |
| } |
| for (SmallPtrSet<void *, 2>::const_iterator I = PreservedPassIDs.begin(), |
| E = PreservedPassIDs.end(); |
| I != E; ++I) |
| if (!Arg.PreservedPassIDs.count(*I)) |
| PreservedPassIDs.erase(*I); |
| } |
| |
| /// \brief Intersect this set with a temporary other set in place. |
| /// |
| /// This is a mutating operation on this preserved set, removing all |
| /// preserved passes which are not also preserved in the argument. |
| void intersect(PreservedAnalyses &&Arg) { |
| if (Arg.areAllPreserved()) |
| return; |
| if (areAllPreserved()) { |
| PreservedPassIDs = std::move(Arg.PreservedPassIDs); |
| return; |
| } |
| for (SmallPtrSet<void *, 2>::const_iterator I = PreservedPassIDs.begin(), |
| E = PreservedPassIDs.end(); |
| I != E; ++I) |
| if (!Arg.PreservedPassIDs.count(*I)) |
| PreservedPassIDs.erase(*I); |
| } |
| |
| /// \brief Query whether a pass is marked as preserved by this set. |
| template <typename PassT> bool preserved() const { |
| return preserved(PassT::ID()); |
| } |
| |
| /// \brief Query whether an abstract pass ID is marked as preserved by this |
| /// set. |
| bool preserved(void *PassID) const { |
| return PreservedPassIDs.count((void *)AllPassesID) || |
| PreservedPassIDs.count(PassID); |
| } |
| |
| private: |
| // Note that this must not be -1 or -2 as those are already used by the |
| // SmallPtrSet. |
| static const uintptr_t AllPassesID = (intptr_t)(-3); |
| |
| bool areAllPreserved() const { |
| return PreservedPassIDs.count((void *)AllPassesID); |
| } |
| |
| SmallPtrSet<void *, 2> PreservedPassIDs; |
| }; |
| |
| /// \brief Implementation details of the pass manager interfaces. |
| namespace detail { |
| |
| /// \brief Template for the abstract base class used to dispatch |
| /// polymorphically over pass objects. |
| template <typename IRUnitT, typename AnalysisManagerT> struct PassConcept { |
| // Boiler plate necessary for the container of derived classes. |
| virtual ~PassConcept() {} |
| |
| /// \brief The polymorphic API which runs the pass over a given IR entity. |
| /// |
| /// Note that actual pass object can omit the analysis manager argument if |
| /// desired. Also that the analysis manager may be null if there is no |
| /// analysis manager in the pass pipeline. |
| virtual PreservedAnalyses run(IRUnitT IR, AnalysisManagerT *AM) = 0; |
| |
| /// \brief Polymorphic method to access the name of a pass. |
| virtual StringRef name() = 0; |
| }; |
| |
| /// \brief SFINAE metafunction for computing whether \c PassT has a run method |
| /// accepting an \c AnalysisManagerT. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT, |
| typename ResultT> |
| class PassRunAcceptsAnalysisManager { |
| typedef char SmallType; |
| struct BigType { |
| char a, b; |
| }; |
| |
| template <typename T, ResultT (T::*)(IRUnitT, AnalysisManagerT *)> |
| struct Checker; |
| |
| template <typename T> static SmallType f(Checker<T, &T::run> *); |
| template <typename T> static BigType f(...); |
| |
| public: |
| enum { Value = sizeof(f<PassT>(nullptr)) == sizeof(SmallType) }; |
| }; |
| |
| /// \brief A template wrapper used to implement the polymorphic API. |
| /// |
| /// Can be instantiated for any object which provides a \c run method accepting |
| /// an \c IRUnitT. It requires the pass to be a copyable object. When the |
| /// \c run method also accepts an \c AnalysisManagerT*, we pass it along. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT, |
| bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager< |
| IRUnitT, AnalysisManagerT, PassT, PreservedAnalyses>::Value> |
| struct PassModel; |
| |
| /// \brief Specialization of \c PassModel for passes that accept an analyis |
| /// manager. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT> |
| struct PassModel<IRUnitT, AnalysisManagerT, PassT, true> |
| : PassConcept<IRUnitT, AnalysisManagerT> { |
| explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} |
| PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} |
| friend void swap(PassModel &LHS, PassModel &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| PassModel &operator=(PassModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| PreservedAnalyses run(IRUnitT IR, AnalysisManagerT *AM) override { |
| return Pass.run(IR, AM); |
| } |
| StringRef name() override { return PassT::name(); } |
| PassT Pass; |
| }; |
| |
| /// \brief Specialization of \c PassModel for passes that accept an analyis |
| /// manager. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT> |
| struct PassModel<IRUnitT, AnalysisManagerT, PassT, false> |
| : PassConcept<IRUnitT, AnalysisManagerT> { |
| explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| PassModel(const PassModel &Arg) : Pass(Arg.Pass) {} |
| PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {} |
| friend void swap(PassModel &LHS, PassModel &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| PassModel &operator=(PassModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| PreservedAnalyses run(IRUnitT IR, AnalysisManagerT *AM) override { |
| return Pass.run(IR); |
| } |
| StringRef name() override { return PassT::name(); } |
| PassT Pass; |
| }; |
| |
| /// \brief Abstract concept of an analysis result. |
| /// |
| /// This concept is parameterized over the IR unit that this result pertains |
| /// to. |
| template <typename IRUnitT> struct AnalysisResultConcept { |
| virtual ~AnalysisResultConcept() {} |
| |
| /// \brief Method to try and mark a result as invalid. |
| /// |
| /// When the outer analysis manager detects a change in some underlying |
| /// unit of the IR, it will call this method on all of the results cached. |
| /// |
| /// This method also receives a set of preserved analyses which can be used |
| /// to avoid invalidation because the pass which changed the underlying IR |
| /// took care to update or preserve the analysis result in some way. |
| /// |
| /// \returns true if the result is indeed invalid (the default). |
| virtual bool invalidate(IRUnitT IR, const PreservedAnalyses &PA) = 0; |
| }; |
| |
| /// \brief SFINAE metafunction for computing whether \c ResultT provides an |
| /// \c invalidate member function. |
| template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod { |
| typedef char SmallType; |
| struct BigType { |
| char a, b; |
| }; |
| |
| template <typename T, bool (T::*)(IRUnitT, const PreservedAnalyses &)> |
| struct Checker; |
| |
| template <typename T> static SmallType f(Checker<T, &T::invalidate> *); |
| template <typename T> static BigType f(...); |
| |
| public: |
| enum { Value = sizeof(f<ResultT>(nullptr)) == sizeof(SmallType) }; |
| }; |
| |
| /// \brief Wrapper to model the analysis result concept. |
| /// |
| /// By default, this will implement the invalidate method with a trivial |
| /// implementation so that the actual analysis result doesn't need to provide |
| /// an invalidation handler. It is only selected when the invalidation handler |
| /// is not part of the ResultT's interface. |
| template <typename IRUnitT, typename PassT, typename ResultT, |
| bool HasInvalidateHandler = |
| ResultHasInvalidateMethod<IRUnitT, ResultT>::Value> |
| struct AnalysisResultModel; |
| |
| /// \brief Specialization of \c AnalysisResultModel which provides the default |
| /// invalidate functionality. |
| template <typename IRUnitT, typename PassT, typename ResultT> |
| struct AnalysisResultModel<IRUnitT, PassT, ResultT, false> |
| : AnalysisResultConcept<IRUnitT> { |
| explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} |
| AnalysisResultModel(AnalysisResultModel &&Arg) |
| : Result(std::move(Arg.Result)) {} |
| friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { |
| using std::swap; |
| swap(LHS.Result, RHS.Result); |
| } |
| AnalysisResultModel &operator=(AnalysisResultModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief The model bases invalidation solely on being in the preserved set. |
| // |
| // FIXME: We should actually use two different concepts for analysis results |
| // rather than two different models, and avoid the indirect function call for |
| // ones that use the trivial behavior. |
| bool invalidate(IRUnitT, const PreservedAnalyses &PA) override { |
| return !PA.preserved(PassT::ID()); |
| } |
| |
| ResultT Result; |
| }; |
| |
| /// \brief Specialization of \c AnalysisResultModel which delegates invalidate |
| /// handling to \c ResultT. |
| template <typename IRUnitT, typename PassT, typename ResultT> |
| struct AnalysisResultModel<IRUnitT, PassT, ResultT, true> |
| : AnalysisResultConcept<IRUnitT> { |
| explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {} |
| AnalysisResultModel(AnalysisResultModel &&Arg) |
| : Result(std::move(Arg.Result)) {} |
| friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) { |
| using std::swap; |
| swap(LHS.Result, RHS.Result); |
| } |
| AnalysisResultModel &operator=(AnalysisResultModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief The model delegates to the \c ResultT method. |
| bool invalidate(IRUnitT IR, const PreservedAnalyses &PA) override { |
| return Result.invalidate(IR, PA); |
| } |
| |
| ResultT Result; |
| }; |
| |
| /// \brief Abstract concept of an analysis pass. |
| /// |
| /// This concept is parameterized over the IR unit that it can run over and |
| /// produce an analysis result. |
| template <typename IRUnitT, typename AnalysisManagerT> |
| struct AnalysisPassConcept { |
| virtual ~AnalysisPassConcept() {} |
| |
| /// \brief Method to run this analysis over a unit of IR. |
| /// \returns A unique_ptr to the analysis result object to be queried by |
| /// users. |
| virtual std::unique_ptr<AnalysisResultConcept<IRUnitT>> |
| run(IRUnitT IR, AnalysisManagerT *AM) = 0; |
| }; |
| |
| /// \brief Wrapper to model the analysis pass concept. |
| /// |
| /// Can wrap any type which implements a suitable \c run method. The method |
| /// must accept the IRUnitT as an argument and produce an object which can be |
| /// wrapped in a \c AnalysisResultModel. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT, |
| bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager< |
| IRUnitT, AnalysisManagerT, PassT, typename PassT::Result>::Value> |
| struct AnalysisPassModel; |
| |
| /// \brief Specialization of \c AnalysisPassModel which passes an |
| /// \c AnalysisManager to PassT's run method. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT> |
| struct AnalysisPassModel<IRUnitT, AnalysisManagerT, PassT, true> |
| : AnalysisPassConcept<IRUnitT, AnalysisManagerT> { |
| explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} |
| AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} |
| friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| AnalysisPassModel &operator=(AnalysisPassModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| // FIXME: Replace PassT::Result with type traits when we use C++11. |
| typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result> |
| ResultModelT; |
| |
| /// \brief The model delegates to the \c PassT::run method. |
| /// |
| /// The return is wrapped in an \c AnalysisResultModel. |
| std::unique_ptr<AnalysisResultConcept<IRUnitT>> |
| run(IRUnitT IR, AnalysisManagerT *AM) override { |
| return make_unique<ResultModelT>(Pass.run(IR, AM)); |
| } |
| |
| PassT Pass; |
| }; |
| |
| /// \brief Specialization of \c AnalysisPassModel which does not pass an |
| /// \c AnalysisManager to PassT's run method. |
| template <typename IRUnitT, typename AnalysisManagerT, typename PassT> |
| struct AnalysisPassModel<IRUnitT, AnalysisManagerT, PassT, false> |
| : AnalysisPassConcept<IRUnitT, AnalysisManagerT> { |
| explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {} |
| AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {} |
| friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| AnalysisPassModel &operator=(AnalysisPassModel RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| // FIXME: Replace PassT::Result with type traits when we use C++11. |
| typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result> |
| ResultModelT; |
| |
| /// \brief The model delegates to the \c PassT::run method. |
| /// |
| /// The return is wrapped in an \c AnalysisResultModel. |
| std::unique_ptr<AnalysisResultConcept<IRUnitT>> |
| run(IRUnitT IR, AnalysisManagerT *) override { |
| return make_unique<ResultModelT>(Pass.run(IR)); |
| } |
| |
| PassT Pass; |
| }; |
| |
| } // End namespace detail |
| |
| class ModuleAnalysisManager; |
| |
| class ModulePassManager { |
| public: |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModulePassManager() {} |
| ModulePassManager(ModulePassManager &&Arg) : Passes(std::move(Arg.Passes)) {} |
| ModulePassManager &operator=(ModulePassManager &&RHS) { |
| Passes = std::move(RHS.Passes); |
| return *this; |
| } |
| |
| /// \brief Run all of the module passes in this module pass manager over |
| /// a module. |
| /// |
| /// This method should only be called for a single module as there is the |
| /// expectation that the lifetime of a pass is bounded to that of a module. |
| PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM = nullptr); |
| |
| template <typename ModulePassT> void addPass(ModulePassT Pass) { |
| Passes.emplace_back(new ModulePassModel<ModulePassT>(std::move(Pass))); |
| } |
| |
| static StringRef name() { return "ModulePassManager"; } |
| |
| private: |
| // Pull in the concept type and model template specialized for modules. |
| typedef detail::PassConcept<Module *, ModuleAnalysisManager> |
| ModulePassConcept; |
| template <typename PassT> |
| struct ModulePassModel |
| : detail::PassModel<Module *, ModuleAnalysisManager, PassT> { |
| ModulePassModel(PassT Pass) |
| : detail::PassModel<Module *, ModuleAnalysisManager, PassT>( |
| std::move(Pass)) {} |
| }; |
| |
| ModulePassManager(const ModulePassManager &) LLVM_DELETED_FUNCTION; |
| ModulePassManager &operator=(const ModulePassManager &) LLVM_DELETED_FUNCTION; |
| |
| std::vector<std::unique_ptr<ModulePassConcept>> Passes; |
| }; |
| |
| class FunctionAnalysisManager; |
| |
| class FunctionPassManager { |
| public: |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| FunctionPassManager() {} |
| FunctionPassManager(FunctionPassManager &&Arg) |
| : Passes(std::move(Arg.Passes)) {} |
| FunctionPassManager &operator=(FunctionPassManager &&RHS) { |
| Passes = std::move(RHS.Passes); |
| return *this; |
| } |
| |
| template <typename FunctionPassT> void addPass(FunctionPassT Pass) { |
| Passes.emplace_back(new FunctionPassModel<FunctionPassT>(std::move(Pass))); |
| } |
| |
| PreservedAnalyses run(Function *F, FunctionAnalysisManager *AM = nullptr); |
| |
| static StringRef name() { return "FunctionPassManager"; } |
| |
| private: |
| // Pull in the concept type and model template specialized for functions. |
| typedef detail::PassConcept<Function *, FunctionAnalysisManager> |
| FunctionPassConcept; |
| template <typename PassT> |
| struct FunctionPassModel |
| : detail::PassModel<Function *, FunctionAnalysisManager, PassT> { |
| FunctionPassModel(PassT Pass) |
| : detail::PassModel<Function *, FunctionAnalysisManager, PassT>( |
| std::move(Pass)) {} |
| }; |
| |
| FunctionPassManager(const FunctionPassManager &) LLVM_DELETED_FUNCTION; |
| FunctionPassManager & |
| operator=(const FunctionPassManager &) LLVM_DELETED_FUNCTION; |
| |
| std::vector<std::unique_ptr<FunctionPassConcept>> Passes; |
| }; |
| |
| namespace detail { |
| |
| /// \brief A CRTP base used to implement analysis managers. |
| /// |
| /// This class template serves as the boiler plate of an analysis manager. Any |
| /// analysis manager can be implemented on top of this base class. Any |
| /// implementation will be required to provide specific hooks: |
| /// |
| /// - getResultImpl |
| /// - getCachedResultImpl |
| /// - invalidateImpl |
| /// |
| /// The details of the call pattern are within. |
| template <typename DerivedT, typename IRUnitT> class AnalysisManagerBase { |
| DerivedT *derived_this() { return static_cast<DerivedT *>(this); } |
| const DerivedT *derived_this() const { |
| return static_cast<const DerivedT *>(this); |
| } |
| |
| AnalysisManagerBase(const AnalysisManagerBase &) LLVM_DELETED_FUNCTION; |
| AnalysisManagerBase & |
| operator=(const AnalysisManagerBase &) LLVM_DELETED_FUNCTION; |
| |
| protected: |
| typedef detail::AnalysisResultConcept<IRUnitT> ResultConceptT; |
| typedef detail::AnalysisPassConcept<IRUnitT, DerivedT> PassConceptT; |
| |
| // FIXME: Provide template aliases for the models when we're using C++11 in |
| // a mode supporting them. |
| |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| AnalysisManagerBase() {} |
| AnalysisManagerBase(AnalysisManagerBase &&Arg) |
| : AnalysisPasses(std::move(Arg.AnalysisPasses)) {} |
| AnalysisManagerBase &operator=(AnalysisManagerBase &&RHS) { |
| AnalysisPasses = std::move(RHS.AnalysisPasses); |
| return *this; |
| } |
| |
| public: |
| /// \brief Get the result of an analysis pass for this module. |
| /// |
| /// If there is not a valid cached result in the manager already, this will |
| /// re-run the analysis to produce a valid result. |
| template <typename PassT> typename PassT::Result &getResult(IRUnitT IR) { |
| assert(AnalysisPasses.count(PassT::ID()) && |
| "This analysis pass was not registered prior to being queried"); |
| |
| ResultConceptT &ResultConcept = |
| derived_this()->getResultImpl(PassT::ID(), IR); |
| typedef detail::AnalysisResultModel<IRUnitT, PassT, typename PassT::Result> |
| ResultModelT; |
| return static_cast<ResultModelT &>(ResultConcept).Result; |
| } |
| |
| /// \brief Get the cached result of an analysis pass for this module. |
| /// |
| /// This method never runs the analysis. |
| /// |
| /// \returns null if there is no cached result. |
| template <typename PassT> |
| typename PassT::Result *getCachedResult(IRUnitT IR) const { |
| assert(AnalysisPasses.count(PassT::ID()) && |
| "This analysis pass was not registered prior to being queried"); |
| |
| ResultConceptT *ResultConcept = |
| derived_this()->getCachedResultImpl(PassT::ID(), IR); |
| if (!ResultConcept) |
| return nullptr; |
| |
| typedef detail::AnalysisResultModel<IRUnitT, PassT, typename PassT::Result> |
| ResultModelT; |
| return &static_cast<ResultModelT *>(ResultConcept)->Result; |
| } |
| |
| /// \brief Register an analysis pass with the manager. |
| /// |
| /// This provides an initialized and set-up analysis pass to the analysis |
| /// manager. Whomever is setting up analysis passes must use this to populate |
| /// the manager with all of the analysis passes available. |
| template <typename PassT> void registerPass(PassT Pass) { |
| assert(!AnalysisPasses.count(PassT::ID()) && |
| "Registered the same analysis pass twice!"); |
| typedef detail::AnalysisPassModel<IRUnitT, DerivedT, PassT> PassModelT; |
| AnalysisPasses[PassT::ID()].reset(new PassModelT(std::move(Pass))); |
| } |
| |
| /// \brief Invalidate a specific analysis pass for an IR module. |
| /// |
| /// Note that the analysis result can disregard invalidation. |
| template <typename PassT> void invalidate(Module *M) { |
| assert(AnalysisPasses.count(PassT::ID()) && |
| "This analysis pass was not registered prior to being invalidated"); |
| derived_this()->invalidateImpl(PassT::ID(), M); |
| } |
| |
| /// \brief Invalidate analyses cached for an IR unit. |
| /// |
| /// Walk through all of the analyses pertaining to this unit of IR and |
| /// invalidate them unless they are preserved by the PreservedAnalyses set. |
| void invalidate(IRUnitT IR, const PreservedAnalyses &PA) { |
| derived_this()->invalidateImpl(IR, PA); |
| } |
| |
| protected: |
| /// \brief Lookup a registered analysis pass. |
| PassConceptT &lookupPass(void *PassID) { |
| typename AnalysisPassMapT::iterator PI = AnalysisPasses.find(PassID); |
| assert(PI != AnalysisPasses.end() && |
| "Analysis passes must be registered prior to being queried!"); |
| return *PI->second; |
| } |
| |
| /// \brief Lookup a registered analysis pass. |
| const PassConceptT &lookupPass(void *PassID) const { |
| typename AnalysisPassMapT::const_iterator PI = AnalysisPasses.find(PassID); |
| assert(PI != AnalysisPasses.end() && |
| "Analysis passes must be registered prior to being queried!"); |
| return *PI->second; |
| } |
| |
| private: |
| /// \brief Map type from module analysis pass ID to pass concept pointer. |
| typedef DenseMap<void *, std::unique_ptr<PassConceptT>> AnalysisPassMapT; |
| |
| /// \brief Collection of module analysis passes, indexed by ID. |
| AnalysisPassMapT AnalysisPasses; |
| }; |
| |
| } // End namespace detail |
| |
| /// \brief A module analysis pass manager with lazy running and caching of |
| /// results. |
| class ModuleAnalysisManager |
| : public detail::AnalysisManagerBase<ModuleAnalysisManager, Module *> { |
| friend class detail::AnalysisManagerBase<ModuleAnalysisManager, Module *>; |
| typedef detail::AnalysisManagerBase<ModuleAnalysisManager, Module *> BaseT; |
| typedef BaseT::ResultConceptT ResultConceptT; |
| typedef BaseT::PassConceptT PassConceptT; |
| |
| public: |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModuleAnalysisManager() {} |
| ModuleAnalysisManager(ModuleAnalysisManager &&Arg) |
| : BaseT(std::move(static_cast<BaseT &>(Arg))), |
| ModuleAnalysisResults(std::move(Arg.ModuleAnalysisResults)) {} |
| ModuleAnalysisManager &operator=(ModuleAnalysisManager &&RHS) { |
| BaseT::operator=(std::move(static_cast<BaseT &>(RHS))); |
| ModuleAnalysisResults = std::move(RHS.ModuleAnalysisResults); |
| return *this; |
| } |
| |
| private: |
| ModuleAnalysisManager(const ModuleAnalysisManager &) LLVM_DELETED_FUNCTION; |
| ModuleAnalysisManager & |
| operator=(const ModuleAnalysisManager &) LLVM_DELETED_FUNCTION; |
| |
| /// \brief Get a module pass result, running the pass if necessary. |
| ResultConceptT &getResultImpl(void *PassID, Module *M); |
| |
| /// \brief Get a cached module pass result or return null. |
| ResultConceptT *getCachedResultImpl(void *PassID, Module *M) const; |
| |
| /// \brief Invalidate a module pass result. |
| void invalidateImpl(void *PassID, Module *M); |
| |
| /// \brief Invalidate results across a module. |
| void invalidateImpl(Module *M, const PreservedAnalyses &PA); |
| |
| /// \brief Map type from module analysis pass ID to pass result concept |
| /// pointer. |
| typedef DenseMap<void *, |
| std::unique_ptr<detail::AnalysisResultConcept<Module *>>> |
| ModuleAnalysisResultMapT; |
| |
| /// \brief Cache of computed module analysis results for this module. |
| ModuleAnalysisResultMapT ModuleAnalysisResults; |
| }; |
| |
| /// \brief A function analysis manager to coordinate and cache analyses run over |
| /// a module. |
| class FunctionAnalysisManager |
| : public detail::AnalysisManagerBase<FunctionAnalysisManager, Function *> { |
| friend class detail::AnalysisManagerBase<FunctionAnalysisManager, Function *>; |
| typedef detail::AnalysisManagerBase<FunctionAnalysisManager, Function *> |
| 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. |
| FunctionAnalysisManager() {} |
| FunctionAnalysisManager(FunctionAnalysisManager &&Arg) |
| : BaseT(std::move(static_cast<BaseT &>(Arg))), |
| FunctionAnalysisResults(std::move(Arg.FunctionAnalysisResults)) {} |
| FunctionAnalysisManager &operator=(FunctionAnalysisManager &&RHS) { |
| BaseT::operator=(std::move(static_cast<BaseT &>(RHS))); |
| FunctionAnalysisResults = std::move(RHS.FunctionAnalysisResults); |
| 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: |
| FunctionAnalysisManager(const FunctionAnalysisManager &) |
| LLVM_DELETED_FUNCTION; |
| FunctionAnalysisManager & |
| operator=(const FunctionAnalysisManager &) LLVM_DELETED_FUNCTION; |
| |
| /// \brief Get a function pass result, running the pass if necessary. |
| ResultConceptT &getResultImpl(void *PassID, Function *F); |
| |
| /// \brief Get a cached function pass result or return null. |
| ResultConceptT *getCachedResultImpl(void *PassID, Function *F) const; |
| |
| /// \brief Invalidate a function pass result. |
| void invalidateImpl(void *PassID, Function *F); |
| |
| /// \brief Invalidate the results for a function.. |
| void invalidateImpl(Function *F, 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<Function *>>>> |
| FunctionAnalysisResultListT; |
| |
| /// \brief Map type from function pointer to our custom list type. |
| typedef DenseMap<Function *, FunctionAnalysisResultListT> |
| FunctionAnalysisResultListMapT; |
| |
| /// \brief Map from function to a list of function analysis results. |
| /// |
| /// Provides linear time removal of all analysis results for a function and |
| /// the ultimate storage for a particular cached analysis result. |
| FunctionAnalysisResultListMapT FunctionAnalysisResultLists; |
| |
| /// \brief Map type from a pair of analysis ID and function pointer to an |
| /// iterator into a particular result list. |
| typedef DenseMap<std::pair<void *, Function *>, |
| FunctionAnalysisResultListT::iterator> |
| FunctionAnalysisResultMapT; |
| |
| /// \brief Map from an analysis ID and function to a particular cached |
| /// analysis result. |
| FunctionAnalysisResultMapT FunctionAnalysisResults; |
| }; |
| |
| /// \brief A module analysis which acts as a proxy for a function analysis |
| /// manager. |
| /// |
| /// This primarily proxies invalidation information from the module analysis |
| /// manager and module pass manager to a function analysis manager. You should |
| /// never use a function analysis manager from within (transitively) a module |
| /// pass manager unless your parent module pass has received a proxy result |
| /// object for it. |
| class FunctionAnalysisManagerModuleProxy { |
| public: |
| class Result; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| explicit FunctionAnalysisManagerModuleProxy(FunctionAnalysisManager &FAM) |
| : FAM(&FAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| FunctionAnalysisManagerModuleProxy( |
| const FunctionAnalysisManagerModuleProxy &Arg) |
| : FAM(Arg.FAM) {} |
| FunctionAnalysisManagerModuleProxy(FunctionAnalysisManagerModuleProxy &&Arg) |
| : FAM(std::move(Arg.FAM)) {} |
| FunctionAnalysisManagerModuleProxy & |
| operator=(FunctionAnalysisManagerModuleProxy 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(Module *M); |
| |
| private: |
| static char PassID; |
| |
| FunctionAnalysisManager *FAM; |
| }; |
| |
| /// \brief The result proxy object for the |
| /// \c FunctionAnalysisManagerModuleProxy. |
| /// |
| /// See its documentation for more information. |
| class FunctionAnalysisManagerModuleProxy::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 module. |
| /// |
| /// If this analysis itself is preserved, then we assume that the set of \c |
| /// Function objects in the \c Module hasn't changed and thus we don't need |
| /// to invalidate *all* cached data associated with a \c Function* in the \c |
| /// FunctionAnalysisManager. |
| /// |
| /// Regardless of whether this analysis is marked as preserved, all of the |
| /// analyses in the \c FunctionAnalysisManager are potentially invalidated |
| /// based on the set of preserved analyses. |
| bool invalidate(Module *M, const PreservedAnalyses &PA); |
| |
| private: |
| FunctionAnalysisManager *FAM; |
| }; |
| |
| /// \brief A function analysis which acts as a proxy for a module analysis |
| /// manager. |
| /// |
| /// This primarily provides an accessor to a parent module analysis manager to |
| /// function passes. Only the const interface of the module analysis manager is |
| /// provided to indicate that once inside of a function 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 ModuleAnalysisManagerFunctionProxy { |
| public: |
| /// \brief Result proxy object for \c ModuleAnalysisManagerFunctionProxy. |
| 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(Function *) { return false; } |
| |
| private: |
| const ModuleAnalysisManager *MAM; |
| }; |
| |
| static void *ID() { return (void *)&PassID; } |
| |
| ModuleAnalysisManagerFunctionProxy(const ModuleAnalysisManager &MAM) |
| : MAM(&MAM) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModuleAnalysisManagerFunctionProxy( |
| const ModuleAnalysisManagerFunctionProxy &Arg) |
| : MAM(Arg.MAM) {} |
| ModuleAnalysisManagerFunctionProxy(ModuleAnalysisManagerFunctionProxy &&Arg) |
| : MAM(std::move(Arg.MAM)) {} |
| ModuleAnalysisManagerFunctionProxy & |
| operator=(ModuleAnalysisManagerFunctionProxy 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(Function *) { return Result(*MAM); } |
| |
| private: |
| static char PassID; |
| |
| const ModuleAnalysisManager *MAM; |
| }; |
| |
| /// \brief Trivial adaptor that maps from a module to its functions. |
| /// |
| /// Designed to allow composition of a FunctionPass(Manager) and |
| /// a ModulePassManager. Note that if this pass is constructed with a pointer |
| /// to a \c ModuleAnalysisManager it will run the |
| /// \c FunctionAnalysisManagerModuleProxy analysis prior to running the function |
| /// pass over the module to enable a \c FunctionAnalysisManager to be used |
| /// within this run safely. |
| template <typename FunctionPassT> class ModuleToFunctionPassAdaptor { |
| public: |
| explicit ModuleToFunctionPassAdaptor(FunctionPassT Pass) |
| : Pass(std::move(Pass)) {} |
| // We have to explicitly define all the special member functions because MSVC |
| // refuses to generate them. |
| ModuleToFunctionPassAdaptor(const ModuleToFunctionPassAdaptor &Arg) |
| : Pass(Arg.Pass) {} |
| ModuleToFunctionPassAdaptor(ModuleToFunctionPassAdaptor &&Arg) |
| : Pass(std::move(Arg.Pass)) {} |
| friend void swap(ModuleToFunctionPassAdaptor &LHS, ModuleToFunctionPassAdaptor &RHS) { |
| using std::swap; |
| swap(LHS.Pass, RHS.Pass); |
| } |
| ModuleToFunctionPassAdaptor &operator=(ModuleToFunctionPassAdaptor RHS) { |
| swap(*this, RHS); |
| return *this; |
| } |
| |
| /// \brief Runs the function pass across every function in the module. |
| PreservedAnalyses run(Module *M, ModuleAnalysisManager *AM) { |
| FunctionAnalysisManager *FAM = nullptr; |
| if (AM) |
| // Setup the function analysis manager from its proxy. |
| FAM = &AM->getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); |
| |
| PreservedAnalyses PA = PreservedAnalyses::all(); |
| for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) { |
| PreservedAnalyses PassPA = Pass.run(I, 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(I, 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. |
| PA.preserve<FunctionAnalysisManagerModuleProxy>(); |
| return PA; |
| } |
| |
| static StringRef name() { return "ModuleToFunctionPassAdaptor"; } |
| |
| private: |
| FunctionPassT Pass; |
| }; |
| |
| /// \brief A function to deduce a function pass type and wrap it in the |
| /// templated adaptor. |
| template <typename FunctionPassT> |
| ModuleToFunctionPassAdaptor<FunctionPassT> |
| createModuleToFunctionPassAdaptor(FunctionPassT Pass) { |
| return std::move(ModuleToFunctionPassAdaptor<FunctionPassT>(std::move(Pass))); |
| } |
| |
| } |
| |
| #endif |