Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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