xref: /freebsd/contrib/llvm-project/llvm/include/llvm/IR/PassManagerInternal.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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/IR/Analysis.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <memory>
25 #include <utility>
26 
27 namespace llvm {
28 
29 template <typename IRUnitT> class AllAnalysesOn;
30 template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
31 class PreservedAnalyses;
32 
33 // Implementation details of the pass manager interfaces.
34 namespace detail {
35 
36 /// Template for the abstract base class used to dispatch
37 /// polymorphically over pass objects.
38 template <typename IRUnitT, typename AnalysisManagerT, typename... ExtraArgTs>
39 struct PassConcept {
40   // Boiler plate necessary for the container of derived classes.
41   virtual ~PassConcept() = default;
42 
43   /// The polymorphic API which runs the pass over a given IR entity.
44   ///
45   /// Note that actual pass object can omit the analysis manager argument if
46   /// desired. Also that the analysis manager may be null if there is no
47   /// analysis manager in the pass pipeline.
48   virtual PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
49                                 ExtraArgTs... ExtraArgs) = 0;
50 
51   virtual void
52   printPipeline(raw_ostream &OS,
53                 function_ref<StringRef(StringRef)> MapClassName2PassName) = 0;
54   /// Polymorphic method to access the name of a pass.
55   virtual StringRef name() const = 0;
56 
57   /// Polymorphic method to let a pass optionally exempted from skipping by
58   /// PassInstrumentation.
59   /// To opt-in, pass should implement `static bool isRequired()`. It's no-op
60   /// to have `isRequired` always return false since that is the default.
61   virtual bool isRequired() const = 0;
62 };
63 
64 /// A template wrapper used to implement the polymorphic API.
65 ///
66 /// Can be instantiated for any object which provides a \c run method accepting
67 /// an \c IRUnitT& and an \c AnalysisManager<IRUnit>&. It requires the pass to
68 /// be a copyable object.
69 template <typename IRUnitT, typename PassT, typename AnalysisManagerT,
70           typename... ExtraArgTs>
71 struct PassModel : PassConcept<IRUnitT, AnalysisManagerT, ExtraArgTs...> {
PassModelPassModel72   explicit PassModel(PassT Pass) : Pass(std::move(Pass)) {}
73   // We have to explicitly define all the special member functions because MSVC
74   // refuses to generate them.
PassModelPassModel75   PassModel(const PassModel &Arg) : Pass(Arg.Pass) {}
PassModelPassModel76   PassModel(PassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
77 
swapPassModel78   friend void swap(PassModel &LHS, PassModel &RHS) {
79     using std::swap;
80     swap(LHS.Pass, RHS.Pass);
81   }
82 
83   PassModel &operator=(PassModel RHS) {
84     swap(*this, RHS);
85     return *this;
86   }
87 
runPassModel88   PreservedAnalyses run(IRUnitT &IR, AnalysisManagerT &AM,
89                         ExtraArgTs... ExtraArgs) override {
90     return Pass.run(IR, AM, ExtraArgs...);
91   }
92 
printPipelinePassModel93   void printPipeline(
94       raw_ostream &OS,
95       function_ref<StringRef(StringRef)> MapClassName2PassName) override {
96     Pass.printPipeline(OS, MapClassName2PassName);
97   }
98 
namePassModel99   StringRef name() const override { return PassT::name(); }
100 
101   template <typename T>
102   using has_required_t = decltype(std::declval<T &>().isRequired());
103 
104   template <typename T>
105   static std::enable_if_t<is_detected<has_required_t, T>::value, bool>
passIsRequiredImplPassModel106   passIsRequiredImpl() {
107     return T::isRequired();
108   }
109   template <typename T>
110   static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
passIsRequiredImplPassModel111   passIsRequiredImpl() {
112     return false;
113   }
114 
isRequiredPassModel115   bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
116 
117   PassT Pass;
118 };
119 
120 /// Abstract concept of an analysis result.
121 ///
122 /// This concept is parameterized over the IR unit that this result pertains
123 /// to.
124 template <typename IRUnitT, typename InvalidatorT>
125 struct AnalysisResultConcept {
126   virtual ~AnalysisResultConcept() = default;
127 
128   /// Method to try and mark a result as invalid.
129   ///
130   /// When the outer analysis manager detects a change in some underlying
131   /// unit of the IR, it will call this method on all of the results cached.
132   ///
133   /// \p PA is a set of preserved analyses which can be used to avoid
134   /// invalidation because the pass which changed the underlying IR took care
135   /// to update or preserve the analysis result in some way.
136   ///
137   /// \p Inv is typically a \c AnalysisManager::Invalidator object that can be
138   /// used by a particular analysis result to discover if other analyses
139   /// results are also invalidated in the event that this result depends on
140   /// them. See the documentation in the \c AnalysisManager for more details.
141   ///
142   /// \returns true if the result is indeed invalid (the default).
143   virtual bool invalidate(IRUnitT &IR, const PreservedAnalyses &PA,
144                           InvalidatorT &Inv) = 0;
145 };
146 
147 /// SFINAE metafunction for computing whether \c ResultT provides an
148 /// \c invalidate member function.
149 template <typename IRUnitT, typename ResultT> class ResultHasInvalidateMethod {
150   using EnabledType = char;
151   struct DisabledType {
152     char a, b;
153   };
154 
155   // Purely to help out MSVC which fails to disable the below specialization,
156   // explicitly enable using the result type's invalidate routine if we can
157   // successfully call that routine.
158   template <typename T> struct Nonce { using Type = EnabledType; };
159   template <typename T>
160   static typename Nonce<decltype(std::declval<T>().invalidate(
161       std::declval<IRUnitT &>(), std::declval<PreservedAnalyses>()))>::Type
162       check(rank<2>);
163 
164   // First we define an overload that can only be taken if there is no
165   // invalidate member. We do this by taking the address of an invalidate
166   // member in an adjacent base class of a derived class. This would be
167   // ambiguous if there were an invalidate member in the result type.
168   template <typename T, typename U> static DisabledType NonceFunction(T U::*);
169   struct CheckerBase { int invalidate; };
170   template <typename T> struct Checker : CheckerBase, T {};
171   template <typename T>
172   static decltype(NonceFunction(&Checker<T>::invalidate)) check(rank<1>);
173 
174   // Now we have the fallback that will only be reached when there is an
175   // invalidate member, and enables the trait.
176   template <typename T>
177   static EnabledType check(rank<0>);
178 
179 public:
180   enum { Value = sizeof(check<ResultT>(rank<2>())) == sizeof(EnabledType) };
181 };
182 
183 /// Wrapper to model the analysis result concept.
184 ///
185 /// By default, this will implement the invalidate method with a trivial
186 /// implementation so that the actual analysis result doesn't need to provide
187 /// an invalidation handler. It is only selected when the invalidation handler
188 /// is not part of the ResultT's interface.
189 template <typename IRUnitT, typename PassT, typename ResultT,
190           typename InvalidatorT,
191           bool HasInvalidateHandler =
192               ResultHasInvalidateMethod<IRUnitT, ResultT>::Value>
193 struct AnalysisResultModel;
194 
195 /// Specialization of \c AnalysisResultModel which provides the default
196 /// invalidate functionality.
197 template <typename IRUnitT, typename PassT, typename ResultT,
198           typename InvalidatorT>
199 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, false>
200     : AnalysisResultConcept<IRUnitT, 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 PreservedAnalyses &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 InvalidatorT>
237 struct AnalysisResultModel<IRUnitT, PassT, ResultT, InvalidatorT, true>
238     : AnalysisResultConcept<IRUnitT, 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 PreservedAnalyses &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 InvalidatorT, typename... ExtraArgTs>
270 struct AnalysisPassConcept {
271   virtual ~AnalysisPassConcept() = default;
272 
273   /// Method to run this analysis over a unit of IR.
274   /// \returns A unique_ptr to the analysis result object to be queried by
275   /// users.
276   virtual std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
277   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
278       ExtraArgTs... ExtraArgs) = 0;
279 
280   /// Polymorphic method to access the name of a pass.
281   virtual StringRef name() const = 0;
282 };
283 
284 /// Wrapper to model the analysis pass concept.
285 ///
286 /// Can wrap any type which implements a suitable \c run method. The method
287 /// must accept an \c IRUnitT& and an \c AnalysisManager<IRUnitT>& as arguments
288 /// and produce an object which can be wrapped in a \c AnalysisResultModel.
289 template <typename IRUnitT, typename PassT, typename InvalidatorT,
290           typename... ExtraArgTs>
291 struct AnalysisPassModel
292     : AnalysisPassConcept<IRUnitT, InvalidatorT, ExtraArgTs...> {
293   explicit AnalysisPassModel(PassT Pass) : Pass(std::move(Pass)) {}
294   // We have to explicitly define all the special member functions because MSVC
295   // refuses to generate them.
296   AnalysisPassModel(const AnalysisPassModel &Arg) : Pass(Arg.Pass) {}
297   AnalysisPassModel(AnalysisPassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
298 
299   friend void swap(AnalysisPassModel &LHS, AnalysisPassModel &RHS) {
300     using std::swap;
301     swap(LHS.Pass, RHS.Pass);
302   }
303 
304   AnalysisPassModel &operator=(AnalysisPassModel RHS) {
305     swap(*this, RHS);
306     return *this;
307   }
308 
309   // FIXME: Replace PassT::Result with type traits when we use C++11.
310   using ResultModelT =
311       AnalysisResultModel<IRUnitT, PassT, typename PassT::Result, InvalidatorT>;
312 
313   /// The model delegates to the \c PassT::run method.
314   ///
315   /// The return is wrapped in an \c AnalysisResultModel.
316   std::unique_ptr<AnalysisResultConcept<IRUnitT, InvalidatorT>>
317   run(IRUnitT &IR, AnalysisManager<IRUnitT, ExtraArgTs...> &AM,
318       ExtraArgTs... ExtraArgs) override {
319     return std::make_unique<ResultModelT>(
320         Pass.run(IR, AM, std::forward<ExtraArgTs>(ExtraArgs)...));
321   }
322 
323   /// The model delegates to a static \c PassT::name method.
324   ///
325   /// The returned string ref must point to constant immutable data!
326   StringRef name() const override { return PassT::name(); }
327 
328   PassT Pass;
329 };
330 
331 } // end namespace detail
332 
333 } // end namespace llvm
334 
335 #endif // LLVM_IR_PASSMANAGERINTERNAL_H
336