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