1# Pass Infrastructure
2
3[TOC]
4
5Passes represent the basic infrastructure for transformation and optimization.
6This document provides an overview of the pass infrastructure in MLIR and how to
7use it.
8
9See [MLIR specification](LangRef.md) for more information about MLIR and its
10core aspects, such as the IR structure and operations.
11
12See [MLIR Rewrites](Tutorials/QuickstartRewrites.md) for a quick start on graph
13rewriting in MLIR. If a transformation involves pattern matching operation DAGs,
14this is a great place to start.
15
16## Operation Pass
17
18In MLIR, the main unit of abstraction and transformation is an
19[operation](LangRef.md/#operations). As such, the pass manager is designed to
20work on instances of operations at different levels of nesting. The structure of
21the [pass manager](#pass-manager), and the concept of nesting, is detailed
22further below. All passes in MLIR derive from `OperationPass` and adhere to the
23following restrictions; any noncompliance will lead to problematic behavior in
24multithreaded and other advanced scenarios:
25
26*   Must not modify any state referenced or relied upon outside the current
27    being operated on. This includes adding or removing operations from the
28    parent block, changing the attributes(depending on the contract of the
29    current operation)/operands/results/successors of the current operation.
30*   Must not modify the state of another operation not nested within the current
31    operation being operated on.
32    *   Other threads may be operating on these operations simultaneously.
33*   Must not inspect the state of sibling operations.
34    *   Other threads may be modifying these operations in parallel.
35    *   Inspecting the state of ancestor/parent operations is permitted.
36*   Must not maintain mutable pass state across invocations of `runOnOperation`.
37    A pass may be run on many different operations with no guarantee of
38    execution order.
39    *   When multithreading, a specific pass instance may not even execute on
40        all operations within the IR. As such, a pass should not rely on running
41        on all operations.
42*   Must not maintain any global mutable state, e.g. static variables within the
43    source file. All mutable state should be maintained by an instance of the
44    pass.
45*   Must be copy-constructible
46    *   Multiple instances of the pass may be created by the pass manager to
47        process operations in parallel.
48
49When creating an operation pass, there are two different types to choose from
50depending on the usage scenario:
51
52### OperationPass : Op-Specific
53
54An `op-specific` operation pass operates explicitly on a given operation type.
55This operation type must adhere to the restrictions set by the pass manager for
56pass execution.
57
58To define an op-specific operation pass, a derived class must adhere to the
59following:
60
61*   Inherit from the CRTP class `OperationPass` and provide the operation type
62    as an additional template parameter.
63*   Override the virtual `void runOnOperation()` method.
64
65A simple pass may look like:
66
67```c++
68namespace {
69/// Here we utilize the CRTP `PassWrapper` utility class to provide some
70/// necessary utility hooks. This is only necessary for passes defined directly
71/// in C++. Passes defined declaratively use a cleaner mechanism for providing
72/// these utilities.
73struct MyFunctionPass : public PassWrapper<MyFunctionPass,
74                                           OperationPass<FuncOp>> {
75  void runOnOperation() override {
76    // Get the current FuncOp operation being operated on.
77    FuncOp f = getOperation();
78
79    // Walk the operations within the function.
80    f.walk([](Operation *inst) {
81      ....
82    });
83  }
84};
85} // namespace
86
87/// Register this pass so that it can be built via from a textual pass pipeline.
88/// (Pass registration is discussed more below)
89void registerMyPass() {
90  PassRegistration<MyFunctionPass>();
91}
92```
93
94### OperationPass : Op-Agnostic
95
96An `op-agnostic` pass operates on the operation type of the pass manager that it
97is added to. This means that passes of this type may operate on several
98different operation types. Passes of this type are generally written generically
99using operation [interfaces](Interfaces.md) and [traits](Traits.md). Examples of
100this type of pass are
101[Common Sub-Expression Elimination](Passes.md/#-cse-eliminate-common-sub-expressions)
102and [Inlining](Passes.md/#-inline-inline-function-calls).
103
104To create an operation pass, a derived class must adhere to the following:
105
106*   Inherit from the CRTP class `OperationPass`.
107*   Override the virtual `void runOnOperation()` method.
108
109A simple pass may look like:
110
111```c++
112/// Here we utilize the CRTP `PassWrapper` utility class to provide some
113/// necessary utility hooks. This is only necessary for passes defined directly
114/// in C++. Passes defined declaratively use a cleaner mechanism for providing
115/// these utilities.
116struct MyOperationPass : public PassWrapper<MyOperationPass, OperationPass<>> {
117  void runOnOperation() override {
118    // Get the current operation being operated on.
119    Operation *op = getOperation();
120    ...
121  }
122};
123```
124
125### Dependent Dialects
126
127Dialects must be loaded in the MLIRContext before entities from these dialects
128(operations, types, attributes, ...) can be created. Dialects must also be
129loaded before starting the execution of a multi-threaded pass pipeline. To this
130end, a pass that may create an entity from a dialect that isn't guaranteed to
131already ne loaded must express this by overriding the `getDependentDialects()`
132method and declare this list of Dialects explicitly.
133
134### Initialization
135
136In certain situations, a Pass may contain state that is constructed dynamically,
137but is potentially expensive to recompute in successive runs of the Pass. One
138such example is when using [`PDL`-based](Dialects/PDLOps.md)
139[patterns](PatternRewriter.md), which are compiled into a bytecode during
140runtime. In these situations, a pass may override the following hook to
141initialize this heavy state:
142
143*   `LogicalResult initialize(MLIRContext *context)`
144
145This hook is executed once per run of a full pass pipeline, meaning that it does
146not have access to the state available during a `runOnOperation` call. More
147concretely, all necessary accesses to an `MLIRContext` should be driven via the
148provided `context` parameter, and methods that utilize "per-run" state such as
149`getContext`/`getOperation`/`getAnalysis`/etc. must not be used.
150In case of an error during initialization, the pass is expected to emit an error
151diagnostic and return a `failure()` which will abort the pass pipeline execution.
152
153## Analysis Management
154
155An important concept, along with transformation passes, are analyses. These are
156conceptually similar to transformation passes, except that they compute
157information on a specific operation without modifying it. In MLIR, analyses are
158not passes but free-standing classes that are computed lazily on-demand and
159cached to avoid unnecessary recomputation. An analysis in MLIR must adhere to
160the following:
161
162*   Provide a valid constructor taking either an `Operation*` or `Operation*`
163    and `AnalysisManager &`.
164    *   The provided `AnalysisManager &` should be used to query any necessary
165        analysis dependencies.
166*   Must not modify the given operation.
167
168An analysis may provide additional hooks to control various behavior:
169
170*   `bool isInvalidated(const AnalysisManager::PreservedAnalyses &)`
171
172Given a preserved analysis set, the analysis returns true if it should truly be
173invalidated. This allows for more fine-tuned invalidation in cases where an
174analysis wasn't explicitly marked preserved, but may be preserved (or
175invalidated) based upon other properties such as analyses sets. If the analysis
176uses any other analysis as a dependency, it must also check if the dependency
177was invalidated.
178
179### Querying Analyses
180
181The base `OperationPass` class provides utilities for querying and preserving
182analyses for the current operation being processed.
183
184*   OperationPass automatically provides the following utilities for querying
185    analyses:
186    *   `getAnalysis<>`
187        -   Get an analysis for the current operation, constructing it if
188            necessary.
189    *   `getCachedAnalysis<>`
190        -   Get an analysis for the current operation, if it already exists.
191    *   `getCachedParentAnalysis<>`
192        -   Get an analysis for a given parent operation, if it exists.
193    *   `getCachedChildAnalysis<>`
194        -   Get an analysis for a given child operation, if it exists.
195    *   `getChildAnalysis<>`
196        -   Get an analysis for a given child operation, constructing it if
197            necessary.
198
199Using the example passes defined above, let's see some examples:
200
201```c++
202/// An interesting analysis.
203struct MyOperationAnalysis {
204  // Compute this analysis with the provided operation.
205  MyOperationAnalysis(Operation *op);
206};
207
208struct MyOperationAnalysisWithDependency {
209  MyOperationAnalysisWithDependency(Operation *op, AnalysisManager &am) {
210    // Request other analysis as dependency
211    MyOperationAnalysis &otherAnalysis = am.getAnalysis<MyOperationAnalysis>();
212    ...
213  }
214
215  bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
216    // Check if analysis or its dependency were invalidated
217    return !pa.isPreserved<MyOperationAnalysisWithDependency>() ||
218           !pa.isPreserved<MyOperationAnalysis>();
219  }
220};
221
222void MyOperationPass::runOnOperation() {
223  // Query MyOperationAnalysis for the current operation.
224  MyOperationAnalysis &myAnalysis = getAnalysis<MyOperationAnalysis>();
225
226  // Query a cached instance of MyOperationAnalysis for the current operation.
227  // It will not be computed if it doesn't exist.
228  auto optionalAnalysis = getCachedAnalysis<MyOperationAnalysis>();
229  if (optionalAnalysis)
230    ...
231
232  // Query a cached instance of MyOperationAnalysis for the parent operation of
233  // the current operation. It will not be computed if it doesn't exist.
234  auto optionalAnalysis = getCachedParentAnalysis<MyOperationAnalysis>();
235  if (optionalAnalysis)
236    ...
237}
238```
239
240### Preserving Analyses
241
242Analyses that are constructed after being queried by a pass are cached to avoid
243unnecessary computation if they are requested again later. To avoid stale
244analyses, all analyses are assumed to be invalidated by a pass. To avoid
245invalidation, a pass must specifically mark analyses that are known to be
246preserved.
247
248*   All Pass classes automatically provide the following utilities for
249    preserving analyses:
250    *   `markAllAnalysesPreserved`
251    *   `markAnalysesPreserved<>`
252
253```c++
254void MyOperationPass::runOnOperation() {
255  // Mark all analyses as preserved. This is useful if a pass can guarantee
256  // that no transformation was performed.
257  markAllAnalysesPreserved();
258
259  // Mark specific analyses as preserved. This is used if some transformation
260  // was performed, but some analyses were either unaffected or explicitly
261  // preserved.
262  markAnalysesPreserved<MyAnalysis, MyAnalyses...>();
263}
264```
265
266## Pass Failure
267
268Passes in MLIR are allowed to gracefully fail. This may happen if some invariant
269of the pass was broken, potentially leaving the IR in some invalid state. If
270such a situation occurs, the pass can directly signal a failure to the pass
271manager via the `signalPassFailure` method. If a pass signaled a failure when
272executing, no other passes in the pipeline will execute and the top-level call
273to `PassManager::run` will return `failure`.
274
275```c++
276void MyOperationPass::runOnOperation() {
277  // Signal failure on a broken invariant.
278  if (some_broken_invariant)
279    return signalPassFailure();
280}
281```
282
283## Pass Manager
284
285The above sections introduced the different types of passes and their
286invariants. This section introduces the concept of a PassManager, and how it can
287be used to configure and schedule a pass pipeline. There are two main classes
288related to pass management, the `PassManager` and the `OpPassManager`. The
289`PassManager` class acts as the top-level entry point, and contains various
290configurations used for the entire pass pipeline. The `OpPassManager` class is
291used to schedule passes to run at a specific level of nesting. The top-level
292`PassManager` also functions as an `OpPassManager`.
293
294### OpPassManager
295
296An `OpPassManager` is essentially a collection of passes to execute on an
297operation of a specific type. This operation type must adhere to the following
298requirement:
299
300*   Must be registered and marked
301    [`IsolatedFromAbove`](Traits.md/#isolatedfromabove).
302
303    *   Passes are expected to not modify operations at or above the current
304        operation being processed. If the operation is not isolated, it may
305        inadvertently modify or traverse the SSA use-list of an operation it is
306        not supposed to.
307
308Passes can be added to a pass manager via `addPass`. The pass must either be an
309`op-specific` pass operating on the same operation type as `OpPassManager`, or
310an `op-agnostic` pass.
311
312An `OpPassManager` is generally created by explicitly nesting a pipeline within
313another existing `OpPassManager` via the `nest<>` method. This method takes the
314operation type that the nested pass manager will operate on. At the top-level, a
315`PassManager` acts as an `OpPassManager`. Nesting in this sense, corresponds to
316the [structural](Tutorials/UnderstandingTheIRStructure.md) nesting within
317[Regions](LangRef.md/#regions) of the IR.
318
319For example, the following `.mlir`:
320
321```
322module {
323  spv.module "Logical" "GLSL450" {
324    func @foo() {
325      ...
326    }
327  }
328}
329```
330
331Has the nesting structure of:
332
333```
334`module`
335  `spv.module`
336    `function`
337```
338
339Below is an example of constructing a pipeline that operates on the above
340structure:
341
342```c++
343// Create a top-level `PassManager` class. If an operation type is not
344// explicitly specific, the default is the builtin `module` operation.
345PassManager pm(ctx);
346// Note: We could also create the above `PassManager` this way.
347PassManager pm(ctx, /*operationName=*/"builtin.module");
348
349// Add a pass on the top-level module operation.
350pm.addPass(std::make_unique<MyModulePass>());
351
352// Nest a pass manager that operates on `spirv.module` operations nested
353// directly under the top-level module.
354OpPassManager &nestedModulePM = pm.nest<spirv::ModuleOp>();
355nestedModulePM.addPass(std::make_unique<MySPIRVModulePass>());
356
357// Nest a pass manager that operates on functions within the nested SPIRV
358// module.
359OpPassManager &nestedFunctionPM = nestedModulePM.nest<FuncOp>();
360nestedFunctionPM.addPass(std::make_unique<MyFunctionPass>());
361
362// Run the pass manager on the top-level module.
363ModuleOp m = ...;
364if (failed(pm.run(m)))
365    ... // One of the passes signaled a failure.
366```
367
368The above pass manager contains the following pipeline structure:
369
370```
371OpPassManager<ModuleOp>
372  MyModulePass
373  OpPassManager<spirv::ModuleOp>
374    MySPIRVModulePass
375    OpPassManager<FuncOp>
376      MyFunctionPass
377```
378
379These pipelines are then run over a single operation at a time. This means that,
380for example, given a series of consecutive passes on FuncOp, it will execute all
381on the first function, then all on the second function, etc. until the entire
382program has been run through the passes. This provides several benefits:
383
384*   This improves the cache behavior of the compiler, because it is only
385    touching a single function at a time, instead of traversing the entire
386    program.
387*   This improves multi-threading performance by reducing the number of jobs
388    that need to be scheduled, as well as increasing the efficiency of each job.
389    An entire function pipeline can be run on each function asynchronously.
390
391## Dynamic Pass Pipelines
392
393In some situations it may be useful to run a pass pipeline within another pass,
394to allow configuring or filtering based on some invariants of the current
395operation being operated on. For example, the
396[Inliner Pass](Passes.md/#-inline-inline-function-calls) may want to run
397intraprocedural simplification passes while it is inlining to produce a better
398cost model, and provide more optimal inlining. To enable this, passes may run an
399arbitrary `OpPassManager` on the current operation being operated on or any
400operation nested within the current operation via the `LogicalResult
401Pass::runPipeline(OpPassManager &, Operation *)` method. This method returns
402whether the dynamic pipeline succeeded or failed, similarly to the result of the
403top-level `PassManager::run` method. A simple example is shown below:
404
405```c++
406void MyModulePass::runOnOperation() {
407  ModuleOp module = getOperation();
408  if (hasSomeSpecificProperty(module)) {
409    OpPassManager dynamicPM("builtin.module");
410    ...; // Build the dynamic pipeline.
411    if (failed(runPipeline(dynamicPM, module)))
412      return signalPassFailure();
413  }
414}
415```
416
417Note: though above the dynamic pipeline was constructed within the
418`runOnOperation` method, this is not necessary and pipelines should be cached
419when possible as the `OpPassManager` class can be safely copy constructed.
420
421The mechanism described in this section should be used whenever a pass pipeline
422should run in a nested fashion, i.e. when the nested pipeline cannot be
423scheduled statically along with the rest of the main pass pipeline. More
424specifically, a `PassManager` should generally never need to be constructed
425within a `Pass`. Using `runPipeline` also ensures that all analyses,
426[instrumentations](#pass-instrumentation), and other pass manager related
427components are integrated with the dynamic pipeline being executed.
428
429## Instance Specific Pass Options
430
431MLIR provides a builtin mechanism for passes to specify options that configure
432its behavior. These options are parsed at pass construction time independently
433for each instance of the pass. Options are defined using the `Option<>` and
434`ListOption<>` classes, and follow the
435[LLVM command line](https://llvm.org/docs/CommandLine.html) flag definition
436rules. See below for a few examples:
437
438```c++
439struct MyPass ... {
440  /// Make sure that we have a valid default constructor and copy constructor to
441  /// ensure that the options are initialized properly.
442  MyPass() = default;
443  MyPass(const MyPass& pass) {}
444
445  /// Any parameters after the description are forwarded to llvm::cl::list and
446  /// llvm::cl::opt respectively.
447  Option<int> exampleOption{*this, "flag-name", llvm::cl::desc("...")};
448  ListOption<int> exampleListOption{*this, "list-flag-name",
449                                    llvm::cl::desc("...")};
450};
451```
452
453For pass pipelines, the `PassPipelineRegistration` templates take an additional
454template parameter for an optional `Option` struct definition. This struct
455should inherit from `mlir::PassPipelineOptions` and contain the desired pipeline
456options. When using `PassPipelineRegistration`, the constructor now takes a
457function with the signature `void (OpPassManager &pm, const MyPipelineOptions&)`
458which should construct the passes from the options and pass them to the pm:
459
460```c++
461struct MyPipelineOptions : public PassPipelineOptions {
462  // The structure of these options is the same as those for pass options.
463  Option<int> exampleOption{*this, "flag-name", llvm::cl::desc("...")};
464  ListOption<int> exampleListOption{*this, "list-flag-name",
465                                    llvm::cl::desc("...")};
466};
467
468void registerMyPasses() {
469  PassPipelineRegistration<MyPipelineOptions>(
470    "example-pipeline", "Run an example pipeline.",
471    [](OpPassManager &pm, const MyPipelineOptions &pipelineOptions) {
472      // Initialize the pass manager.
473    });
474}
475```
476
477## Pass Statistics
478
479Statistics are a way to keep track of what the compiler is doing and how
480effective various transformations are. It is often useful to see what effect
481specific transformations have on a particular input, and how often they trigger.
482Pass statistics are specific to each pass instance, which allow for seeing the
483effect of placing a particular transformation at specific places within the pass
484pipeline. For example, they help answer questions like "What happens if I run
485CSE again here?".
486
487Statistics can be added to a pass by using the 'Pass::Statistic' class. This
488class takes as a constructor arguments: the parent pass, a name, and a
489description. This class acts like an atomic unsigned integer, and may be
490incremented and updated accordingly. These statistics rely on the same
491infrastructure as
492[`llvm::Statistic`](http://llvm.org/docs/ProgrammersManual.html#the-statistic-class-stats-option)
493and thus have similar usage constraints. Collected statistics can be dumped by
494the [pass manager](#pass-manager) programmatically via
495`PassManager::enableStatistics`; or via `-pass-statistics` and
496`-pass-statistics-display` on the command line.
497
498An example is shown below:
499
500```c++
501struct MyPass ... {
502  /// Make sure that we have a valid default constructor and copy constructor to
503  /// ensure that the options are initialized properly.
504  MyPass() = default;
505  MyPass(const MyPass& pass) {}
506  StringRef getArgument() const final {
507    // This is the argument used to refer to the pass in
508    // the textual format (on the commandline for example).
509    return "argument";
510  }
511  StringRef getDescription() const final {
512    // This is a brief description of the pass.
513    return  "description";
514  }
515  /// Define the statistic to track during the execution of MyPass.
516  Statistic exampleStat{this, "exampleStat", "An example statistic"};
517
518  void runOnOperation() {
519    ...
520
521    // Update the statistic after some invariant was hit.
522    ++exampleStat;
523
524    ...
525  }
526};
527```
528
529The collected statistics may be aggregated in two types of views:
530
531A pipeline view that models the structure of the pass manager, this is the
532default view:
533
534```shell
535$ mlir-opt -pass-pipeline='func.func(my-pass,my-pass)' foo.mlir -pass-statistics
536
537===-------------------------------------------------------------------------===
538                         ... Pass statistics report ...
539===-------------------------------------------------------------------------===
540'func.func' Pipeline
541  MyPass
542    (S) 15 exampleStat - An example statistic
543  VerifierPass
544  MyPass
545    (S)  6 exampleStat - An example statistic
546  VerifierPass
547VerifierPass
548```
549
550A list view that aggregates the statistics of all instances of a specific pass
551together:
552
553```shell
554$ mlir-opt -pass-pipeline='func.func(my-pass, my-pass)' foo.mlir -pass-statistics -pass-statistics-display=list
555
556===-------------------------------------------------------------------------===
557                         ... Pass statistics report ...
558===-------------------------------------------------------------------------===
559MyPass
560  (S) 21 exampleStat - An example statistic
561```
562
563## Pass Registration
564
565Briefly shown in the example definitions of the various pass types is the
566`PassRegistration` class. This mechanism allows for registering pass classes so
567that they may be created within a
568[textual pass pipeline description](#textual-pass-pipeline-specification). An
569example registration is shown below:
570
571```c++
572void registerMyPass() {
573  PassRegistration<MyPass>();
574}
575```
576
577*   `MyPass` is the name of the derived pass class.
578*   The pass `getArgument()` method is used to get the identifier that will be
579    used to refer to the pass.
580*   The pass `getDescription()` method provides a short summary describing the
581    pass.
582
583For passes that cannot be default-constructed, `PassRegistration` accepts an
584optional argument that takes a callback to create the pass:
585
586```c++
587void registerMyPass() {
588  PassRegistration<MyParametricPass>(
589    []() -> std::unique_ptr<Pass> {
590      std::unique_ptr<Pass> p = std::make_unique<MyParametricPass>(/*options*/);
591      /*... non-trivial-logic to configure the pass ...*/;
592      return p;
593    });
594}
595```
596
597This variant of registration can be used, for example, to accept the
598configuration of a pass from command-line arguments and pass it to the pass
599constructor.
600
601Note: Make sure that the pass is copy-constructible in a way that does not share
602data as the [pass manager](#pass-manager) may create copies of the pass to run
603in parallel.
604
605### Pass Pipeline Registration
606
607Described above is the mechanism used for registering a specific derived pass
608class. On top of that, MLIR allows for registering custom pass pipelines in a
609similar fashion. This allows for custom pipelines to be available to tools like
610mlir-opt in the same way that passes are, which is useful for encapsulating
611common pipelines like the "-O1" series of passes. Pipelines are registered via a
612similar mechanism to passes in the form of `PassPipelineRegistration`. Compared
613to `PassRegistration`, this class takes an additional parameter in the form of a
614pipeline builder that modifies a provided `OpPassManager`.
615
616```c++
617void pipelineBuilder(OpPassManager &pm) {
618  pm.addPass(std::make_unique<MyPass>());
619  pm.addPass(std::make_unique<MyOtherPass>());
620}
621
622void registerMyPasses() {
623  // Register an existing pipeline builder function.
624  PassPipelineRegistration<>(
625    "argument", "description", pipelineBuilder);
626
627  // Register an inline pipeline builder.
628  PassPipelineRegistration<>(
629    "argument", "description", [](OpPassManager &pm) {
630      pm.addPass(std::make_unique<MyPass>());
631      pm.addPass(std::make_unique<MyOtherPass>());
632    });
633}
634```
635
636### Textual Pass Pipeline Specification
637
638The previous sections detailed how to register passes and pass pipelines with a
639specific argument and description. Once registered, these can be used to
640configure a pass manager from a string description. This is especially useful
641for tools like `mlir-opt`, that configure pass managers from the command line,
642or as options to passes that utilize
643[dynamic pass pipelines](#dynamic-pass-pipelines).
644
645To support the ability to describe the full structure of pass pipelines, MLIR
646supports a custom textual description of pass pipelines. The textual description
647includes the nesting structure, the arguments of the passes and pass pipelines
648to run, and any options for those passes and pipelines. A textual pipeline is
649defined as a series of names, each of which may in itself recursively contain a
650nested pipeline description. The syntax for this specification is as follows:
651
652```ebnf
653pipeline          ::= op-name `(` pipeline-element (`,` pipeline-element)* `)`
654pipeline-element  ::= pipeline | (pass-name | pass-pipeline-name) options?
655options           ::= '{' (key ('=' value)?)+ '}'
656```
657
658*   `op-name`
659    *   This corresponds to the mnemonic name of an operation to run passes on,
660        e.g. `func.func` or `builtin.module`.
661*   `pass-name` | `pass-pipeline-name`
662    *   This corresponds to the argument of a registered pass or pass pipeline,
663        e.g. `cse` or `canonicalize`.
664*   `options`
665    *   Options are specific key value pairs representing options defined by a
666        pass or pass pipeline, as described in the
667        ["Instance Specific Pass Options"](#instance-specific-pass-options)
668        section. See this section for an example usage in a textual pipeline.
669
670For example, the following pipeline:
671
672```shell
673$ mlir-opt foo.mlir -cse -canonicalize -convert-func-to-llvm='use-bare-ptr-memref-call-conv=1'
674```
675
676Can also be specified as (via the `-pass-pipeline` flag):
677
678```shell
679$ mlir-opt foo.mlir -pass-pipeline='func.func(cse,canonicalize),convert-func-to-llvm{use-bare-ptr-memref-call-conv=1}'
680```
681
682In order to support round-tripping a pass to the textual representation using
683`OpPassManager::printAsTextualPipeline(raw_ostream&)`, override `StringRef
684Pass::getArgument()` to specify the argument used when registering a pass.
685
686## Declarative Pass Specification
687
688Some aspects of a Pass may be specified declaratively, in a form similar to
689[operations](OpDefinitions.md). This specification simplifies several mechanisms
690used when defining passes. It can be used for generating pass registration
691calls, defining boilerplate pass utilities, and generating pass documentation.
692
693Consider the following pass specified in C++:
694
695```c++
696struct MyPass : PassWrapper<MyPass, OperationPass<ModuleOp>> {
697  MyPass() = default;
698  MyPass(const MyPass &) {}
699
700  ...
701
702  // Specify any options.
703  Option<bool> option{
704      *this, "example-option",
705      llvm::cl::desc("An example option"), llvm::cl::init(true)};
706  ListOption<int64_t> listOption{
707      *this, "example-list",
708      llvm::cl::desc("An example list option"), llvm::cl::ZeroOrMore,
709      llvm::cl::MiscFlags::CommaSeparated};
710
711  // Specify any statistics.
712  Statistic statistic{this, "example-statistic", "An example statistic"};
713};
714
715/// Expose this pass to the outside world.
716std::unique_ptr<Pass> foo::createMyPass() {
717  return std::make_unique<MyPass>();
718}
719
720/// Register this pass.
721void foo::registerMyPass() {
722  PassRegistration<MyPass>();
723}
724```
725
726This pass may be specified declaratively as so:
727
728```tablegen
729def MyPass : Pass<"my-pass", "ModuleOp"> {
730  let summary = "My Pass Summary";
731  let description = [{
732    Here we can now give a much larger description of `MyPass`, including all of
733    its various constraints and behavior.
734  }];
735
736  // A constructor must be provided to specify how to create a default instance
737  // of MyPass.
738  let constructor = "foo::createMyPass()";
739
740  // Specify any options.
741  let options = [
742    Option<"option", "example-option", "bool", /*default=*/"true",
743           "An example option">,
744    ListOption<"listOption", "example-list", "int64_t",
745               "An example list option",
746               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">
747  ];
748
749  // Specify any statistics.
750  let statistics = [
751    Statistic<"statistic", "example-statistic", "An example statistic">
752  ];
753}
754```
755
756Using the `gen-pass-decls` generator, we can generate most of the boilerplate
757above automatically. This generator takes as an input a `-name` parameter, that
758provides a tag for the group of passes that are being generated. This generator
759produces two chunks of output:
760
761The first is a code block for registering the declarative passes with the global
762registry. For each pass, the generator produces a `registerFooPass` where `Foo`
763is the name of the definition specified in tablegen. It also generates a
764`registerGroupPasses`, where `Group` is the tag provided via the `-name` input
765parameter, that registers all of the passes present.
766
767```c++
768// gen-pass-decls -name="Example"
769
770#define GEN_PASS_REGISTRATION
771#include "Passes.h.inc"
772
773void registerMyPasses() {
774  // Register all of the passes.
775  registerExamplePasses();
776
777  // Register `MyPass` specifically.
778  registerMyPassPass();
779}
780```
781
782The second is a base class for each of the passes, containing most of the boiler
783plate related to pass definitions. These classes are named in the form of
784`MyPassBase`, where `MyPass` is the name of the pass definition in tablegen. We
785can update the original C++ pass definition as so:
786
787```c++
788/// Include the generated base pass class definitions.
789#define GEN_PASS_CLASSES
790#include "Passes.h.inc"
791
792/// Define the main class as deriving from the generated base class.
793struct MyPass : MyPassBase<MyPass> {
794  /// The explicit constructor is no longer explicitly necessary when defining
795  /// pass options and statistics, the base class takes care of that
796  /// automatically.
797  ...
798
799  /// The definitions of the options and statistics are now generated within
800  /// the base class, but are accessible in the same way.
801};
802
803/// Expose this pass to the outside world.
804std::unique_ptr<Pass> foo::createMyPass() {
805  return std::make_unique<MyPass>();
806}
807```
808
809Using the `gen-pass-doc` generator, markdown documentation for each of the
810passes can be generated. See [Passes.md](Passes.md) for example output of real
811MLIR passes.
812
813### Tablegen Specification
814
815The `Pass` class is used to begin a new pass definition. This class takes as an
816argument the registry argument to attribute to the pass, as well as an optional
817string corresponding to the operation type that the pass operates on. The class
818contains the following fields:
819
820*   `summary`
821    -   A short one line summary of the pass, used as the description when
822        registering the pass.
823*   `description`
824    -   A longer, more detailed description of the pass. This is used when
825        generating pass documentation.
826*   `dependentDialects`
827    -   A list of strings representing the `Dialect` classes this pass may
828        introduce entities, Attributes/Operations/Types/etc., of.
829*   `constructor`
830    -   A code block used to create a default instance of the pass.
831*   `options`
832    -   A list of pass options used by the pass.
833*   `statistics`
834    -   A list of pass statistics used by the pass.
835
836#### Options
837
838Options may be specified via the `Option` and `ListOption` classes. The `Option`
839class takes the following template parameters:
840
841*   C++ variable name
842    -   A name to use for the generated option variable.
843*   argument
844    -   The argument name of the option.
845*   type
846    -   The C++ type of the option.
847*   default value
848    -   The default option value.
849*   description
850    -   A one line description of the option.
851*   additional option flags
852    -   A string containing any additional options necessary to construct the
853        option.
854
855```tablegen
856def MyPass : Pass<"my-pass"> {
857  let options = [
858    Option<"option", "example-option", "bool", /*default=*/"true",
859           "An example option">,
860  ];
861}
862```
863
864The `ListOption` class takes the following fields:
865
866*   C++ variable name
867    -   A name to use for the generated option variable.
868*   argument
869    -   The argument name of the option.
870*   element type
871    -   The C++ type of the list element.
872*   description
873    -   A one line description of the option.
874*   additional option flags
875    -   A string containing any additional options necessary to construct the
876        option.
877
878```tablegen
879def MyPass : Pass<"my-pass"> {
880  let options = [
881    ListOption<"listOption", "example-list", "int64_t",
882               "An example list option",
883               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">
884  ];
885}
886```
887
888#### Statistic
889
890Statistics may be specified via the `Statistic`, which takes the following
891template parameters:
892
893*   C++ variable name
894    -   A name to use for the generated statistic variable.
895*   display name
896    -   The name used when displaying the statistic.
897*   description
898    -   A one line description of the statistic.
899
900```tablegen
901def MyPass : Pass<"my-pass"> {
902  let statistics = [
903    Statistic<"statistic", "example-statistic", "An example statistic">
904  ];
905}
906```
907
908## Pass Instrumentation
909
910MLIR provides a customizable framework to instrument pass execution and analysis
911computation, via the `PassInstrumentation` class. This class provides hooks into
912the PassManager that observe various events:
913
914*   `runBeforePipeline`
915    *   This callback is run just before a pass pipeline, i.e. pass manager, is
916        executed.
917*   `runAfterPipeline`
918    *   This callback is run right after a pass pipeline has been executed,
919        successfully or not.
920*   `runBeforePass`
921    *   This callback is run just before a pass is executed.
922*   `runAfterPass`
923    *   This callback is run right after a pass has been successfully executed.
924        If this hook is executed, `runAfterPassFailed` will *not* be.
925*   `runAfterPassFailed`
926    *   This callback is run right after a pass execution fails. If this hook is
927        executed, `runAfterPass` will *not* be.
928*   `runBeforeAnalysis`
929    *   This callback is run just before an analysis is computed.
930    *   If the analysis requested another analysis as a dependency, the
931        `runBeforeAnalysis`/`runAfterAnalysis` pair for the dependency can be
932        called from inside of the current `runBeforeAnalysis`/`runAfterAnalysis`
933        pair.
934*   `runAfterAnalysis`
935    *   This callback is run right after an analysis is computed.
936
937PassInstrumentation instances may be registered directly with a
938[PassManager](#pass-manager) instance via the `addInstrumentation` method.
939Instrumentations added to the PassManager are run in a stack like fashion, i.e.
940the last instrumentation to execute a `runBefore*` hook will be the first to
941execute the respective `runAfter*` hook. The hooks of a `PassInstrumentation`
942class are guaranteed to be executed in a thread safe fashion, so additional
943synchronization is not necessary. Below in an example instrumentation that
944counts the number of times the `DominanceInfo` analysis is computed:
945
946```c++
947struct DominanceCounterInstrumentation : public PassInstrumentation {
948  /// The cumulative count of how many times dominance has been calculated.
949  unsigned &count;
950
951  DominanceCounterInstrumentation(unsigned &count) : count(count) {}
952  void runAfterAnalysis(llvm::StringRef, TypeID id, Operation *) override {
953    if (id == TypeID::get<DominanceInfo>())
954      ++count;
955  }
956};
957
958MLIRContext *ctx = ...;
959PassManager pm(ctx);
960
961// Add the instrumentation to the pass manager.
962unsigned domInfoCount;
963pm.addInstrumentation(
964    std::make_unique<DominanceCounterInstrumentation>(domInfoCount));
965
966// Run the pass manager on a module operation.
967ModuleOp m = ...;
968if (failed(pm.run(m)))
969    ...
970
971llvm::errs() << "DominanceInfo was computed " << domInfoCount << " times!\n";
972```
973
974### Standard Instrumentations
975
976MLIR utilizes the pass instrumentation framework to provide a few useful
977developer tools and utilities. Each of these instrumentations are directly
978available to all users of the MLIR pass framework.
979
980#### Pass Timing
981
982The PassTiming instrumentation provides timing information about the execution
983of passes and computation of analyses. This provides a quick glimpse into what
984passes are taking the most time to execute, as well as how much of an effect a
985pass has on the total execution time of the pipeline. Users can enable this
986instrumentation directly on the PassManager via `enableTiming`. This
987instrumentation is also made available in mlir-opt via the `-mlir-timing` flag.
988The PassTiming instrumentation provides several different display modes for the
989timing results, each of which is described below:
990
991##### List Display Mode
992
993In this mode, the results are displayed in a list sorted by total time with each
994pass/analysis instance aggregated into one unique result. This view is useful
995for getting an overview of what analyses/passes are taking the most time in a
996pipeline. This display mode is available in mlir-opt via
997`-mlir-timing-display=list`.
998
999```shell
1000$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func.func(cse,canonicalize)' -convert-func-to-llvm -mlir-timing -mlir-timing-display=list
1001
1002===-------------------------------------------------------------------------===
1003                      ... Pass execution timing report ...
1004===-------------------------------------------------------------------------===
1005  Total Execution Time: 0.0203 seconds
1006
1007   ---Wall Time---  --- Name ---
1008   0.0047 ( 55.9%)  Canonicalizer
1009   0.0019 ( 22.2%)  VerifierPass
1010   0.0016 ( 18.5%)  LLVMLoweringPass
1011   0.0003 (  3.4%)  CSE
1012   0.0002 (  1.9%)  (A) DominanceInfo
1013   0.0084 (100.0%)  Total
1014```
1015
1016##### Tree Display Mode
1017
1018In this mode, the results are displayed in a nested pipeline view that mirrors
1019the internal pass pipeline that is being executed in the pass manager. This view
1020is useful for understanding specifically which parts of the pipeline are taking
1021the most time, and can also be used to identify when analyses are being
1022invalidated and recomputed. This is the default display mode.
1023
1024```shell
1025$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func.func(cse,canonicalize)' -convert-func-to-llvm -mlir-timing
1026
1027===-------------------------------------------------------------------------===
1028                      ... Pass execution timing report ...
1029===-------------------------------------------------------------------------===
1030  Total Execution Time: 0.0249 seconds
1031
1032   ---Wall Time---  --- Name ---
1033   0.0058 ( 70.8%)  'func.func' Pipeline
1034   0.0004 (  4.3%)    CSE
1035   0.0002 (  2.6%)      (A) DominanceInfo
1036   0.0004 (  4.8%)    VerifierPass
1037   0.0046 ( 55.4%)    Canonicalizer
1038   0.0005 (  6.2%)    VerifierPass
1039   0.0005 (  5.8%)  VerifierPass
1040   0.0014 ( 17.2%)  LLVMLoweringPass
1041   0.0005 (  6.2%)  VerifierPass
1042   0.0082 (100.0%)  Total
1043```
1044
1045##### Multi-threaded Pass Timing
1046
1047When multi-threading is enabled in the pass manager the meaning of the display
1048slightly changes. First, a new timing column is added, `User Time`, that
1049displays the total time spent across all threads. Secondly, the `Wall Time`
1050column displays the longest individual time spent amongst all of the threads.
1051This means that the `Wall Time` column will continue to give an indicator on the
1052perceived time, or clock time, whereas the `User Time` will display the total
1053cpu time.
1054
1055```shell
1056$ mlir-opt foo.mlir -pass-pipeline='func.func(cse,canonicalize)' -convert-func-to-llvm -mlir-timing
1057
1058===-------------------------------------------------------------------------===
1059                      ... Pass execution timing report ...
1060===-------------------------------------------------------------------------===
1061  Total Execution Time: 0.0078 seconds
1062
1063   ---User Time---   ---Wall Time---  --- Name ---
1064   0.0177 ( 88.5%)     0.0057 ( 71.3%)  'func.func' Pipeline
1065   0.0044 ( 22.0%)     0.0015 ( 18.9%)    CSE
1066   0.0029 ( 14.5%)     0.0012 ( 15.2%)      (A) DominanceInfo
1067   0.0038 ( 18.9%)     0.0015 ( 18.7%)    VerifierPass
1068   0.0089 ( 44.6%)     0.0025 ( 31.1%)    Canonicalizer
1069   0.0006 (  3.0%)     0.0002 (  2.6%)    VerifierPass
1070   0.0004 (  2.2%)     0.0004 (  5.4%)  VerifierPass
1071   0.0013 (  6.5%)     0.0013 ( 16.3%)  LLVMLoweringPass
1072   0.0006 (  2.8%)     0.0006 (  7.0%)  VerifierPass
1073   0.0200 (100.0%)     0.0081 (100.0%)  Total
1074```
1075
1076#### IR Printing
1077
1078When debugging it is often useful to dump the IR at various stages of a pass
1079pipeline. This is where the IR printing instrumentation comes into play. This
1080instrumentation allows for conditionally printing the IR before and after pass
1081execution by optionally filtering on the pass being executed. This
1082instrumentation can be added directly to the PassManager via the
1083`enableIRPrinting` method. `mlir-opt` provides a few useful flags for utilizing
1084this instrumentation:
1085
1086*   `print-ir-before=(comma-separated-pass-list)`
1087    *   Print the IR before each of the passes provided within the pass list.
1088*   `print-ir-before-all`
1089    *   Print the IR before every pass in the pipeline.
1090
1091```shell
1092$ mlir-opt foo.mlir -pass-pipeline='func.func(cse)' -print-ir-before=cse
1093
1094*** IR Dump Before CSE ***
1095func @simple_constant() -> (i32, i32) {
1096  %c1_i32 = arith.constant 1 : i32
1097  %c1_i32_0 = arith.constant 1 : i32
1098  return %c1_i32, %c1_i32_0 : i32, i32
1099}
1100```
1101
1102*   `print-ir-after=(comma-separated-pass-list)`
1103    *   Print the IR after each of the passes provided within the pass list.
1104*   `print-ir-after-all`
1105    *   Print the IR after every pass in the pipeline.
1106
1107```shell
1108$ mlir-opt foo.mlir -pass-pipeline='func.func(cse)' -print-ir-after=cse
1109
1110*** IR Dump After CSE ***
1111func @simple_constant() -> (i32, i32) {
1112  %c1_i32 = arith.constant 1 : i32
1113  return %c1_i32, %c1_i32 : i32, i32
1114}
1115```
1116
1117*   `print-ir-after-change`
1118    *   Only print the IR after a pass if the pass mutated the IR. This helps to
1119        reduce the number of IR dumps for "uninteresting" passes.
1120    *   Note: Changes are detected by comparing a hash of the operation before
1121        and after the pass. This adds additional run-time to compute the hash of
1122        the IR, and in some rare cases may result in false-positives depending
1123        on the collision rate of the hash algorithm used.
1124    *   Note: This option should be used in unison with one of the other
1125        'print-ir-after' options above, as this option alone does not enable
1126        printing.
1127
1128```shell
1129$ mlir-opt foo.mlir -pass-pipeline='func.func(cse,cse)' -print-ir-after=cse -print-ir-after-change
1130
1131*** IR Dump After CSE ***
1132func @simple_constant() -> (i32, i32) {
1133  %c1_i32 = arith.constant 1 : i32
1134  return %c1_i32, %c1_i32 : i32, i32
1135}
1136```
1137
1138*   `print-ir-after-failure`
1139    *   Only print IR after a pass failure.
1140    *   This option should *not* be used with the other `print-ir-after` flags
1141        above.
1142
1143```shell
1144$ mlir-opt foo.mlir -pass-pipeline='func.func(cse,bad-pass)' -print-ir-failure
1145
1146*** IR Dump After BadPass Failed ***
1147func @simple_constant() -> (i32, i32) {
1148  %c1_i32 = arith.constant 1 : i32
1149  return %c1_i32, %c1_i32 : i32, i32
1150}
1151```
1152
1153*   `print-ir-module-scope`
1154    *   Always print the top-level module operation, regardless of pass type or
1155        operation nesting level.
1156    *   Note: Printing at module scope should only be used when multi-threading
1157        is disabled(`-mlir-disable-threading`)
1158
1159```shell
1160$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func.func(cse)' -print-ir-after=cse -print-ir-module-scope
1161
1162*** IR Dump After CSE ***  ('func.func' operation: @bar)
1163func @bar(%arg0: f32, %arg1: f32) -> f32 {
1164  ...
1165}
1166
1167func @simple_constant() -> (i32, i32) {
1168  %c1_i32 = arith.constant 1 : i32
1169  %c1_i32_0 = arith.constant 1 : i32
1170  return %c1_i32, %c1_i32_0 : i32, i32
1171}
1172
1173*** IR Dump After CSE ***  ('func.func' operation: @simple_constant)
1174func @bar(%arg0: f32, %arg1: f32) -> f32 {
1175  ...
1176}
1177
1178func @simple_constant() -> (i32, i32) {
1179  %c1_i32 = arith.constant 1 : i32
1180  return %c1_i32, %c1_i32 : i32, i32
1181}
1182```
1183
1184## Crash and Failure Reproduction
1185
1186The [pass manager](#pass-manager) in MLIR contains a builtin mechanism to
1187generate reproducibles in the event of a crash, or a
1188[pass failure](#pass-failure). This functionality can be enabled via
1189`PassManager::enableCrashReproducerGeneration` or via the command line flag
1190`pass-pipeline-crash-reproducer`. In either case, an argument is provided that
1191corresponds to the output `.mlir` file name that the reproducible should be
1192written to. The reproducible contains the configuration of the pass manager that
1193was executing, as well as the initial IR before any passes were run. A potential
1194reproducible may have the form:
1195
1196```mlir
1197// configuration: -pass-pipeline='func.func(cse,canonicalize),inline' -verify-each
1198
1199module {
1200  func @foo() {
1201    ...
1202  }
1203}
1204```
1205
1206The configuration dumped can be passed to `mlir-opt` by specifying
1207`-run-reproducer` flag. This will result in parsing the first line configuration
1208of the reproducer and adding those to the command line options.
1209
1210Beyond specifying a filename, one can also register a `ReproducerStreamFactory`
1211function that would be invoked in the case of a crash and the reproducer written
1212to its stream.
1213
1214### Local Reproducer Generation
1215
1216An additional flag may be passed to
1217`PassManager::enableCrashReproducerGeneration`, and specified via
1218`pass-pipeline-local-reproducer` on the command line, that signals that the pass
1219manager should attempt to generate a "local" reproducer. This will attempt to
1220generate a reproducer containing IR right before the pass that fails. This is
1221useful for situations where the crash is known to be within a specific pass, or
1222when the original input relies on components (like dialects or passes) that may
1223not always be available.
1224
1225Note: Local reproducer generation requires that multi-threading is
1226disabled(`-mlir-disable-threading`)
1227
1228For example, if the failure in the previous example came from `canonicalize`,
1229the following reproducer will be generated:
1230
1231```mlir
1232// configuration: -pass-pipeline='func.func(canonicalize)' -verify-each -mlir-disable-threading
1233
1234module {
1235  func @foo() {
1236    ...
1237  }
1238}
1239```
1240