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/StringRef.h"
     22 #include "llvm/ADT/STLExtras.h"
     23 
     24 namespace llvm {
     25 
     26 template <typename IRUnitT> class AnalysisManager;
     27 class PreservedAnalyses;
     28 
     29 /// \brief Implementation details of the pass manager interfaces.
     30 namespace detail {
     31 
     32 /// \brief Template for the abstract base class used to dispatch
     33 /// polymorphically over pass objects.
     34 template <typename IRUnitT> struct PassConcept {
     35   // Boiler plate necessary for the container of derived classes.
     36   virtual ~PassConcept() {}
     37 
     38   /// \brief The polymorphic API which runs the pass over a given IR entity.
     39   ///
     40   /// Note that actual pass object can omit the analysis manager argument if
     41   /// desired. Also that the analysis manager may be null if there is no
     42   /// analysis manager in the pass pipeline.
     43   virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0;
     44 
     45   /// \brief Polymorphic method to access the name of a pass.
     46   virtual StringRef name() = 0;
     47 };
     48 
     49 /// \brief SFINAE metafunction for computing whether \c PassT has a run method
     50 /// accepting an \c AnalysisManager<IRUnitT>.
     51 template <typename IRUnitT, typename PassT, typename ResultT>
     52 class PassRunAcceptsAnalysisManager {
     53   typedef char SmallType;
     54   struct BigType {
     55     char a, b;
     56   };
     57 
     58   template <typename T, ResultT (T::*)(IRUnitT &, AnalysisManager<IRUnitT> *)>
     59   struct Checker;
     60 
     61   template <typename T> static SmallType f(Checker<T, &T::run> *);
     62   template <typename T> static BigType f(...);
     63 
     64 public:
     65   enum { Value = sizeof(f<PassT>(nullptr)) == sizeof(SmallType) };
     66 };
     67 
     68 /// \brief A template wrapper used to implement the polymorphic API.
     69 ///
     70 /// Can be instantiated for any object which provides a \c run method accepting
     71 /// an \c IRUnitT. It requires the pass to be a copyable object. When the
     72 /// \c run method also accepts an \c AnalysisManager<IRUnitT>*, we pass it
     73 /// along.
     74 template <typename IRUnitT, typename PassT,
     75           typename PreservedAnalysesT = PreservedAnalyses,
     76           bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager<
     77               IRUnitT, PassT, PreservedAnalysesT>::Value>
     78 struct PassModel;
     79 
     80 /// \brief Specialization of \c PassModel for passes that accept an analyis
     81 /// manager.
     82 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT>
     83 struct PassModel<IRUnitT, PassT, PreservedAnalysesT, true>
     84     : PassConcept<IRUnitT> {
     85   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
     86   // We have to explicitly define all the special member functions because MSVC
     87   // refuses to generate them.
     88   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
     89   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
     90   friend void swap(PassModel &LHS, PassModel &RHS) {
     91     using std::swap;
     92     swap(LHS.Pass, RHS.Pass);
     93   }
     94   PassModel &operator=(PassModel RHS) {
     95     swap(*this, RHS);
     96     return *this;
     97   }
     98 
     99   PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
    100     return Pass.run(IR, AM);
    101   }
    102   StringRef name() override { return PassT::name(); }
    103   PassT Pass;
    104 };
    105 
    106 /// \brief Specialization of \c PassModel for passes that accept an analyis
    107 /// manager.
    108 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT>
    109 struct PassModel<IRUnitT, PassT, PreservedAnalysesT, false>
    110     : PassConcept<IRUnitT> {
    111   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
    112   // We have to explicitly define all the special member functions because MSVC
    113   // refuses to generate them.
    114   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
    115   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
    116   friend void swap(PassModel &LHS, PassModel &RHS) {
    117     using std::swap;
    118     swap(LHS.Pass, RHS.Pass);
    119   }
    120   PassModel &operator=(PassModel RHS) {
    121     swap(*this, RHS);
    122     return *this;
    123   }
    124 
    125   PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
    126     return Pass.run(IR);
    127   }
    128   StringRef name() override { return PassT::name(); }
    129   PassT Pass;
    130 };
    131 
    132 /// \brief Abstract concept of an analysis result.
    133 ///
    134 /// This concept is parameterized over the IR unit that this result pertains
    135 /// to.
    136 template <typename IRUnitT> struct AnalysisResultConcept {
    137   virtual ~AnalysisResultConcept() {}
    138 
    139   /// \brief Method to try and mark a result as invalid.
    140   ///
    141   /// When the outer analysis manager detects a change in some underlying
    142   /// unit of the IR, it will call this method on all of the results cached.
    143   ///
    144   /// This method also receives a set of preserved analyses which can be used
    145   /// to avoid invalidation because the pass which changed the underlying IR
    146   /// took care to update or preserve the analysis result in some way.
    147   ///
    148   /// \returns true if the result is indeed invalid (the default).
    149   virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA) = 0;
    150 };
    151 
    152 /// \brief SFINAE metafunction for computing whether \c ResultT provides an
    153 /// \c invalidate member function.
    154 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
    155   typedef char SmallType;
    156   struct BigType {
    157     char a, b;
    158   };
    159 
    160   template <typename T, bool (T::*)(IRUnitT &, const PreservedAnalyses &)>
    161   struct Checker;
    162 
    163   template <typename T> static SmallType f(Checker<T, &T::invalidate> *);
    164   template <typename T> static BigType f(...);
    165 
    166 public:
    167   enum { Value = sizeof(f<ResultT>(nullptr)) == sizeof(SmallType) };
    168 };
    169 
    170 /// \brief Wrapper to model the analysis result concept.
    171 ///
    172 /// By default, this will implement the invalidate method with a trivial
    173 /// implementation so that the actual analysis result doesn't need to provide
    174 /// an invalidation handler. It is only selected when the invalidation handler
    175 /// is not part of the ResultT's interface.
    176 template <typename IRUnitT, typename PassT, typename ResultT,
    177           typename PreservedAnalysesT = PreservedAnalyses,
    178           bool HasInvalidateHandler =
    179               ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
    180 struct AnalysisResultModel;
    181 
    182 /// \brief Specialization of \c AnalysisResultModel which provides the default
    183 /// invalidate functionality.
    184 template <typename IRUnitT, typename PassT, typename ResultT,
    185           typename PreservedAnalysesT>
    186 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, false>
    187     : AnalysisResultConcept<IRUnitT> {
    188   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
    189   // We have to explicitly define all the special member functions because MSVC
    190   // refuses to generate them.
    191   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
    192   AnalysisResultModel(AnalysisResultModel &&Arg)
    193       : Result(std::move(Arg.Result)) {}
    194   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
    195     using std::swap;
    196     swap(LHS.Result, RHS.Result);
    197   }
    198   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
    199     swap(*this, RHS);
    200     return *this;
    201   }
    202 
    203   /// \brief The model bases invalidation solely on being in the preserved set.
    204   //
    205   // FIXME: We should actually use two different concepts for analysis results
    206   // rather than two different models, and avoid the indirect function call for
    207   // ones that use the trivial behavior.
    208   bool invalidate(IRUnitT &, const PreservedAnalysesT &PA) override {
    209     return !PA.preserved(PassT::ID());
    210   }
    211 
    212   ResultT Result;
    213 };
    214 
    215 /// \brief Specialization of \c AnalysisResultModel which delegates invalidate
    216 /// handling to \c ResultT.
    217 template <typename IRUnitT, typename PassT, typename ResultT,
    218           typename PreservedAnalysesT>
    219 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, true>
    220     : AnalysisResultConcept<IRUnitT> {
    221   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
    222   // We have to explicitly define all the special member functions because MSVC
    223   // refuses to generate them.
    224   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
    225   AnalysisResultModel(AnalysisResultModel &&Arg)
    226       : Result(std::move(Arg.Result)) {}
    227   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
    228     using std::swap;
    229     swap(LHS.Result, RHS.Result);
    230   }
    231   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
    232     swap(*this, RHS);
    233     return *this;
    234   }
    235 
    236   /// \brief The model delegates to the \c ResultT method.
    237   bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA) override {
    238     return Result.invalidate(IR, PA);
    239   }
    240 
    241   ResultT Result;
    242 };
    243 
    244 /// \brief Abstract concept of an analysis pass.
    245 ///
    246 /// This concept is parameterized over the IR unit that it can run over and
    247 /// produce an analysis result.
    248 template <typename IRUnitT> struct AnalysisPassConcept {
    249   virtual ~AnalysisPassConcept() {}
    250 
    251   /// \brief Method to run this analysis over a unit of IR.
    252   /// \returns A unique_ptr to the analysis result object to be queried by
    253   /// users.
    254   virtual std::unique_ptr<AnalysisResultConcept<IRUnitT>>
    255   run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0;
    256 
    257   /// \brief Polymorphic method to access the name of a pass.
    258   virtual StringRef name() = 0;
    259 };
    260 
    261 /// \brief Wrapper to model the analysis pass concept.
    262 ///
    263 /// Can wrap any type which implements a suitable \c run method. The method
    264 /// must accept the IRUnitT as an argument and produce an object which can be
    265 /// wrapped in a \c AnalysisResultModel.
    266 template <typename IRUnitT, typename PassT,
    267           bool AcceptsAnalysisManager = PassRunAcceptsAnalysisManager<
    268               IRUnitT, PassT, typename PassT::Result>::Value>
    269 struct AnalysisPassModel;
    270 
    271 /// \brief Specialization of \c AnalysisPassModel which passes an
    272 /// \c AnalysisManager to PassT's run method.
    273 template <typename IRUnitT, typename PassT>
    274 struct AnalysisPassModel<IRUnitT, PassT, true> : AnalysisPassConcept<IRUnitT> {
    275   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
    276   // We have to explicitly define all the special member functions because MSVC
    277   // refuses to generate them.
    278   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
    279   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
    280   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
    281     using std::swap;
    282     swap(LHS.Pass, RHS.Pass);
    283   }
    284   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
    285     swap(*this, RHS);
    286     return *this;
    287   }
    288 
    289   // FIXME: Replace PassT::Result with type traits when we use C++11.
    290   typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
    291       ResultModelT;
    292 
    293   /// \brief The model delegates to the \c PassT::run method.
    294   ///
    295   /// The return is wrapped in an \c AnalysisResultModel.
    296   std::unique_ptr<AnalysisResultConcept<IRUnitT>>
    297   run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
    298     return make_unique<ResultModelT>(Pass.run(IR, AM));
    299   }
    300 
    301   /// \brief The model delegates to a static \c PassT::name method.
    302   ///
    303   /// The returned string ref must point to constant immutable data!
    304   StringRef name() override { return PassT::name(); }
    305 
    306   PassT Pass;
    307 };
    308 
    309 /// \brief Specialization of \c AnalysisPassModel which does not pass an
    310 /// \c AnalysisManager to PassT's run method.
    311 template <typename IRUnitT, typename PassT>
    312 struct AnalysisPassModel<IRUnitT, PassT, false> : AnalysisPassConcept<IRUnitT> {
    313   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
    314   // We have to explicitly define all the special member functions because MSVC
    315   // refuses to generate them.
    316   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
    317   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
    318   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
    319     using std::swap;
    320     swap(LHS.Pass, RHS.Pass);
    321   }
    322   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
    323     swap(*this, RHS);
    324     return *this;
    325   }
    326 
    327   // FIXME: Replace PassT::Result with type traits when we use C++11.
    328   typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
    329       ResultModelT;
    330 
    331   /// \brief The model delegates to the \c PassT::run method.
    332   ///
    333   /// The return is wrapped in an \c AnalysisResultModel.
    334   std::unique_ptr<AnalysisResultConcept<IRUnitT>>
    335   run(IRUnitT &IR, AnalysisManager<IRUnitT> *) override {
    336     return make_unique<ResultModelT>(Pass.run(IR));
    337   }
    338 
    339   /// \brief The model delegates to a static \c PassT::name method.
    340   ///
    341   /// The returned string ref must point to constant immutable data!
    342   StringRef name() override { return PassT::name(); }
    343 
    344   PassT Pass;
    345 };
    346 
    347 } // End namespace detail
    348 }
    349 
    350 #endif
    351