Home | History | Annotate | Download | only in IR
      1 //===- PassManager internal APIs and implementation details -----*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 /// \file
     10 ///
     11 /// This header provides internal APIs and implementation details used by the
     12 /// pass management interfaces exposed in PassManager.h. To understand more
     13 /// context of why these particular interfaces are needed, see that header
     14 /// file. None of these APIs should be used elsewhere.
     15 ///
     16 //===----------------------------------------------------------------------===//
     17 
     18 #ifndef LLVM_IR_PASSMANAGERINTERNAL_H
     19 #define LLVM_IR_PASSMANAGERINTERNAL_H
     20 
     21 #include "llvm/ADT/STLExtras.h"
     22 #include "llvm/ADT/StringRef.h"
     23 #include <memory>
     24 #include <utility>
     25 
     26 namespace llvm {
     27 
     28 template <typename IRUnitT> class AllAnalysesOn;
     29 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
     30 class Invalidator;
     31 class PreservedAnalyses;
     32 
     33 /// \brief Implementation details of the pass manager interfaces.
     34 namespace detail {
     35 
     36 /// \brief Template for the abstract base class used to dispatch
     37 /// polymorphically over pass objects.
     38 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
     39 struct PassConcept {
     40   // Boiler plate necessary for the container of derived classes.
     41   virtual ~PassConcept() = default;
     42 
     43   /// \brief The polymorphic API which runs the pass over a given IR entity.
     44   ///
     45   /// Note that actual pass object can omit the analysis manager argument if
     46   /// desired. Also that the analysis manager may be null if there is no
     47   /// analysis manager in the pass pipeline.
     48   virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
     49                                 ExtraArgTs... ExtraArgs) = 0;
     50 
     51   /// \brief Polymorphic method to access the name of a pass.
     52   virtual StringRef name() = 0;
     53 };
     54 
     55 /// \brief A template wrapper used to implement the polymorphic API.
     56 ///
     57 /// Can be instantiated for any object which provides a \c run method accepting
     58 /// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to
     59 /// be a copyable object.
     60 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
     61           typename AnalysisManagerT, typename... ExtraArgTs>
     62 struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
     63   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
     64   // We have to explicitly define all the special member functions because MSVC
     65   // refuses to generate them.
     66   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
     67   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
     68 
     69   friend void swap(PassModel &LHS, PassModel &RHS) {
     70     using std::swap;
     71     swap(LHS.Pass, RHS.Pass);
     72   }
     73 
     74   PassModel &operator=(PassModel RHS) {
     75     swap(*this, RHS);
     76     return *this;
     77   }
     78 
     79   PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM,
     80                          ExtraArgTs... ExtraArgs) override {
     81     return Pass.run(IR, AM, ExtraArgs...);
     82   }
     83 
     84   StringRef name() override { return PassT::name(); }
     85 
     86   PassT Pass;
     87 };
     88 
     89 /// \brief Abstract concept of an analysis result.
     90 ///
     91 /// This concept is parameterized over the IR unit that this result pertains
     92 /// to.
     93 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT>
     94 struct AnalysisResultConcept {
     95   virtual ~AnalysisResultConcept() = default;
     96 
     97   /// \brief Method to try and mark a result as invalid.
     98   ///
     99   /// When the outer analysis manager detects a change in some underlying
    100   /// unit of the IR, it will call this method on all of the results cached.
    101   ///
    102   /// \p PA is a set of preserved analyses which can be used to avoid
    103   /// invalidation because the pass which changed the underlying IR took care
    104   /// to update or preserve the analysis result in some way.
    105   ///
    106   /// \p Inv is typically a \c AnalysisManager::Invalidator object that can be
    107   /// used by a particular analysis result to discover if other analyses
    108   /// results are also invalidated in the event that this result depends on
    109   /// them. See the documentation in the \c AnalysisManager for more details.
    110   ///
    111   /// \returns true if the result is indeed invalid (the default).
    112   virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA,
    113                           InvalidatorT &Inv) = 0;
    114 };
    115 
    116 /// \brief SFINAE metafunction for computing whether \c ResultT provides an
    117 /// \c invalidate member function.
    118 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
    119   typedef char EnabledType;
    120   struct DisabledType {
    121     char a, b;
    122   };
    123 
    124   // Purely to help out MSVC which fails to disable the below specialization,
    125   // explicitly enable using the result type's invalidate routine if we can
    126   // successfully call that routine.
    127   template <typename T> struct Nonce { typedef EnabledType Type; };
    128   template <typename T>
    129   static typename Nonce<decltype(std::declval<T>().invalidate(
    130       std::declval<IRUnitT &>(), std::declval<PreservedAnalyses>()))>::Type
    131       check(rank<2>);
    132 
    133   // First we define an overload that can only be taken if there is no
    134   // invalidate member. We do this by taking the address of an invalidate
    135   // member in an adjacent base class of a derived class. This would be
    136   // ambiguous if there were an invalidate member in the result type.
    137   template <typename T, typename U> static DisabledType NonceFunction(T U::*);
    138   struct CheckerBase { int invalidate; };
    139   template <typename T> struct Checker : CheckerBase, T {};
    140   template <typename T>
    141   static decltype(NonceFunction(&Checker<T>::invalidate)) check(rank<1>);
    142 
    143   // Now we have the fallback that will only be reached when there is an
    144   // invalidate member, and enables the trait.
    145   template <typename T>
    146   static EnabledType check(rank<0>);
    147 
    148 public:
    149   enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) };
    150 };
    151 
    152 /// \brief Wrapper to model the analysis result concept.
    153 ///
    154 /// By default, this will implement the invalidate method with a trivial
    155 /// implementation so that the actual analysis result doesn't need to provide
    156 /// an invalidation handler. It is only selected when the invalidation handler
    157 /// is not part of the ResultT's interface.
    158 template <typename IRUnitT, typename PassT, typename ResultT,
    159           typename PreservedAnalysesT, typename InvalidatorT,
    160           bool HasInvalidateHandler =
    161               ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
    162 struct AnalysisResultModel;
    163 
    164 /// \brief Specialization of \c AnalysisResultModel which provides the default
    165 /// invalidate functionality.
    166 template <typename IRUnitT, typename PassT, typename ResultT,
    167           typename PreservedAnalysesT, typename InvalidatorT>
    168 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT,
    169                            InvalidatorT, false>
    170     : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> {
    171   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
    172   // We have to explicitly define all the special member functions because MSVC
    173   // refuses to generate them.
    174   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
    175   AnalysisResultModel(AnalysisResultModel &&Arg)
    176       : Result(std::move(Arg.Result)) {}
    177 
    178   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
    179     using std::swap;
    180     swap(LHS.Result, RHS.Result);
    181   }
    182 
    183   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
    184     swap(*this, RHS);
    185     return *this;
    186   }
    187 
    188   /// \brief The model bases invalidation solely on being in the preserved set.
    189   //
    190   // FIXME: We should actually use two different concepts for analysis results
    191   // rather than two different models, and avoid the indirect function call for
    192   // ones that use the trivial behavior.
    193   bool invalidate(IRUnitT &, const PreservedAnalysesT &PA,
    194                   InvalidatorT &) override {
    195     auto PAC = PA.template getChecker<PassT>();
    196     return !PAC.preserved() &&
    197            !PAC.template preservedSet<AllAnalysesOn<IRUnitT>>();
    198   }
    199 
    200   ResultT Result;
    201 };
    202 
    203 /// \brief Specialization of \c AnalysisResultModel which delegates invalidate
    204 /// handling to \c ResultT.
    205 template <typename IRUnitT, typename PassT, typename ResultT,
    206           typename PreservedAnalysesT, typename InvalidatorT>
    207 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT,
    208                            InvalidatorT, true>
    209     : AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT> {
    210   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
    211   // We have to explicitly define all the special member functions because MSVC
    212   // refuses to generate them.
    213   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
    214   AnalysisResultModel(AnalysisResultModel &&Arg)
    215       : Result(std::move(Arg.Result)) {}
    216 
    217   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
    218     using std::swap;
    219     swap(LHS.Result, RHS.Result);
    220   }
    221 
    222   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
    223     swap(*this, RHS);
    224     return *this;
    225   }
    226 
    227   /// \brief The model delegates to the \c ResultT method.
    228   bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA,
    229                   InvalidatorT &Inv) override {
    230     return Result.invalidate(IR, PA, Inv);
    231   }
    232 
    233   ResultT Result;
    234 };
    235 
    236 /// \brief Abstract concept of an analysis pass.
    237 ///
    238 /// This concept is parameterized over the IR unit that it can run over and
    239 /// produce an analysis result.
    240 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT,
    241           typename... ExtraArgTs>
    242 struct AnalysisPassConcept {
    243   virtual ~AnalysisPassConcept() = default;
    244 
    245   /// \brief Method to run this analysis over a unit of IR.
    246   /// \returns A unique_ptr to the analysis result object to be queried by
    247   /// users.
    248   virtual std::unique_ptr<
    249       AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>>
    250   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
    251       ExtraArgTs... ExtraArgs) = 0;
    252 
    253   /// \brief Polymorphic method to access the name of a pass.
    254   virtual StringRef name() = 0;
    255 };
    256 
    257 /// \brief Wrapper to model the analysis pass concept.
    258 ///
    259 /// Can wrap any type which implements a suitable \c run method. The method
    260 /// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments
    261 /// and produce an object which can be wrapped in a \c AnalysisResultModel.
    262 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
    263           typename InvalidatorT, typename... ExtraArgTs>
    264 struct AnalysisPassModel : AnalysisPassConcept<IRUnitT, PreservedAnalysesT,
    265                                                InvalidatorT, ExtraArgTs...> {
    266   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
    267   // We have to explicitly define all the special member functions because MSVC
    268   // refuses to generate them.
    269   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
    270   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
    271 
    272   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
    273     using std::swap;
    274     swap(LHS.Pass, RHS.Pass);
    275   }
    276 
    277   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
    278     swap(*this, RHS);
    279     return *this;
    280   }
    281 
    282   // FIXME: Replace PassT::Result with type traits when we use C++11.
    283   typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result,
    284                               PreservedAnalysesT, InvalidatorT>
    285       ResultModelT;
    286 
    287   /// \brief The model delegates to the \c PassT::run method.
    288   ///
    289   /// The return is wrapped in an \c AnalysisResultModel.
    290   std::unique_ptr<
    291       AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>>
    292   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
    293       ExtraArgTs... ExtraArgs) override {
    294     return llvm::make_unique<ResultModelT>(Pass.run(IR, AM, ExtraArgs...));
    295   }
    296 
    297   /// \brief The model delegates to a static \c PassT::name method.
    298   ///
    299   /// The returned string ref must point to constant immutable data!
    300   StringRef name() override { return PassT::name(); }
    301 
    302   PassT Pass;
    303 };
    304 
    305 } // end namespace detail
    306 
    307 } // end namespace llvm
    308 
    309 #endif // LLVM_IR_PASSMANAGERINTERNAL_H
    310