[PM] Use a simpler technique to drop optional analysis manager arguments
[oota-llvm.git] / include / llvm / IR / PassManagerInternal.h
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 Helper template to run a pass *with* an optional analysis manager.
33 ///
34 /// This accepts the address of the run method as an argument to detect that it
35 /// accepts the analysis manager and pass it through. This isn't (quite)
36 /// a generic optional argument invocation tool, and couldn't be without making
37 /// the calling syntax significantly more verbose.
38 template <typename ResultT, typename IRUnitT, typename PassT>
39 ResultT invokeRunMethod(PassT &Pass,
40                         ResultT (PassT::*run)(IRUnitT &,
41                                               AnalysisManager<IRUnitT> *),
42                         IRUnitT &IR, AnalysisManager<IRUnitT> *AM) {
43   return (Pass.*run)(IR, AM);
44 }
45
46 /// \brief Helper template to run a pass *without* an optional analysis manager.
47 ///
48 /// This accepts the address of the run method as an argument to detect that it
49 /// does not accept an analysis manager and drop it. This isn't (quite)
50 /// a generic optional argument invocation tool, and couldn't be without making
51 /// the calling syntax significantly more verbose.
52 template <typename ResultT, typename IRUnitT, typename PassT>
53 ResultT invokeRunMethod(
54     PassT &Pass,
55     ResultT (PassT::*run)(IRUnitT &),
56     IRUnitT &IR, AnalysisManager<IRUnitT> * /*AM*/) {
57   return (Pass.*run)(IR);
58 }
59
60 /// \brief Template for the abstract base class used to dispatch
61 /// polymorphically over pass objects.
62 template <typename ResultT, typename IRUnitT> struct PassConceptBase {
63   virtual ~PassConceptBase() {}
64
65   /// \brief The polymorphic API which runs the pass over a given IR entity.
66   ///
67   /// Note that actual pass object can omit the analysis manager argument if
68   /// desired. Also that the analysis manager may be null if there is no
69   /// analysis manager in the pass pipeline.
70   virtual ResultT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) = 0;
71
72   /// \brief Polymorphic method to access the name of a pass.
73   virtual StringRef name() = 0;
74 };
75
76 /// \brief Abstract concept of an transform pass.
77 ///
78 /// This concept is parameterized over the IR unit that it can run over and
79 /// returns status of preserved analyses.
80 template <typename IRUnitT>
81 using PassConcept = PassConceptBase<PreservedAnalyses, IRUnitT>;
82
83 /// \brief A template wrapper used to implement the polymorphic API.
84 ///
85 /// Can be instantiated for any object which provides a \c run method accepting
86 /// an \c IRUnitT. It requires the pass to be a copyable object. When the
87 /// \c run method also accepts an \c AnalysisManager<IRUnitT>*, we pass it
88 /// along.
89 template <typename IRUnitT, typename PassT,
90           typename PreservedAnalysesT = PreservedAnalyses>
91 struct PassModel : PassConcept<IRUnitT> {
92   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
93   // We have to explicitly define all the special member functions because MSVC
94   // refuses to generate them.
95   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
96   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
97   friend void swap(PassModel &LHS, PassModel &RHS) {
98     using std::swap;
99     swap(LHS.Pass, RHS.Pass);
100   }
101   PassModel &operator=(PassModel RHS) {
102     swap(*this, RHS);
103     return *this;
104   }
105
106   /// \brief The model delegates to the \c PassT::run method.
107   PreservedAnalysesT run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
108     return invokeRunMethod<PreservedAnalysesT>(Pass, &PassT::run, IR, AM);
109   }
110   StringRef name() override { return PassT::name(); }
111   PassT Pass;
112 };
113
114 /// \brief Abstract concept of an analysis result.
115 ///
116 /// This concept is parameterized over the IR unit that this result pertains
117 /// to.
118 template <typename IRUnitT> struct AnalysisResultConcept {
119   virtual ~AnalysisResultConcept() {}
120
121   /// \brief Method to try and mark a result as invalid.
122   ///
123   /// When the outer analysis manager detects a change in some underlying
124   /// unit of the IR, it will call this method on all of the results cached.
125   ///
126   /// This method also receives a set of preserved analyses which can be used
127   /// to avoid invalidation because the pass which changed the underlying IR
128   /// took care to update or preserve the analysis result in some way.
129   ///
130   /// \returns true if the result is indeed invalid (the default).
131   virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA) = 0;
132 };
133
134 /// \brief SFINAE metafunction for computing whether \c ResultT provides an
135 /// \c invalidate member function.
136 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
137   typedef char SmallType;
138   struct BigType {
139     char a, b;
140   };
141
142   template <typename T, bool (T::*)(IRUnitT &, const PreservedAnalyses &)>
143   struct Checker;
144
145   template <typename T> static SmallType f(Checker<T, &T::invalidate> *);
146   template <typename T> static BigType f(...);
147
148 public:
149   enum { Value = sizeof(f<ResultT>(nullptr)) == sizeof(SmallType) };
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 = PreservedAnalyses,
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>
168 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, false>
169     : AnalysisResultConcept<IRUnitT> {
170   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
171   // We have to explicitly define all the special member functions because MSVC
172   // refuses to generate them.
173   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
174   AnalysisResultModel(AnalysisResultModel &&Arg)
175       : Result(std::move(Arg.Result)) {}
176   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
177     using std::swap;
178     swap(LHS.Result, RHS.Result);
179   }
180   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
181     swap(*this, RHS);
182     return *this;
183   }
184
185   /// \brief The model bases invalidation solely on being in the preserved set.
186   //
187   // FIXME: We should actually use two different concepts for analysis results
188   // rather than two different models, and avoid the indirect function call for
189   // ones that use the trivial behavior.
190   bool invalidate(IRUnitT &, const PreservedAnalysesT &PA) override {
191     return !PA.preserved(PassT::ID());
192   }
193
194   ResultT Result;
195 };
196
197 /// \brief Specialization of \c AnalysisResultModel which delegates invalidate
198 /// handling to \c ResultT.
199 template <typename IRUnitT, typename PassT, typename ResultT,
200           typename PreservedAnalysesT>
201 struct AnalysisResultModel<IRUnitT, PassT, ResultT, PreservedAnalysesT, true>
202     : AnalysisResultConcept<IRUnitT> {
203   explicit AnalysisResultModel(ResultT Result) : Result(std::move(Result)) {}
204   // We have to explicitly define all the special member functions because MSVC
205   // refuses to generate them.
206   AnalysisResultModel(const AnalysisResultModel &Arg) : Result(Arg.Result) {}
207   AnalysisResultModel(AnalysisResultModel &&Arg)
208       : Result(std::move(Arg.Result)) {}
209   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
210     using std::swap;
211     swap(LHS.Result, RHS.Result);
212   }
213   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
214     swap(*this, RHS);
215     return *this;
216   }
217
218   /// \brief The model delegates to the \c ResultT method.
219   bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA) override {
220     return Result.invalidate(IR, PA);
221   }
222
223   ResultT Result;
224 };
225
226 /// \brief Abstract concept of an analysis pass.
227 ///
228 /// This concept is parameterized over the IR unit that it can run over and
229 /// produce an analysis result.
230 template <typename IRUnitT>
231 using AnalysisPassConcept =
232     PassConceptBase<std::unique_ptr<AnalysisResultConcept<IRUnitT>>, IRUnitT>;
233
234 /// \brief Wrapper to model the analysis pass concept.
235 ///
236 /// Can wrap any type which implements a suitable \c run method. The method
237 /// must accept the IRUnitT as an argument and produce an object which can be
238 /// wrapped in a \c AnalysisResultModel.
239 template <typename IRUnitT, typename PassT>
240 struct AnalysisPassModel : AnalysisPassConcept<IRUnitT> {
241   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
242   // We have to explicitly define all the special member functions because MSVC
243   // refuses to generate them.
244   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
245   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
246   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
247     using std::swap;
248     swap(LHS.Pass, RHS.Pass);
249   }
250   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
251     swap(*this, RHS);
252     return *this;
253   }
254
255   // FIXME: Replace PassT::Result with type traits when we use C++11.
256   using ResultT = typename PassT::Result;
257   using ResultModelT = AnalysisResultModel<IRUnitT, PassT, ResultT>;
258
259   /// \brief The model delegates to the \c PassT::run method.
260   ///
261   /// The return is wrapped in an \c AnalysisResultModel.
262   std::unique_ptr<AnalysisResultConcept<IRUnitT>>
263   run(IRUnitT &IR, AnalysisManager<IRUnitT> *AM) override {
264     return make_unique<ResultModelT>(
265         invokeRunMethod<ResultT>(Pass, &PassT::run, IR, AM));
266   }
267
268   /// \brief The model delegates to a static \c PassT::name method.
269   ///
270   /// The returned string ref must point to constant immutable data!
271   StringRef name() override { return PassT::name(); }
272
273   PassT Pass;
274 };
275
276 } // End namespace detail
277 }
278
279 #endif