1 //===- PassManager internal APIs and implementation details -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
15 //===----------------------------------------------------------------------===//
17 #ifndef LLVM_IR_PASSMANAGERINTERNAL_H
18 #define LLVM_IR_PASSMANAGERINTERNAL_H
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringRef.h"
27 template <typename IRUnitT
> class AllAnalysesOn
;
28 template <typename IRUnitT
, typename
... ExtraArgTs
> class AnalysisManager
;
29 class PreservedAnalyses
;
31 /// Implementation details of the pass manager interfaces.
34 /// Template for the abstract base class used to dispatch
35 /// polymorphically over pass objects.
36 template <typename IRUnitT
, typename AnalysisManagerT
, typename
... ExtraArgTs
>
38 // Boiler plate necessary for the container of derived classes.
39 virtual ~PassConcept() = default;
41 /// The polymorphic API which runs the pass over a given IR entity.
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;
49 /// Polymorphic method to access the name of a pass.
50 virtual StringRef
name() const = 0;
53 /// A template wrapper used to implement the polymorphic API.
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.
58 template <typename IRUnitT
, typename PassT
, typename PreservedAnalysesT
,
59 typename AnalysisManagerT
, typename
... ExtraArgTs
>
60 struct 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
)) {}
67 friend void swap(PassModel
&LHS
, PassModel
&RHS
) {
69 swap(LHS
.Pass
, RHS
.Pass
);
72 PassModel
&operator=(PassModel RHS
) {
77 PreservedAnalysesT
run(IRUnitT
&IR
, AnalysisManagerT
&AM
,
78 ExtraArgTs
... ExtraArgs
) override
{
79 return Pass
.run(IR
, AM
, ExtraArgs
...);
82 StringRef
name() const override
{ return PassT::name(); }
87 /// Abstract concept of an analysis result.
89 /// This concept is parameterized over the IR unit that this result pertains
91 template <typename IRUnitT
, typename PreservedAnalysesT
, typename InvalidatorT
>
92 struct AnalysisResultConcept
{
93 virtual ~AnalysisResultConcept() = default;
95 /// Method to try and mark a result as invalid.
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.
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.
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.
109 /// \returns true if the result is indeed invalid (the default).
110 virtual bool invalidate(IRUnitT
&IR
, const PreservedAnalysesT
&PA
,
111 InvalidatorT
&Inv
) = 0;
114 /// SFINAE metafunction for computing whether \c ResultT provides an
115 /// \c invalidate member function.
116 template <typename IRUnitT
, typename ResultT
> class ResultHasInvalidateMethod
{
117 using EnabledType
= char;
118 struct DisabledType
{
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
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>);
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>);
147 enum { Value
= sizeof(check
<ResultT
>(rank
<2>())) == sizeof(EnabledType
) };
150 /// Wrapper to model the analysis result concept.
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.
156 template <typename IRUnitT
, typename PassT
, typename ResultT
,
157 typename PreservedAnalysesT
, typename InvalidatorT
,
158 bool HasInvalidateHandler
=
159 ResultHasInvalidateMethod
<IRUnitT
, ResultT
>::Value
>
160 struct AnalysisResultModel
;
162 /// Specialization of \c AnalysisResultModel which provides the default
163 /// invalidate functionality.
164 template <typename IRUnitT
, typename PassT
, typename ResultT
,
165 typename PreservedAnalysesT
, typename InvalidatorT
>
166 struct AnalysisResultModel
<IRUnitT
, PassT
, ResultT
, PreservedAnalysesT
,
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
)) {}
176 friend void swap(AnalysisResultModel
&LHS
, AnalysisResultModel
&RHS
) {
178 swap(LHS
.Result
, RHS
.Result
);
181 AnalysisResultModel
&operator=(AnalysisResultModel RHS
) {
186 /// The model bases invalidation solely on being in the preserved set.
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
>>();
201 /// Specialization of \c AnalysisResultModel which delegates invalidate
202 /// handling to \c ResultT.
203 template <typename IRUnitT
, typename PassT
, typename ResultT
,
204 typename PreservedAnalysesT
, typename InvalidatorT
>
205 struct AnalysisResultModel
<IRUnitT
, PassT
, ResultT
, PreservedAnalysesT
,
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
)) {}
215 friend void swap(AnalysisResultModel
&LHS
, AnalysisResultModel
&RHS
) {
217 swap(LHS
.Result
, RHS
.Result
);
220 AnalysisResultModel
&operator=(AnalysisResultModel RHS
) {
225 /// The model delegates to the \c ResultT method.
226 bool invalidate(IRUnitT
&IR
, const PreservedAnalysesT
&PA
,
227 InvalidatorT
&Inv
) override
{
228 return Result
.invalidate(IR
, PA
, Inv
);
234 /// Abstract concept of an analysis pass.
236 /// This concept is parameterized over the IR unit that it can run over and
237 /// produce an analysis result.
238 template <typename IRUnitT
, typename PreservedAnalysesT
, typename InvalidatorT
,
239 typename
... ExtraArgTs
>
240 struct AnalysisPassConcept
{
241 virtual ~AnalysisPassConcept() = default;
243 /// Method to run this analysis over a unit of IR.
244 /// \returns A unique_ptr to the analysis result object to be queried by
246 virtual std::unique_ptr
<
247 AnalysisResultConcept
<IRUnitT
, PreservedAnalysesT
, InvalidatorT
>>
248 run(IRUnitT
&IR
, AnalysisManager
<IRUnitT
, ExtraArgTs
...> &AM
,
249 ExtraArgTs
... ExtraArgs
) = 0;
251 /// Polymorphic method to access the name of a pass.
252 virtual StringRef
name() const = 0;
255 /// Wrapper to model the analysis pass concept.
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.
260 template <typename IRUnitT
, typename PassT
, typename PreservedAnalysesT
,
261 typename InvalidatorT
, typename
... ExtraArgTs
>
262 struct 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
)) {}
270 friend void swap(AnalysisPassModel
&LHS
, AnalysisPassModel
&RHS
) {
272 swap(LHS
.Pass
, RHS
.Pass
);
275 AnalysisPassModel
&operator=(AnalysisPassModel RHS
) {
280 // FIXME: Replace PassT::Result with type traits when we use C++11.
282 AnalysisResultModel
<IRUnitT
, PassT
, typename
PassT::Result
,
283 PreservedAnalysesT
, InvalidatorT
>;
285 /// The model delegates to the \c PassT::run method.
287 /// The return is wrapped in an \c AnalysisResultModel.
289 AnalysisResultConcept
<IRUnitT
, PreservedAnalysesT
, InvalidatorT
>>
290 run(IRUnitT
&IR
, AnalysisManager
<IRUnitT
, ExtraArgTs
...> &AM
,
291 ExtraArgTs
... ExtraArgs
) override
{
292 return std::make_unique
<ResultModelT
>(
293 Pass
.run(IR
, AM
, std::forward
<ExtraArgTs
>(ExtraArgs
)...));
296 /// The model delegates to a static \c PassT::name method.
298 /// The returned string ref must point to constant immutable data!
299 StringRef
name() const override
{ return PassT::name(); }
304 } // end namespace detail
306 } // end namespace llvm
308 #endif // LLVM_IR_PASSMANAGERINTERNAL_H