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