1 //===- Pass.h - Base classes for compiler passes ----------------*- 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 
9 #ifndef MLIR_PASS_PASS_H
10 #define MLIR_PASS_PASS_H
11 
12 #include "mlir/Pass/AnalysisManager.h"
13 #include "mlir/Pass/PassRegistry.h"
14 #include "mlir/Support/LogicalResult.h"
15 #include "llvm/ADT/PointerIntPair.h"
16 #include "llvm/ADT/Statistic.h"
17 
18 namespace mlir {
19 namespace detail {
20 class OpToOpPassAdaptor;
21 struct OpPassManagerImpl;
22 
23 /// The state for a single execution of a pass. This provides a unified
24 /// interface for accessing and initializing necessary state for pass execution.
25 struct PassExecutionState {
PassExecutionStatePassExecutionState26   PassExecutionState(Operation *ir, AnalysisManager analysisManager,
27                      function_ref<LogicalResult(OpPassManager &, Operation *)>
28                          pipelineExecutor)
29       : irAndPassFailed(ir, false), analysisManager(analysisManager),
30         pipelineExecutor(pipelineExecutor) {}
31 
32   /// The current operation being transformed and a bool for if the pass
33   /// signaled a failure.
34   llvm::PointerIntPair<Operation *, 1, bool> irAndPassFailed;
35 
36   /// The analysis manager for the operation.
37   AnalysisManager analysisManager;
38 
39   /// The set of preserved analyses for the current execution.
40   detail::PreservedAnalyses preservedAnalyses;
41 
42   /// This is a callback in the PassManager that allows to schedule dynamic
43   /// pipelines that will be rooted at the provided operation.
44   function_ref<LogicalResult(OpPassManager &, Operation *)> pipelineExecutor;
45 };
46 } // namespace detail
47 
48 /// The abstract base pass class. This class contains information describing the
49 /// derived pass object, e.g its kind and abstract TypeID.
50 class Pass {
51 public:
52   virtual ~Pass() = default;
53 
54   /// Returns the unique identifier that corresponds to this pass.
getTypeID()55   TypeID getTypeID() const { return passID; }
56 
57   /// Returns the pass info for the specified pass class or null if unknown.
58   static const PassInfo *lookupPassInfo(StringRef passArg);
59 
60   /// Returns the pass info for this pass, or null if unknown.
lookupPassInfo()61   const PassInfo *lookupPassInfo() const {
62     return lookupPassInfo(getArgument());
63   }
64 
65   /// Returns the derived pass name.
66   virtual StringRef getName() const = 0;
67 
68   /// Register dependent dialects for the current pass.
69   /// A pass is expected to register the dialects it will create entities for
70   /// (Operations, Types, Attributes), other than dialect that exists in the
71   /// input. For example, a pass that converts from Linalg to Affine would
72   /// register the Affine dialect but does not need to register Linalg.
getDependentDialects(DialectRegistry & registry)73   virtual void getDependentDialects(DialectRegistry &registry) const {}
74 
75   /// Return the command line argument used when registering this pass. Return
76   /// an empty string if one does not exist.
getArgument()77   virtual StringRef getArgument() const { return ""; }
78 
79   /// Return the command line description used when registering this pass.
80   /// Return an empty string if one does not exist.
getDescription()81   virtual StringRef getDescription() const { return ""; }
82 
83   /// Returns the name of the operation that this pass operates on, or None if
84   /// this is a generic OperationPass.
getOpName()85   Optional<StringRef> getOpName() const { return opName; }
86 
87   //===--------------------------------------------------------------------===//
88   // Options
89   //===--------------------------------------------------------------------===//
90 
91   /// This class represents a specific pass option, with a provided data type.
92   template <typename DataType,
93             typename OptionParser = detail::PassOptions::OptionParser<DataType>>
94   struct Option : public detail::PassOptions::Option<DataType, OptionParser> {
95     template <typename... Args>
OptionOption96     Option(Pass &parent, StringRef arg, Args &&...args)
97         : detail::PassOptions::Option<DataType, OptionParser>(
98               parent.passOptions, arg, std::forward<Args>(args)...) {}
99     using detail::PassOptions::Option<DataType, OptionParser>::operator=;
100   };
101   /// This class represents a specific pass option that contains a list of
102   /// values of the provided data type.
103   template <typename DataType,
104             typename OptionParser = detail::PassOptions::OptionParser<DataType>>
105   struct ListOption
106       : public detail::PassOptions::ListOption<DataType, OptionParser> {
107     template <typename... Args>
ListOptionListOption108     ListOption(Pass &parent, StringRef arg, Args &&...args)
109         : detail::PassOptions::ListOption<DataType, OptionParser>(
110               parent.passOptions, arg, std::forward<Args>(args)...) {}
111     using detail::PassOptions::ListOption<DataType, OptionParser>::operator=;
112   };
113 
114   /// Attempt to initialize the options of this pass from the given string.
115   /// Derived classes may override this method to hook into the point at which
116   /// options are initialized, but should generally always invoke this base
117   /// class variant.
118   virtual LogicalResult initializeOptions(StringRef options);
119 
120   /// Prints out the pass in the textual representation of pipelines. If this is
121   /// an adaptor pass, print with the op_name(sub_pass,...) format.
122   void printAsTextualPipeline(raw_ostream &os);
123 
124   //===--------------------------------------------------------------------===//
125   // Statistics
126   //===--------------------------------------------------------------------===//
127 
128   /// This class represents a single pass statistic. This statistic functions
129   /// similarly to an unsigned integer value, and may be updated and incremented
130   /// accordingly. This class can be used to provide additional information
131   /// about the transformations and analyses performed by a pass.
132   class Statistic : public llvm::Statistic {
133   public:
134     /// The statistic is initialized by the pass owner, a name, and a
135     /// description.
136     Statistic(Pass *owner, const char *name, const char *description);
137 
138     /// Assign the statistic to the given value.
139     Statistic &operator=(unsigned value);
140   };
141 
142   /// Returns the main statistics for this pass instance.
getStatistics()143   ArrayRef<Statistic *> getStatistics() const { return statistics; }
getStatistics()144   MutableArrayRef<Statistic *> getStatistics() { return statistics; }
145 
146   /// Returns the thread sibling of this pass.
147   ///
148   /// If this pass was cloned by the pass manager for the sake of
149   /// multi-threading, this function returns the original pass it was cloned
150   /// from. This is useful for diagnostic purposes to distinguish passes that
151   /// were replicated for threading purposes from passes instantiated by the
152   /// user. Used to collapse passes in timing statistics.
getThreadingSibling()153   const Pass *getThreadingSibling() const { return threadingSibling; }
154 
155   /// Returns the thread sibling of this pass, or the pass itself it has no
156   /// sibling. See `getThreadingSibling()` for details.
getThreadingSiblingOrThis()157   const Pass *getThreadingSiblingOrThis() const {
158     return threadingSibling ? threadingSibling : this;
159   }
160 
161 protected:
162   explicit Pass(TypeID passID, Optional<StringRef> opName = llvm::None)
passID(passID)163       : passID(passID), opName(opName) {}
Pass(const Pass & other)164   Pass(const Pass &other) : Pass(other.passID, other.opName) {}
165 
166   /// Returns the current pass state.
getPassState()167   detail::PassExecutionState &getPassState() {
168     assert(passState && "pass state was never initialized");
169     return *passState;
170   }
171 
172   /// Return the MLIR context for the current operation being transformed.
getContext()173   MLIRContext &getContext() { return *getOperation()->getContext(); }
174 
175   /// The polymorphic API that runs the pass over the currently held operation.
176   virtual void runOnOperation() = 0;
177 
178   /// Initialize any complex state necessary for running this pass. This hook
179   /// should not rely on any state accessible during the execution of a pass.
180   /// For example, `getContext`/`getOperation`/`getAnalysis`/etc. should not be
181   /// invoked within this hook.
182   /// Returns a LogicalResult to indicate failure, in which case the pass
183   /// pipeline won't execute.
initialize(MLIRContext * context)184   virtual LogicalResult initialize(MLIRContext *context) { return success(); }
185 
186   /// Indicate if the current pass can be scheduled on the given operation type.
187   /// This is useful for generic operation passes to add restrictions on the
188   /// operations they operate on.
189   virtual bool canScheduleOn(RegisteredOperationName opName) const = 0;
190 
191   /// Schedule an arbitrary pass pipeline on the provided operation.
192   /// This can be invoke any time in a pass to dynamic schedule more passes.
193   /// The provided operation must be the current one or one nested below.
runPipeline(OpPassManager & pipeline,Operation * op)194   LogicalResult runPipeline(OpPassManager &pipeline, Operation *op) {
195     return passState->pipelineExecutor(pipeline, op);
196   }
197 
198   /// A clone method to create a copy of this pass.
clone()199   std::unique_ptr<Pass> clone() const {
200     auto newInst = clonePass();
201     newInst->copyOptionValuesFrom(this);
202     return newInst;
203   }
204 
205   /// Return the current operation being transformed.
getOperation()206   Operation *getOperation() {
207     return getPassState().irAndPassFailed.getPointer();
208   }
209 
210   /// Signal that some invariant was broken when running. The IR is allowed to
211   /// be in an invalid state.
signalPassFailure()212   void signalPassFailure() { getPassState().irAndPassFailed.setInt(true); }
213 
214   /// Query an analysis for the current ir unit.
215   template <typename AnalysisT>
getAnalysis()216   AnalysisT &getAnalysis() {
217     return getAnalysisManager().getAnalysis<AnalysisT>();
218   }
219 
220   /// Query an analysis for the current ir unit of a specific derived operation
221   /// type.
222   template <typename AnalysisT, typename OpT>
getAnalysis()223   AnalysisT &getAnalysis() {
224     return getAnalysisManager().getAnalysis<AnalysisT, OpT>();
225   }
226 
227   /// Query a cached instance of an analysis for the current ir unit if one
228   /// exists.
229   template <typename AnalysisT>
getCachedAnalysis()230   Optional<std::reference_wrapper<AnalysisT>> getCachedAnalysis() {
231     return getAnalysisManager().getCachedAnalysis<AnalysisT>();
232   }
233 
234   /// Mark all analyses as preserved.
markAllAnalysesPreserved()235   void markAllAnalysesPreserved() {
236     getPassState().preservedAnalyses.preserveAll();
237   }
238 
239   /// Mark the provided analyses as preserved.
240   template <typename... AnalysesT>
markAnalysesPreserved()241   void markAnalysesPreserved() {
242     getPassState().preservedAnalyses.preserve<AnalysesT...>();
243   }
markAnalysesPreserved(TypeID id)244   void markAnalysesPreserved(TypeID id) {
245     getPassState().preservedAnalyses.preserve(id);
246   }
247 
248   /// Returns the analysis for the given parent operation if it exists.
249   template <typename AnalysisT>
250   Optional<std::reference_wrapper<AnalysisT>>
getCachedParentAnalysis(Operation * parent)251   getCachedParentAnalysis(Operation *parent) {
252     return getAnalysisManager().getCachedParentAnalysis<AnalysisT>(parent);
253   }
254 
255   /// Returns the analysis for the parent operation if it exists.
256   template <typename AnalysisT>
getCachedParentAnalysis()257   Optional<std::reference_wrapper<AnalysisT>> getCachedParentAnalysis() {
258     return getAnalysisManager().getCachedParentAnalysis<AnalysisT>(
259         getOperation()->getParentOp());
260   }
261 
262   /// Returns the analysis for the given child operation if it exists.
263   template <typename AnalysisT>
264   Optional<std::reference_wrapper<AnalysisT>>
getCachedChildAnalysis(Operation * child)265   getCachedChildAnalysis(Operation *child) {
266     return getAnalysisManager().getCachedChildAnalysis<AnalysisT>(child);
267   }
268 
269   /// Returns the analysis for the given child operation, or creates it if it
270   /// doesn't exist.
271   template <typename AnalysisT>
getChildAnalysis(Operation * child)272   AnalysisT &getChildAnalysis(Operation *child) {
273     return getAnalysisManager().getChildAnalysis<AnalysisT>(child);
274   }
275 
276   /// Returns the analysis for the given child operation of specific derived
277   /// operation type, or creates it if it doesn't exist.
278   template <typename AnalysisT, typename OpTy>
getChildAnalysis(OpTy child)279   AnalysisT &getChildAnalysis(OpTy child) {
280     return getAnalysisManager().getChildAnalysis<AnalysisT>(child);
281   }
282 
283   /// Returns the current analysis manager.
getAnalysisManager()284   AnalysisManager getAnalysisManager() {
285     return getPassState().analysisManager;
286   }
287 
288   /// Create a copy of this pass, ignoring statistics and options.
289   virtual std::unique_ptr<Pass> clonePass() const = 0;
290 
291   /// Copy the option values from 'other', which is another instance of this
292   /// pass.
293   void copyOptionValuesFrom(const Pass *other);
294 
295 private:
296   /// Out of line virtual method to ensure vtables and metadata are emitted to a
297   /// single .o file.
298   virtual void anchor();
299 
300   /// Represents a unique identifier for the pass.
301   TypeID passID;
302 
303   /// The name of the operation that this pass operates on, or None if this is a
304   /// generic OperationPass.
305   Optional<StringRef> opName;
306 
307   /// The current execution state for the pass.
308   Optional<detail::PassExecutionState> passState;
309 
310   /// The set of statistics held by this pass.
311   std::vector<Statistic *> statistics;
312 
313   /// The pass options registered to this pass instance.
314   detail::PassOptions passOptions;
315 
316   /// A pointer to the pass this pass was cloned from, if the clone was made by
317   /// the pass manager for the sake of multi-threading.
318   const Pass *threadingSibling = nullptr;
319 
320   /// Allow access to 'clone'.
321   friend class OpPassManager;
322 
323   /// Allow access to 'canScheduleOn'.
324   friend detail::OpPassManagerImpl;
325 
326   /// Allow access to 'passState'.
327   friend detail::OpToOpPassAdaptor;
328 
329   /// Allow access to 'passOptions'.
330   friend class PassInfo;
331 };
332 
333 //===----------------------------------------------------------------------===//
334 // Pass Model Definitions
335 //===----------------------------------------------------------------------===//
336 
337 /// Pass to transform an operation of a specific type.
338 ///
339 /// Operation passes must not:
340 ///   - modify any other operations within the parent region, as other threads
341 ///     may be manipulating them concurrently.
342 ///   - modify any state within the parent operation, this includes adding
343 ///     additional operations.
344 ///
345 /// Derived operation passes are expected to provide the following:
346 ///   - A 'void runOnOperation()' method.
347 ///   - A 'StringRef getName() const' method.
348 ///   - A 'std::unique_ptr<Pass> clonePass() const' method.
349 template <typename OpT = void>
350 class OperationPass : public Pass {
351 protected:
OperationPass(TypeID passID)352   OperationPass(TypeID passID) : Pass(passID, OpT::getOperationName()) {}
353   OperationPass(const OperationPass &) = default;
354 
355   /// Support isa/dyn_cast functionality.
classof(const Pass * pass)356   static bool classof(const Pass *pass) {
357     return pass->getOpName() == OpT::getOperationName();
358   }
359 
360   /// Indicate if the current pass can be scheduled on the given operation type.
canScheduleOn(RegisteredOperationName opName)361   bool canScheduleOn(RegisteredOperationName opName) const final {
362     return opName.getStringRef() == getOpName();
363   }
364 
365   /// Return the current operation being transformed.
getOperation()366   OpT getOperation() { return cast<OpT>(Pass::getOperation()); }
367 
368   /// Query an analysis for the current operation of the specific derived
369   /// operation type.
370   template <typename AnalysisT>
getAnalysis()371   AnalysisT &getAnalysis() {
372     return Pass::getAnalysis<AnalysisT, OpT>();
373   }
374 };
375 
376 /// Pass to transform an operation.
377 ///
378 /// Operation passes must not:
379 ///   - modify any other operations within the parent region, as other threads
380 ///     may be manipulating them concurrently.
381 ///   - modify any state within the parent operation, this includes adding
382 ///     additional operations.
383 ///
384 /// Derived operation passes are expected to provide the following:
385 ///   - A 'void runOnOperation()' method.
386 ///   - A 'StringRef getName() const' method.
387 ///   - A 'std::unique_ptr<Pass> clonePass() const' method.
388 template <>
389 class OperationPass<void> : public Pass {
390 protected:
OperationPass(TypeID passID)391   OperationPass(TypeID passID) : Pass(passID) {}
392   OperationPass(const OperationPass &) = default;
393 
394   /// Indicate if the current pass can be scheduled on the given operation type.
395   /// By default, generic operation passes can be scheduled on any operation.
canScheduleOn(RegisteredOperationName opName)396   bool canScheduleOn(RegisteredOperationName opName) const override {
397     return true;
398   }
399 };
400 
401 /// Pass to transform an operation that implements the given interface.
402 ///
403 /// Interface passes must not:
404 ///   - modify any other operations within the parent region, as other threads
405 ///     may be manipulating them concurrently.
406 ///   - modify any state within the parent operation, this includes adding
407 ///     additional operations.
408 ///
409 /// Derived interface passes are expected to provide the following:
410 ///   - A 'void runOnOperation()' method.
411 ///   - A 'StringRef getName() const' method.
412 ///   - A 'std::unique_ptr<Pass> clonePass() const' method.
413 template <typename InterfaceT>
414 class InterfacePass : public OperationPass<> {
415 protected:
416   using OperationPass::OperationPass;
417 
418   /// Indicate if the current pass can be scheduled on the given operation type.
419   /// For an InterfacePass, this checks if the operation implements the given
420   /// interface.
canScheduleOn(RegisteredOperationName opName)421   bool canScheduleOn(RegisteredOperationName opName) const final {
422     return opName.hasInterface<InterfaceT>();
423   }
424 
425   /// Return the current operation being transformed.
getOperation()426   InterfaceT getOperation() { return cast<InterfaceT>(Pass::getOperation()); }
427 
428   /// Query an analysis for the current operation.
429   template <typename AnalysisT>
getAnalysis()430   AnalysisT &getAnalysis() {
431     return Pass::getAnalysis<AnalysisT, InterfaceT>();
432   }
433 };
434 
435 /// This class provides a CRTP wrapper around a base pass class to define
436 /// several necessary utility methods. This should only be used for passes that
437 /// are not suitably represented using the declarative pass specification(i.e.
438 /// tablegen backend).
439 template <typename PassT, typename BaseT>
440 class PassWrapper : public BaseT {
441 public:
442   /// Support isa/dyn_cast functionality for the derived pass class.
classof(const Pass * pass)443   static bool classof(const Pass *pass) {
444     return pass->getTypeID() == TypeID::get<PassT>();
445   }
446 
447 protected:
PassWrapper()448   PassWrapper() : BaseT(TypeID::get<PassT>()) {}
449   PassWrapper(const PassWrapper &) = default;
450 
451   /// Returns the derived pass name.
getName()452   StringRef getName() const override { return llvm::getTypeName<PassT>(); }
453 
454   /// A clone method to create a copy of this pass.
clonePass()455   std::unique_ptr<Pass> clonePass() const override {
456     return std::make_unique<PassT>(*static_cast<const PassT *>(this));
457   }
458 };
459 
460 } // namespace mlir
461 
462 #endif // MLIR_PASS_PASS_H
463