LLVM 18.0.0git
PassManagerInternal.h
Go to the documentation of this file.
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"
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>
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
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 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
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
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>
106 return T::isRequired();
107 }
108 template <typename T>
109 static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
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>
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 =
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) {}
206 : Result(std::move(Arg.Result)) {}
207
209 using std::swap;
210 swap(LHS.Result, RHS.Result);
211 }
212
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) {}
245 : Result(std::move(Arg.Result)) {}
246
248 using std::swap;
249 swap(LHS.Result, RHS.Result);
250 }
251
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>
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<
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.
301
303 using std::swap;
304 swap(LHS.Pass, RHS.Pass);
305 }
306
308 swap(*this, RHS);
309 return *this;
310 }
311
312 // FIXME: Replace PassT::Result with type traits when we use C++11.
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<
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
basic Basic Alias true
Legalize the Machine IR a function s Machine IR
Definition: Legalizer.cpp:81
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
Value * RHS
Value * LHS
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:94
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
SFINAE metafunction for computing whether ResultT provides an invalidate member function.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1854
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
Abstract concept of an analysis pass.
virtual StringRef name() const =0
Polymorphic method to access the name of a pass.
virtual ~AnalysisPassConcept()=default
virtual std::unique_ptr< AnalysisResultConcept< IRUnitT, PreservedAnalysesT, InvalidatorT > > run(IRUnitT &IR, AnalysisManager< IRUnitT, ExtraArgTs... > &AM, ExtraArgTs... ExtraArgs)=0
Method to run this analysis over a unit of IR.
Wrapper to model the analysis pass concept.
AnalysisPassModel(const AnalysisPassModel &Arg)
std::unique_ptr< AnalysisResultConcept< IRUnitT, PreservedAnalysesT, InvalidatorT > > run(IRUnitT &IR, AnalysisManager< IRUnitT, ExtraArgTs... > &AM, ExtraArgTs... ExtraArgs) override
The model delegates to the PassT::run method.
StringRef name() const override
The model delegates to a static PassT::name method.
AnalysisPassModel(AnalysisPassModel &&Arg)
AnalysisPassModel & operator=(AnalysisPassModel RHS)
friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS)
Abstract concept of an analysis result.
virtual ~AnalysisResultConcept()=default
virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, InvalidatorT &Inv)=0
Method to try and mark a result as invalid.
bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA, InvalidatorT &Inv) override
The model delegates to the ResultT method.
bool invalidate(IRUnitT &, const PreservedAnalysesT &PA, InvalidatorT &) override
The model bases invalidation solely on being in the preserved set.
Wrapper to model the analysis result concept.
Template for the abstract base class used to dispatch polymorphically over pass objects.
virtual StringRef name() const =0
Polymorphic method to access the name of a pass.
virtual void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)=0
virtual bool isRequired() const =0
Polymorphic method to let a pass optionally exempted from skipping by PassInstrumentation.
virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs)=0
The polymorphic API which runs the pass over a given IR entity.
virtual ~PassConcept()=default
A template wrapper used to implement the polymorphic API.
friend void swap(PassModel &LHS, PassModel &RHS)
decltype(std::declval< T & >().isRequired()) has_required_t
PassModel(const PassModel &Arg)
void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName) override
static std::enable_if_t<!is_detected< has_required_t, T >::value, bool > passIsRequiredImpl()
PassModel & operator=(PassModel RHS)
PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM, ExtraArgTs... ExtraArgs) override
The polymorphic API which runs the pass over a given IR entity.
StringRef name() const override
Polymorphic method to access the name of a pass.
bool isRequired() const override
Polymorphic method to let a pass optionally exempted from skipping by PassInstrumentation.
static std::enable_if_t< is_detected< has_required_t, T >::value, bool > passIsRequiredImpl()
Utility type to build an inheritance chain that makes it easy to rank overload candidates.
Definition: STLExtras.h:1484