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

source code of mlir/include/mlir/Pass/Pass.h