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
24namespace llvm {
25
26template <typename IRUnitT> class AnalysisManager;
27class PreservedAnalyses;
28
29/// \brief Implementation details of the pass manager interfaces.
30namespace detail {
31
32/// \brief Template for the abstract base class used to dispatch
33/// polymorphically over pass objects.
34template <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 A template wrapper used to implement the polymorphic API.
50///
51/// Can be instantiated for any object which provides a \c run method accepting
52/// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to
53/// be a copyable object. When the
54template <typename IRUnitT, typename PassT,
55          typename PreservedAnalysesT = PreservedAnalyses>
56struct PassModel : PassConcept<IRUnitT> {
57  explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
58  // We have to explicitly define all the special member functions because MSVC
59  // refuses to generate them.
60  PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
61  PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
62  friend void swap(PassModel &LHS, PassModel &RHS) {
63    using std::swap;
64    swap(LHS.Pass, RHS.Pass);
65  }
66  PassModel &operator=(PassModel RHS) {
67    swap(*this, RHS);
68    return *this;
69  }
70
71  PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) override {
72    return Pass.run(IR, AM);
73  }
74  StringRef name() override { return PassT::name(); }
75  PassT Pass;
76};
77
78/// \brief Abstract concept of an analysis result.
79///
80/// This concept is parameterized over the IR unit that this result pertains
81/// to.
82template <typename IRUnitT> struct AnalysisResultConcept {
83  virtual ~AnalysisResultConcept() {}
84
85  /// \brief Method to try and mark a result as invalid.
86  ///
87  /// When the outer analysis manager detects a change in some underlying
88  /// unit of the IR, it will call this method on all of the results cached.
89  ///
90  /// This method also receives a set of preserved analyses which can be used
91  /// to avoid invalidation because the pass which changed the underlying IR
92  /// took care to update or preserve the analysis result in some way.
93  ///
94  /// \returns true if the result is indeed invalid (the default).
95  virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA) = 0;
96};
97
98/// \brief SFINAE metafunction for computing whether \c ResultT provides an
99/// \c invalidate member function.
100template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
101  typedef char SmallType;
102  struct BigType {
103    char a, b;
104  };
105
106  template <typename T, bool (T::*)(IRUnitT &, const PreservedAnalyses &)>
107  struct Checker;
108
109  template <typename T> static SmallType f(Checker<T, &T::invalidate> *);
110  template <typename T> static BigType f(...);
111
112public:
113  enum { Value = sizeof(f<ResultT>(nullptr)) == sizeof(SmallType) };
114};
115
116/// \brief Wrapper to model the analysis result concept.
117///
118/// By default, this will implement the invalidate method with a trivial
119/// implementation so that the actual analysis result doesn't need to provide
120/// an invalidation handler. It is only selected when the invalidation handler
121/// is not part of the ResultT's interface.
122template <typename IRUnitT, typename PassT, typename ResultT,
123          typename PreservedAnalysesT = PreservedAnalyses,
124          bool HasInvalidateHandler =
125              ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
126struct AnalysisResultModel;
127
128/// \brief Specialization of \c AnalysisResultModel which provides the default
129/// invalidate functionality.
130template <typename IRUnitT, typename PassT, typename ResultT,
131          typename PreservedAnalysesT>
132struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, false>
133    : AnalysisResultConcept<IRUnitT> {
134  explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
135  // We have to explicitly define all the special member functions because MSVC
136  // refuses to generate them.
137  AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
138  AnalysisResultModel(AnalysisResultModel &&Arg)
139      : Result(std::move(Arg.Result)) {}
140  friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
141    using std::swap;
142    swap(LHS.Result, RHS.Result);
143  }
144  AnalysisResultModel &operator=(AnalysisResultModel RHS) {
145    swap(*this, RHS);
146    return *this;
147  }
148
149  /// \brief The model bases invalidation solely on being in the preserved set.
150  //
151  // FIXME: We should actually use two different concepts for analysis results
152  // rather than two different models, and avoid the indirect function call for
153  // ones that use the trivial behavior.
154  bool invalidate(IRUnitT &, const PreservedAnalysesT &PA) override {
155    return !PA.preserved(PassT::ID());
156  }
157
158  ResultT Result;
159};
160
161/// \brief Specialization of \c AnalysisResultModel which delegates invalidate
162/// handling to \c ResultT.
163template <typename IRUnitT, typename PassT, typename ResultT,
164          typename PreservedAnalysesT>
165struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, true>
166    : AnalysisResultConcept<IRUnitT> {
167  explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
168  // We have to explicitly define all the special member functions because MSVC
169  // refuses to generate them.
170  AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
171  AnalysisResultModel(AnalysisResultModel &&Arg)
172      : Result(std::move(Arg.Result)) {}
173  friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
174    using std::swap;
175    swap(LHS.Result, RHS.Result);
176  }
177  AnalysisResultModel &operator=(AnalysisResultModel RHS) {
178    swap(*this, RHS);
179    return *this;
180  }
181
182  /// \brief The model delegates to the \c ResultT method.
183  bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA) override {
184    return Result.invalidate(IR, PA);
185  }
186
187  ResultT Result;
188};
189
190/// \brief Abstract concept of an analysis pass.
191///
192/// This concept is parameterized over the IR unit that it can run over and
193/// produce an analysis result.
194template <typename IRUnitT> struct AnalysisPassConcept {
195  virtual ~AnalysisPassConcept() {}
196
197  /// \brief Method to run this analysis over a unit of IR.
198  /// \returns A unique_ptr to the analysis result object to be queried by
199  /// users.
200  virtual std::unique_ptr<AnalysisResultConcept<IRUnitT>>
201  run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) = 0;
202
203  /// \brief Polymorphic method to access the name of a pass.
204  virtual StringRef name() = 0;
205};
206
207/// \brief Wrapper to model the analysis pass concept.
208///
209/// Can wrap any type which implements a suitable \c run method. The method
210/// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments
211/// and produce an object which can be wrapped in a \c AnalysisResultModel.
212template <typename IRUnitT, typename PassT>
213struct AnalysisPassModel : AnalysisPassConcept<IRUnitT> {
214  explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
215  // We have to explicitly define all the special member functions because MSVC
216  // refuses to generate them.
217  AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
218  AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
219  friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
220    using std::swap;
221    swap(LHS.Pass, RHS.Pass);
222  }
223  AnalysisPassModel &operator=(AnalysisPassModel RHS) {
224    swap(*this, RHS);
225    return *this;
226  }
227
228  // FIXME: Replace PassT::Result with type traits when we use C++11.
229  typedef AnalysisResultModel<IRUnitT, PassT, typename PassT::Result>
230      ResultModelT;
231
232  /// \brief The model delegates to the \c PassT::run method.
233  ///
234  /// The return is wrapped in an \c AnalysisResultModel.
235  std::unique_ptr<AnalysisResultConcept<IRUnitT>>
236  run(IRUnitT &IR, AnalysisManager<IRUnitT> &AM) override {
237    return make_unique<ResultModelT>(Pass.run(IR, AM));
238  }
239
240  /// \brief The model delegates to a static \c PassT::name method.
241  ///
242  /// The returned string ref must point to constant immutable data!
243  StringRef name() override { return PassT::name(); }
244
245  PassT Pass;
246};
247
248} // End namespace detail
249}
250
251#endif
252