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