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

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