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