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*   Modify any state referenced or relied upon outside the current being
27    operated on. This includes adding or removing operations from the parent
28    block, changing the attributes(depending on the contract of the current
29    operation)/operands/results/successors of the current operation.
30*   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*   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*   Maintain mutable pass state across invocations of `runOnOperation`. A pass
37    may be run on many different operations with no guarantee of execution
38    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*   Maintain any global mutable state, e.g. static variables within the source
43    file. All mutable state should be maintained by an instance of the pass.
44*   Must be copy-constructible
45    *   Multiple instances of the pass may be created by the pass manager to
46        process operations in parallel.
47
48When creating an operation pass, there are two different types to choose from
49depending on the usage scenario:
50
51### OperationPass : Op-Specific
52
53An `op-specific` operation pass operates explicitly on a given operation type.
54This operation type must adhere to the restrictions set by the pass manager for
55pass execution.
56
57To define an op-specific operation pass, a derived class must adhere to the
58following:
59
60*   Inherit from the CRTP class `OperationPass` and provide the operation type
61    as an additional template parameter.
62*   Override the virtual `void runOnOperation()` method.
63
64A simple pass may look like:
65
66```c++
67namespace {
68/// Here we utilize the CRTP `PassWrapper` utility class to provide some
69/// necessary utility hooks. This is only necessary for passes defined directly
70/// in C++. Passes defined declaratively use a cleaner mechanism for providing
71/// these utilities.
72struct MyFunctionPass : public PassWrapper<OperationPass<FuncOp>,
73                                           MyFunctionPass> {
74  void runOnOperation() override {
75    // Get the current FuncOp operation being operated on.
76    FuncOp f = getOperation();
77
78    // Walk the operations within the function.
79    f.walk([](Operation *inst) {
80      ....
81    });
82  }
83};
84} // end anonymous namespace
85
86/// Register this pass so that it can be built via from a textual pass pipeline.
87/// (Pass registration is discussed more below)
88void registerMyPass() {
89  PassRegistration<MyFunctionPass>(
90    "flag-name-to-invoke-pass-via-mlir-opt", "Pass description here");
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<OperationPass<>, MyOperationPass> {
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=*/"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("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
507  /// Define the statistic to track during the execution of MyPass.
508  Statistic exampleStat{this, "exampleStat", "An example statistic"};
509
510  void runOnOperation() {
511    ...
512
513    // Update the statistic after some invariant was hit.
514    ++exampleStat;
515
516    ...
517  }
518};
519```
520
521The collected statistics may be aggregated in two types of views:
522
523A pipeline view that models the structure of the pass manager, this is the
524default view:
525
526```shell
527$ mlir-opt -pass-pipeline='func(my-pass,my-pass)' foo.mlir -pass-statistics
528
529===-------------------------------------------------------------------------===
530                         ... Pass statistics report ...
531===-------------------------------------------------------------------------===
532'func' Pipeline
533  MyPass
534    (S) 15 exampleStat - An example statistic
535  VerifierPass
536  MyPass
537    (S)  6 exampleStat - An example statistic
538  VerifierPass
539VerifierPass
540```
541
542A list view that aggregates the statistics of all instances of a specific pass
543together:
544
545```shell
546$ mlir-opt -pass-pipeline='func(my-pass, my-pass)' foo.mlir -pass-statistics -pass-statistics-display=list
547
548===-------------------------------------------------------------------------===
549                         ... Pass statistics report ...
550===-------------------------------------------------------------------------===
551MyPass
552  (S) 21 exampleStat - An example statistic
553```
554
555## Pass Registration
556
557Briefly shown in the example definitions of the various pass types is the
558`PassRegistration` class. This mechanism allows for registering pass classes so
559that they may be created within a
560[textual pass pipeline description](#textual-pass-pipeline-specification). An
561example registration is shown below:
562
563```c++
564void registerMyPass() {
565  PassRegistration<MyPass>("argument", "description");
566}
567```
568
569*   `MyPass` is the name of the derived pass class.
570*   "argument" is the argument used to refer to the pass in the textual format.
571*   "description" is a brief description of the pass.
572
573For passes that cannot be default-constructed, `PassRegistration` accepts an
574optional third argument that takes a callback to create the pass:
575
576```c++
577void registerMyPass() {
578  PassRegistration<MyParametricPass>(
579    "argument", "description",
580    []() -> std::unique_ptr<Pass> {
581      std::unique_ptr<Pass> p = std::make_unique<MyParametricPass>(/*options*/);
582      /*... non-trivial-logic to configure the pass ...*/;
583      return p;
584    });
585}
586```
587
588This variant of registration can be used, for example, to accept the
589configuration of a pass from command-line arguments and pass it to the pass
590constructor.
591
592Note: Make sure that the pass is copy-constructible in a way that does not share
593data as the [pass manager](#pass-manager) may create copies of the pass to run
594in parallel.
595
596### Pass Pipeline Registration
597
598Described above is the mechanism used for registering a specific derived pass
599class. On top of that, MLIR allows for registering custom pass pipelines in a
600similar fashion. This allows for custom pipelines to be available to tools like
601mlir-opt in the same way that passes are, which is useful for encapsulating
602common pipelines like the "-O1" series of passes. Pipelines are registered via a
603similar mechanism to passes in the form of `PassPipelineRegistration`. Compared
604to `PassRegistration`, this class takes an additional parameter in the form of a
605pipeline builder that modifies a provided `OpPassManager`.
606
607```c++
608void pipelineBuilder(OpPassManager &pm) {
609  pm.addPass(std::make_unique<MyPass>());
610  pm.addPass(std::make_unique<MyOtherPass>());
611}
612
613void registerMyPasses() {
614  // Register an existing pipeline builder function.
615  PassPipelineRegistration<>(
616    "argument", "description", pipelineBuilder);
617
618  // Register an inline pipeline builder.
619  PassPipelineRegistration<>(
620    "argument", "description", [](OpPassManager &pm) {
621      pm.addPass(std::make_unique<MyPass>());
622      pm.addPass(std::make_unique<MyOtherPass>());
623    });
624}
625```
626
627### Textual Pass Pipeline Specification
628
629The previous sections detailed how to register passes and pass pipelines with a
630specific argument and description. Once registered, these can be used to
631configure a pass manager from a string description. This is especially useful
632for tools like `mlir-opt`, that configure pass managers from the command line,
633or as options to passes that utilize
634[dynamic pass pipelines](#dynamic-pass-pipelines).
635
636To support the ability to describe the full structure of pass pipelines, MLIR
637supports a custom textual description of pass pipelines. The textual description
638includes the nesting structure, the arguments of the passes and pass pipelines
639to run, and any options for those passes and pipelines. A textual pipeline is
640defined as a series of names, each of which may in itself recursively contain a
641nested pipeline description. The syntax for this specification is as follows:
642
643```ebnf
644pipeline          ::= op-name `(` pipeline-element (`,` pipeline-element)* `)`
645pipeline-element  ::= pipeline | (pass-name | pass-pipeline-name) options?
646options           ::= '{' (key ('=' value)?)+ '}'
647```
648
649*   `op-name`
650    *   This corresponds to the mnemonic name of an operation to run passes on,
651        e.g. `func` or `module`.
652*   `pass-name` | `pass-pipeline-name`
653    *   This corresponds to the argument of a registered pass or pass pipeline,
654        e.g. `cse` or `canonicalize`.
655*   `options`
656    *   Options are specific key value pairs representing options defined by a
657        pass or pass pipeline, as described in the
658        ["Instance Specific Pass Options"](#instance-specific-pass-options)
659        section. See this section for an example usage in a textual pipeline.
660
661For example, the following pipeline:
662
663```shell
664$ mlir-opt foo.mlir -cse -canonicalize -convert-std-to-llvm='use-bare-ptr-memref-call-conv=1'
665```
666
667Can also be specified as (via the `-pass-pipeline` flag):
668
669```shell
670$ mlir-opt foo.mlir -pass-pipeline='func(cse,canonicalize),convert-std-to-llvm{use-bare-ptr-memref-call-conv=1}'
671```
672
673In order to support round-tripping a pass to the textual representation using
674`OpPassManager::printAsTextualPipeline(raw_ostream&)`, override `StringRef
675Pass::getArgument()` to specify the argument used when registering a pass.
676
677## Declarative Pass Specification
678
679Some aspects of a Pass may be specified declaratively, in a form similar to
680[operations](OpDefinitions.md). This specification simplifies several mechanisms
681used when defining passes. It can be used for generating pass registration
682calls, defining boilerplate pass utilities, and generating pass documentation.
683
684Consider the following pass specified in C++:
685
686```c++
687struct MyPass : PassWrapper<MyPass, OperationPass<ModuleOp>> {
688  MyPass() = default;
689  MyPass(const MyPass &) {}
690
691  ...
692
693  // Specify any options.
694  Option<bool> option{
695      *this, "example-option",
696      llvm::cl::desc("An example option"), llvm::cl::init(true)};
697  ListOption<int64_t> listOption{
698      *this, "example-list",
699      llvm::cl::desc("An example list option"), llvm::cl::ZeroOrMore,
700      llvm::cl::MiscFlags::CommaSeparated};
701
702  // Specify any statistics.
703  Statistic statistic{this, "example-statistic", "An example statistic"};
704};
705
706/// Expose this pass to the outside world.
707std::unique_ptr<Pass> foo::createMyPass() {
708  return std::make_unique<MyPass>();
709}
710
711/// Register this pass.
712void foo::registerMyPass() {
713  PassRegistration<MyPass>("my-pass", "My pass summary");
714}
715```
716
717This pass may be specified declaratively as so:
718
719```tablegen
720def MyPass : Pass<"my-pass", "ModuleOp"> {
721  let summary = "My Pass Summary";
722  let description = [{
723    Here we can now give a much larger description of `MyPass`, including all of
724    its various constraints and behavior.
725  }];
726
727  // A constructor must be provided to specify how to create a default instance
728  // of MyPass.
729  let constructor = "foo::createMyPass()";
730
731  // Specify any options.
732  let options = [
733    Option<"option", "example-option", "bool", /*default=*/"true",
734           "An example option">,
735    ListOption<"listOption", "example-list", "int64_t",
736               "An example list option",
737               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">
738  ];
739
740  // Specify any statistics.
741  let statistics = [
742    Statistic<"statistic", "example-statistic", "An example statistic">
743  ];
744}
745```
746
747Using the `gen-pass-decls` generator, we can generate most of the boilerplate
748above automatically. This generator takes as an input a `-name` parameter, that
749provides a tag for the group of passes that are being generated. This generator
750produces two chunks of output:
751
752The first is a code block for registering the declarative passes with the global
753registry. For each pass, the generator produces a `registerFooPass` where `Foo`
754is the name of the definition specified in tablegen. It also generates a
755`registerGroupPasses`, where `Group` is the tag provided via the `-name` input
756parameter, that registers all of the passes present.
757
758```c++
759// gen-pass-decls -name="Example"
760
761#define GEN_PASS_REGISTRATION
762#include "Passes.h.inc"
763
764void registerMyPasses() {
765  // Register all of the passes.
766  registerExamplePasses();
767
768  // Register `MyPass` specifically.
769  registerMyPassPass();
770}
771```
772
773The second is a base class for each of the passes, containing most of the boiler
774plate related to pass definitions. These classes are named in the form of
775`MyPassBase`, where `MyPass` is the name of the pass definition in tablegen. We
776can update the original C++ pass definition as so:
777
778```c++
779/// Include the generated base pass class definitions.
780#define GEN_PASS_CLASSES
781#include "Passes.h.inc"
782
783/// Define the main class as deriving from the generated base class.
784struct MyPass : MyPassBase<MyPass> {
785  /// The explicit constructor is no longer explicitly necessary when defining
786  /// pass options and statistics, the base class takes care of that
787  /// automatically.
788  ...
789
790  /// The definitions of the options and statistics are now generated within
791  /// the base class, but are accessible in the same way.
792};
793
794/// Expose this pass to the outside world.
795std::unique_ptr<Pass> foo::createMyPass() {
796  return std::make_unique<MyPass>();
797}
798```
799
800Using the `gen-pass-doc` generator, markdown documentation for each of the
801passes can be generated. See [Passes.md](Passes.md) for example output of real
802MLIR passes.
803
804### Tablegen Specification
805
806The `Pass` class is used to begin a new pass definition. This class takes as an
807argument the registry argument to attribute to the pass, as well as an optional
808string corresponding to the operation type that the pass operates on. The class
809contains the following fields:
810
811*   `summary`
812    -   A short one line summary of the pass, used as the description when
813        registering the pass.
814*   `description`
815    -   A longer, more detailed description of the pass. This is used when
816        generating pass documentation.
817*   `dependentDialects`
818    -   A list of strings representing the `Dialect` classes this pass may
819        introduce entities, Attributes/Operations/Types/etc., of.
820*   `constructor`
821    -   A code block used to create a default instance of the pass.
822*   `options`
823    -   A list of pass options used by the pass.
824*   `statistics`
825    -   A list of pass statistics used by the pass.
826
827#### Options
828
829Options may be specified via the `Option` and `ListOption` classes. The `Option`
830class takes the following template parameters:
831
832*   C++ variable name
833    -   A name to use for the generated option variable.
834*   argument
835    -   The argument name of the option.
836*   type
837    -   The C++ type of the option.
838*   default value
839    -   The default option value.
840*   description
841    -   A one line description of the option.
842*   additional option flags
843    -   A string containing any additional options necessary to construct the
844        option.
845
846```tablegen
847def MyPass : Pass<"my-pass"> {
848  let options = [
849    Option<"option", "example-option", "bool", /*default=*/"true",
850           "An example option">,
851  ];
852}
853```
854
855The `ListOption` class takes the following fields:
856
857*   C++ variable name
858    -   A name to use for the generated option variable.
859*   argument
860    -   The argument name of the option.
861*   element type
862    -   The C++ type of the list element.
863*   description
864    -   A one line description of the option.
865*   additional option flags
866    -   A string containing any additional options necessary to construct the
867        option.
868
869```tablegen
870def MyPass : Pass<"my-pass"> {
871  let options = [
872    ListOption<"listOption", "example-list", "int64_t",
873               "An example list option",
874               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">
875  ];
876}
877```
878
879#### Statistic
880
881Statistics may be specified via the `Statistic`, which takes the following
882template parameters:
883
884*   C++ variable name
885    -   A name to use for the generated statistic variable.
886*   display name
887    -   The name used when displaying the statistic.
888*   description
889    -   A one line description of the statistic.
890
891```tablegen
892def MyPass : Pass<"my-pass"> {
893  let statistics = [
894    Statistic<"statistic", "example-statistic", "An example statistic">
895  ];
896}
897```
898
899## Pass Instrumentation
900
901MLIR provides a customizable framework to instrument pass execution and analysis
902computation, via the `PassInstrumentation` class. This class provides hooks into
903the PassManager that observe various events:
904
905*   `runBeforePipeline`
906    *   This callback is run just before a pass pipeline, i.e. pass manager, is
907        executed.
908*   `runAfterPipeline`
909    *   This callback is run right after a pass pipeline has been executed,
910        successfully or not.
911*   `runBeforePass`
912    *   This callback is run just before a pass is executed.
913*   `runAfterPass`
914    *   This callback is run right after a pass has been successfully executed.
915        If this hook is executed, `runAfterPassFailed` will *not* be.
916*   `runAfterPassFailed`
917    *   This callback is run right after a pass execution fails. If this hook is
918        executed, `runAfterPass` will *not* be.
919*   `runBeforeAnalysis`
920    *   This callback is run just before an analysis is computed.
921    *   If the analysis requested another analysis as a dependency, the
922        `runBeforeAnalysis`/`runAfterAnalysis` pair for the dependency can be
923        called from inside of the current `runBeforeAnalysis`/`runAfterAnalysis`
924        pair.
925*   `runAfterAnalysis`
926    *   This callback is run right after an analysis is computed.
927
928PassInstrumentation instances may be registered directly with a
929[PassManager](#pass-manager) instance via the `addInstrumentation` method.
930Instrumentations added to the PassManager are run in a stack like fashion, i.e.
931the last instrumentation to execute a `runBefore*` hook will be the first to
932execute the respective `runAfter*` hook. The hooks of a `PassInstrumentation`
933class are guaranteed to be executed in a thread safe fashion, so additional
934synchronization is not necessary. Below in an example instrumentation that
935counts the number of times the `DominanceInfo` analysis is computed:
936
937```c++
938struct DominanceCounterInstrumentation : public PassInstrumentation {
939  /// The cumulative count of how many times dominance has been calculated.
940  unsigned &count;
941
942  DominanceCounterInstrumentation(unsigned &count) : count(count) {}
943  void runAfterAnalysis(llvm::StringRef, TypeID id, Operation *) override {
944    if (id == TypeID::get<DominanceInfo>())
945      ++count;
946  }
947};
948
949MLIRContext *ctx = ...;
950PassManager pm(ctx);
951
952// Add the instrumentation to the pass manager.
953unsigned domInfoCount;
954pm.addInstrumentation(
955    std::make_unique<DominanceCounterInstrumentation>(domInfoCount));
956
957// Run the pass manager on a module operation.
958ModuleOp m = ...;
959if (failed(pm.run(m)))
960    ...
961
962llvm::errs() << "DominanceInfo was computed " << domInfoCount << " times!\n";
963```
964
965### Standard Instrumentations
966
967MLIR utilizes the pass instrumentation framework to provide a few useful
968developer tools and utilities. Each of these instrumentations are directly
969available to all users of the MLIR pass framework.
970
971#### Pass Timing
972
973The PassTiming instrumentation provides timing information about the execution
974of passes and computation of analyses. This provides a quick glimpse into what
975passes are taking the most time to execute, as well as how much of an effect a
976pass has on the total execution time of the pipeline. Users can enable this
977instrumentation directly on the PassManager via `enableTiming`. This
978instrumentation is also made available in mlir-opt via the `-pass-timing` flag.
979The PassTiming instrumentation provides several different display modes for the
980timing results, each of which is described below:
981
982##### List Display Mode
983
984In this mode, the results are displayed in a list sorted by total time with each
985pass/analysis instance aggregated into one unique result. This view is useful
986for getting an overview of what analyses/passes are taking the most time in a
987pipeline. This display mode is available in mlir-opt via
988`-pass-timing-display=list`.
989
990```shell
991$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing -pass-timing-display=list
992
993===-------------------------------------------------------------------------===
994                      ... Pass execution timing report ...
995===-------------------------------------------------------------------------===
996  Total Execution Time: 0.0203 seconds
997
998   ---Wall Time---  --- Name ---
999   0.0047 ( 55.9%)  Canonicalizer
1000   0.0019 ( 22.2%)  VerifierPass
1001   0.0016 ( 18.5%)  LLVMLoweringPass
1002   0.0003 (  3.4%)  CSE
1003   0.0002 (  1.9%)  (A) DominanceInfo
1004   0.0084 (100.0%)  Total
1005```
1006
1007##### Pipeline Display Mode
1008
1009In this mode, the results are displayed in a nested pipeline view that mirrors
1010the internal pass pipeline that is being executed in the pass manager. This view
1011is useful for understanding specifically which parts of the pipeline are taking
1012the most time, and can also be used to identify when analyses are being
1013invalidated and recomputed. This is the default display mode.
1014
1015```shell
1016$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing
1017
1018===-------------------------------------------------------------------------===
1019                      ... Pass execution timing report ...
1020===-------------------------------------------------------------------------===
1021  Total Execution Time: 0.0249 seconds
1022
1023   ---Wall Time---  --- Name ---
1024   0.0058 ( 70.8%)  'func' Pipeline
1025   0.0004 (  4.3%)    CSE
1026   0.0002 (  2.6%)      (A) DominanceInfo
1027   0.0004 (  4.8%)    VerifierPass
1028   0.0046 ( 55.4%)    Canonicalizer
1029   0.0005 (  6.2%)    VerifierPass
1030   0.0005 (  5.8%)  VerifierPass
1031   0.0014 ( 17.2%)  LLVMLoweringPass
1032   0.0005 (  6.2%)  VerifierPass
1033   0.0082 (100.0%)  Total
1034```
1035
1036##### Multi-threaded Pass Timing
1037
1038When multi-threading is enabled in the pass manager the meaning of the display
1039slightly changes. First, a new timing column is added, `User Time`, that
1040displays the total time spent across all threads. Secondly, the `Wall Time`
1041column displays the longest individual time spent amongst all of the threads.
1042This means that the `Wall Time` column will continue to give an indicator on the
1043perceived time, or clock time, whereas the `User Time` will display the total
1044cpu time.
1045
1046```shell
1047$ mlir-opt foo.mlir -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing
1048
1049===-------------------------------------------------------------------------===
1050                      ... Pass execution timing report ...
1051===-------------------------------------------------------------------------===
1052  Total Execution Time: 0.0078 seconds
1053
1054   ---User Time---   ---Wall Time---  --- Name ---
1055   0.0177 ( 88.5%)     0.0057 ( 71.3%)  'func' Pipeline
1056   0.0044 ( 22.0%)     0.0015 ( 18.9%)    CSE
1057   0.0029 ( 14.5%)     0.0012 ( 15.2%)      (A) DominanceInfo
1058   0.0038 ( 18.9%)     0.0015 ( 18.7%)    VerifierPass
1059   0.0089 ( 44.6%)     0.0025 ( 31.1%)    Canonicalizer
1060   0.0006 (  3.0%)     0.0002 (  2.6%)    VerifierPass
1061   0.0004 (  2.2%)     0.0004 (  5.4%)  VerifierPass
1062   0.0013 (  6.5%)     0.0013 ( 16.3%)  LLVMLoweringPass
1063   0.0006 (  2.8%)     0.0006 (  7.0%)  VerifierPass
1064   0.0200 (100.0%)     0.0081 (100.0%)  Total
1065```
1066
1067#### IR Printing
1068
1069When debugging it is often useful to dump the IR at various stages of a pass
1070pipeline. This is where the IR printing instrumentation comes into play. This
1071instrumentation allows for conditionally printing the IR before and after pass
1072execution by optionally filtering on the pass being executed. This
1073instrumentation can be added directly to the PassManager via the
1074`enableIRPrinting` method. `mlir-opt` provides a few useful flags for utilizing
1075this instrumentation:
1076
1077*   `print-ir-before=(comma-separated-pass-list)`
1078    *   Print the IR before each of the passes provided within the pass list.
1079*   `print-ir-before-all`
1080    *   Print the IR before every pass in the pipeline.
1081
1082```shell
1083$ mlir-opt foo.mlir -pass-pipeline='func(cse)' -print-ir-before=cse
1084
1085*** IR Dump Before CSE ***
1086func @simple_constant() -> (i32, i32) {
1087  %c1_i32 = constant 1 : i32
1088  %c1_i32_0 = constant 1 : i32
1089  return %c1_i32, %c1_i32_0 : i32, i32
1090}
1091```
1092
1093*   `print-ir-after=(comma-separated-pass-list)`
1094    *   Print the IR after each of the passes provided within the pass list.
1095*   `print-ir-after-all`
1096    *   Print the IR after every pass in the pipeline.
1097
1098```shell
1099$ mlir-opt foo.mlir -pass-pipeline='func(cse)' -print-ir-after=cse
1100
1101*** IR Dump After CSE ***
1102func @simple_constant() -> (i32, i32) {
1103  %c1_i32 = constant 1 : i32
1104  return %c1_i32, %c1_i32 : i32, i32
1105}
1106```
1107
1108*   `print-ir-after-change`
1109    *   Only print the IR after a pass if the pass mutated the IR. This helps to
1110        reduce the number of IR dumps for "uninteresting" passes.
1111    *   Note: Changes are detected by comparing a hash of the operation before
1112        and after the pass. This adds additional run-time to compute the hash of
1113        the IR, and in some rare cases may result in false-positives depending
1114        on the collision rate of the hash algorithm used.
1115    *   Note: This option should be used in unison with one of the other
1116        'print-ir-after' options above, as this option alone does not enable
1117        printing.
1118
1119```shell
1120$ mlir-opt foo.mlir -pass-pipeline='func(cse,cse)' -print-ir-after=cse -print-ir-after-change
1121
1122*** IR Dump After CSE ***
1123func @simple_constant() -> (i32, i32) {
1124  %c1_i32 = constant 1 : i32
1125  return %c1_i32, %c1_i32 : i32, i32
1126}
1127```
1128
1129*   `print-ir-module-scope`
1130    *   Always print the top-level module operation, regardless of pass type or
1131        operation nesting level.
1132    *   Note: Printing at module scope should only be used when multi-threading
1133        is disabled(`-mlir-disable-threading`)
1134
1135```shell
1136$ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func(cse)' -print-ir-after=cse -print-ir-module-scope
1137
1138*** IR Dump After CSE ***  ('func' operation: @bar)
1139func @bar(%arg0: f32, %arg1: f32) -> f32 {
1140  ...
1141}
1142
1143func @simple_constant() -> (i32, i32) {
1144  %c1_i32 = constant 1 : i32
1145  %c1_i32_0 = constant 1 : i32
1146  return %c1_i32, %c1_i32_0 : i32, i32
1147}
1148
1149*** IR Dump After CSE ***  ('func' operation: @simple_constant)
1150func @bar(%arg0: f32, %arg1: f32) -> f32 {
1151  ...
1152}
1153
1154func @simple_constant() -> (i32, i32) {
1155  %c1_i32 = constant 1 : i32
1156  return %c1_i32, %c1_i32 : i32, i32
1157}
1158```
1159
1160## Crash and Failure Reproduction
1161
1162The [pass manager](#pass-manager) in MLIR contains a builtin mechanism to
1163generate reproducibles in the event of a crash, or a
1164[pass failure](#pass-failure). This functionality can be enabled via
1165`PassManager::enableCrashReproducerGeneration` or via the command line flag
1166`pass-pipeline-crash-reproducer`. In either case, an argument is provided that
1167corresponds to the output `.mlir` file name that the reproducible should be
1168written to. The reproducible contains the configuration of the pass manager that
1169was executing, as well as the initial IR before any passes were run. A potential
1170reproducible may have the form:
1171
1172```mlir
1173// configuration: -pass-pipeline='func(cse,canonicalize),inline' -verify-each
1174
1175module {
1176  func @foo() {
1177    ...
1178  }
1179}
1180```
1181
1182The configuration dumped can be passed to `mlir-opt` by specifying
1183`-run-reproducer` flag. This will result in parsing the first line configuration
1184of the reproducer and adding those to the command line options.
1185
1186Beyond specifying a filename, one can also register a `ReproducerStreamFactory`
1187function that would be invoked in the case of a crash and the reproducer written
1188to its stream.
1189
1190### Local Reproducer Generation
1191
1192An additional flag may be passed to
1193`PassManager::enableCrashReproducerGeneration`, and specified via
1194`pass-pipeline-local-reproducer` on the command line, that signals that the pass
1195manager should attempt to generate a "local" reproducer. This will attempt to
1196generate a reproducer containing IR right before the pass that fails. This is
1197useful for situations where the crash is known to be within a specific pass, or
1198when the original input relies on components (like dialects or passes) that may
1199not always be available.
1200
1201For example, if the failure in the previous example came from `canonicalize`,
1202the following reproducer will be generated:
1203
1204```mlir
1205// configuration: -pass-pipeline='func(canonicalize)' -verify-each
1206
1207module {
1208  func @foo() {
1209    ...
1210  }
1211}
1212```
1213