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