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