• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 namespace llvm {
26 
27 template <typename IRUnitT> class AllAnalysesOn;
28 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
29 class PreservedAnalyses;
30 
31 /// Implementation details of the pass manager interfaces.
32 namespace detail {
33 
34 /// Template for the abstract base class used to dispatch
35 /// polymorphically over pass objects.
36 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
37 struct 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 
53 /// A template wrapper used to implement the polymorphic API.
54 ///
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...> {
PassModelPassModel61   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.
PassModelPassModel64   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
PassModelPassModel65   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
66 
swapPassModel67   friend void swap(PassModel &LHS, PassModel &RHS) {
68     using std::swap;
69     swap(LHS.Pass, RHS.Pass);
70   }
71 
72   PassModel &operator=(PassModel RHS) {
73     swap(*this, RHS);
74     return *this;
75   }
76 
runPassModel77   PreservedAnalysesT run(IRUnitT &IR, AnalysisManagerT &AM,
78                          ExtraArgTs... ExtraArgs) override {
79     return Pass.run(IR, AM, ExtraArgs...);
80   }
81 
namePassModel82   StringRef name() const override { return PassT::name(); }
83 
84   PassT Pass;
85 };
86 
87 /// Abstract concept of an analysis result.
88 ///
89 /// This concept is parameterized over the IR unit that this result pertains
90 /// to.
91 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT>
92 struct AnalysisResultConcept {
93   virtual ~AnalysisResultConcept() = default;
94 
95   /// Method to try and mark a result as invalid.
96   ///
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.
99   ///
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.
103   ///
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.
108   ///
109   /// \returns true if the result is indeed invalid (the default).
110   virtual bool invalidate(IRUnitT &IR, const PreservedAnalysesT &PA,
111                           InvalidatorT &Inv) = 0;
112 };
113 
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 {
119     char a, b;
120   };
121 
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
129       check(rank<2>);
130 
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>);
140 
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>);
145 
146 public:
147   enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) };
148 };
149 
150 /// Wrapper to model the analysis result concept.
151 ///
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;
161 
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,
167                            InvalidatorT, false>
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)) {}
175 
176   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
177     using std::swap;
178     swap(LHS.Result, RHS.Result);
179   }
180 
181   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
182     swap(*this, RHS);
183     return *this;
184   }
185 
186   /// The model bases invalidation solely on being in the preserved set.
187   //
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>>();
196   }
197 
198   ResultT Result;
199 };
200 
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,
206                            InvalidatorT, true>
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)) {}
214 
215   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
216     using std::swap;
217     swap(LHS.Result, RHS.Result);
218   }
219 
220   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
221     swap(*this, RHS);
222     return *this;
223   }
224 
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);
229   }
230 
231   ResultT Result;
232 };
233 
234 /// Abstract concept of an analysis pass.
235 ///
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;
242 
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
245   /// users.
246   virtual std::unique_ptr<
247       AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>>
248   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
249       ExtraArgTs... ExtraArgs) = 0;
250 
251   /// Polymorphic method to access the name of a pass.
252   virtual StringRef name() const = 0;
253 };
254 
255 /// Wrapper to model the analysis pass concept.
256 ///
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)) {}
269 
270   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
271     using std::swap;
272     swap(LHS.Pass, RHS.Pass);
273   }
274 
275   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
276     swap(*this, RHS);
277     return *this;
278   }
279 
280   // FIXME: Replace PassT::Result with type traits when we use C++11.
281   using ResultModelT =
282       AnalysisResultModel<IRUnitT, PassT, typename PassT::Result,
283                           PreservedAnalysesT, InvalidatorT>;
284 
285   /// The model delegates to the \c PassT::run method.
286   ///
287   /// The return is wrapped in an \c AnalysisResultModel.
288   std::unique_ptr<
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)...));
294   }
295 
296   /// The model delegates to a static \c PassT::name method.
297   ///
298   /// The returned string ref must point to constant immutable data!
299   StringRef name() const override { return PassT::name(); }
300 
301   PassT Pass;
302 };
303 
304 } // end namespace detail
305 
306 } // end namespace llvm
307 
308 #endif // LLVM_IR_PASSMANAGERINTERNAL_H
309