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/Support/raw_ostream.h"
23 #include <memory>
24 #include <utility>
25 
26 namespace llvm {
27 
28 template <typename IRUnitT> class AllAnalysesOn;
29 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
30 class PreservedAnalyses;
31 
32 // Implementation details of the pass manager interfaces.
33 namespace detail {
34 
35 /// Template for the abstract base class used to dispatch
36 /// polymorphically over pass objects.
37 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
38 struct PassConcept {
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
51   printPipeline(raw_ostream &OS,
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 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.
68 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
69           typename AnalysisManagerT, typename... ExtraArgTs>
70 struct 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 
82   PassModel &operator=(PassModel RHS) {
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 
92   void printPipeline(
93       raw_ostream &OS,
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>
105   passIsRequiredImpl() {
106     return T::isRequired();
107   }
108   template <typename T>
109   static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
110   passIsRequiredImpl() {
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.
123 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT>
124 struct AnalysisResultConcept {
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.
148 template <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 
178 public:
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.
188 template <typename IRUnitT, typename PassT, typename ResultT,
189           typename PreservedAnalysesT, typename InvalidatorT,
190           bool HasInvalidateHandler =
191               ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
192 struct AnalysisResultModel;
193 
194 /// Specialization of \c AnalysisResultModel which provides the default
195 /// invalidate functionality.
196 template <typename IRUnitT, typename PassT, typename ResultT,
197           typename PreservedAnalysesT, typename InvalidatorT>
198 struct 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) {}
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 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.
235 template <typename IRUnitT, typename PassT, typename ResultT,
236           typename PreservedAnalysesT, typename InvalidatorT>
237 struct 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) {}
244   AnalysisResultModel(AnalysisResultModel &&Arg)
245       : Result(std::move(Arg.Result)) {}
246 
247   friend void swap(AnalysisResultModel &LHS, AnalysisResultModel &RHS) {
248     using std::swap;
249     swap(LHS.Result, RHS.Result);
250   }
251 
252   AnalysisResultModel &operator=(AnalysisResultModel RHS) {
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.
270 template <typename IRUnitT, typename PreservedAnalysesT, typename InvalidatorT,
271           typename... ExtraArgTs>
272 struct AnalysisPassConcept {
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<
279       AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>>
280   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
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.
292 template <typename IRUnitT, typename PassT, typename PreservedAnalysesT,
293           typename InvalidatorT, typename... ExtraArgTs>
294 struct 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.
299   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
300   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
301 
302   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
303     using std::swap;
304     swap(LHS.Pass, RHS.Pass);
305   }
306 
307   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
308     swap(*this, RHS);
309     return *this;
310   }
311 
312   // FIXME: Replace PassT::Result with type traits when we use C++11.
313   using ResultModelT =
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<
321       AnalysisResultConcept<IRUnitT, PreservedAnalysesT, InvalidatorT>>
322   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
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
341