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

source code of llvm/include/llvm/IR/PassManagerInternal.h