1# Pass Infrastructure
2
3[TOC]
4
5Passes represent the basic infrastructure for transformation and optimization.
6This document provides a quickstart to the pass infrastructure in MLIR and how
7to use 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](QuickstartRewrites.md) for a quick start on graph rewriting
13in MLIR. If your transformation involves pattern matching operation DAGs, this
14is 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 anything within the parent block/region/operation/etc, outside of the
27    current operation being operated on. This includes adding or removing
28    operations from the parent block.
29*   Maintain pass state across invocations of `runOnOperation`. A pass may be
30    run on several different operations with no guarantee of execution order.
31    *   When multithreading, a specific pass instance may not even execute on
32        all operations within the module. As such, a pass should not rely on
33        running on all operations.
34*   Modify the state of another operation not nested within the current
35    operation being operated on.
36    *   Other threads may be operating on different operations within the module
37        simultaneously.
38*   Maintain any global mutable state, e.g. static variables within the source
39    file. All mutable state should be maintained by an instance of the pass.
40*   Must be copy-constructible, multiple instances of the pass may be created by
41    the pass manager to process operations in parallel.
42*   Inspect the IR of sibling operations. Other threads may be modifying these
43    operations in parallel.
44
45When creating an operation pass, there are two different types to choose from
46depending on the usage scenario:
47
48### OperationPass : Op-Specific
49
50An `op-specific` operation pass operates explicitly on a given operation type.
51This operation type must adhere to the restrictions set by the pass manager for
52pass execution.
53
54To define an op-specific operation pass, a derived class must adhere to the
55following:
56
57*   Inherit from the CRTP class `OperationPass` and provide the operation type
58    as an additional template parameter.
59*   Override the virtual `void runOnOperation()` method.
60
61A simple pass may look like:
62
63```c++
64namespace {
65struct MyFunctionPass : public OperationPass<MyFunctionPass, FuncOp> {
66  void runOnOperation() override {
67    // Get the current FuncOp operation being operated on.
68    FuncOp f = getOperation();
69
70    // Walk the operations within the function.
71    f.walk([](Operation *inst) {
72      ....
73    });
74  }
75};
76} // end anonymous namespace
77
78// Register this pass to make it accessible to utilities like mlir-opt.
79// (Pass registration is discussed more below)
80static PassRegistration<MyFunctionPass> pass(
81    "flag-name-to-invoke-pass-via-mlir-opt", "Pass description here");
82```
83
84### OperationPass : Op-Agnostic
85
86An `op-agnostic` pass operates on the operation type of the pass manager that it
87is added to. This means that a pass that operates on several different operation
88types in the same way only needs one implementation.
89
90To create an operation pass, a derived class must adhere to the following:
91
92*   Inherit from the CRTP class `OperationPass`.
93*   Override the virtual `void runOnOperation()` method.
94
95A simple pass may look like:
96
97```c++
98struct MyOperationPass : public OperationPass<MyOperationPass> {
99  void runOnOperation() override {
100    // Get the current operation being operated on.
101    Operation *op = getOperation();
102    ...
103  }
104};
105```
106
107## Analysis Management
108
109An important concept, along with transformation passes, are analyses. These are
110conceptually similar to transformation passes, except that they compute
111information on a specific operation without modifying it. In MLIR, analyses are
112not passes but free-standing classes that are computed lazily on-demand and
113cached to avoid unnecessary recomputation. An analysis in MLIR must adhere to
114the following:
115
116*   Provide a valid constructor taking an `Operation*`.
117*   Must not modify the given operation.
118
119An analysis may provide additional hooks to control various behavior:
120
121*   `bool isInvalidated(const AnalysisManager::PreservedAnalyses &)`
122
123Given a preserved analysis set, the analysis returns true if it should truly be
124invalidated. This allows for more fine-tuned invalidation in cases where an
125analysis wasn't explicitly marked preserved, but may be preserved (or
126invalidated) based upon other properties such as analyses sets.
127
128### Querying Analyses
129
130The base `OperationPass` class provides utilities for querying and preserving
131analyses for the current operation being processed.
132
133*   OperationPass automatically provides the following utilities for querying
134    analyses:
135    *   `getAnalysis<>`
136        -   Get an analysis for the current operation, constructing it if
137            necessary.
138    *   `getCachedAnalysis<>`
139        -   Get an analysis for the current operation, if it already exists.
140    *   `getCachedParentAnalysis<>`
141        -   Get an analysis for a given parent operation, if it exists.
142    *   `getCachedChildAnalysis<>`
143        -   Get an analysis for a given child operation, if it exists.
144    *   `getChildAnalysis<>`
145        -   Get an analysis for a given child operation, constructing it if
146            necessary.
147
148Using the example passes defined above, let's see some examples:
149
150```c++
151/// An interesting analysis.
152struct MyOperationAnalysis {
153  // Compute this analysis with the provided operation.
154  MyOperationAnalysis(Operation *op);
155};
156
157void MyOperationPass::runOnOperation() {
158  // Query MyOperationAnalysis for the current operation.
159  MyOperationAnalysis &myAnalysis = getAnalysis<MyOperationAnalysis>();
160
161  // Query a cached instance of MyOperationAnalysis for the current operation.
162  // It will not be computed if it doesn't exist.
163  auto optionalAnalysis = getCachedAnalysis<MyOperationAnalysis>();
164  if (optionalAnalysis)
165    ...
166
167  // Query a cached instance of MyOperationAnalysis for the parent operation of
168  // the current operation. It will not be computed if it doesn't exist.
169  auto optionalAnalysis = getCachedParentAnalysis<MyOperationAnalysis>();
170  if (optionalAnalysis)
171    ...
172}
173```
174
175### Preserving Analyses
176
177Analyses that are constructed after being queried by a pass are cached to avoid
178unnecessary computation if they are requested again later. To avoid stale
179analyses, all analyses are assumed to be invalidated by a pass. To avoid
180invalidation, a pass must specifically mark analyses that are known to be
181preserved.
182
183*   All Pass classes automatically provide the following utilities for
184    preserving analyses:
185    *   `markAllAnalysesPreserved`
186    *   `markAnalysesPreserved<>`
187
188```c++
189void MyOperationPass::runOnOperation() {
190  // Mark all analyses as preserved. This is useful if a pass can guarantee
191  // that no transformation was performed.
192  markAllAnalysesPreserved();
193
194  // Mark specific analyses as preserved. This is used if some transformation
195  // was performed, but some analyses were either unaffected or explicitly
196  // preserved.
197  markAnalysesPreserved<MyAnalysis, MyAnalyses...>();
198}
199```
200
201## Pass Failure
202
203Passes in MLIR are allowed to gracefully fail. This may happen if some invariant
204of the pass was broken, potentially leaving the IR in some invalid state. If
205such a situation occurs, the pass can directly signal a failure to the pass
206manager. If a pass signaled a failure when executing, no other passes in the
207pipeline will execute and the `PassManager::run` will return failure. Failure
208signaling is provided in the form of a `signalPassFailure` method.
209
210```c++
211void MyPass::runOnOperation() {
212  // Signal failure on a broken invariant.
213  if (some_broken_invariant) {
214    signalPassFailure();
215    return;
216  }
217}
218```
219
220## Pass Manager
221
222Above we introduced the different types of passes and their constraints. Now
223that we have our pass we need to be able to run it over a specific module. This
224is where the pass manager comes into play. The `PassManager` class is used to
225configure and run a pipeline. The `OpPassManager` class is used to schedule
226passes to run at a specific level of nesting.
227
228### OpPassManager
229
230An `OpPassManager` is essentially a collection of passes to execute on an
231operation of a given type. This operation type must adhere to the following
232requirement:
233
234*   Must be registered and marked `IsolatedFromAbove`.
235
236    *   Passes are expected to not modify operations at or above the current
237        operation being processed. If the operation is not isolated, it may
238        inadvertently modify the use-list of an operation it is not supposed to
239        modify.
240
241Passes can be added to a pass manager via `addPass`. The pass must either be an
242`op-specific` pass operating on the same operation type as `OpPassManager`, or
243an `op-agnostic` pass.
244
245An `OpPassManager` cannot be created directly, but must be explicitly nested
246within another `OpPassManager` via the `nest<>` method. This method takes the
247operation type that the nested pass manager will operate on. At the top-level, a
248`PassManager` acts as an `OpPassManager` that operates on the
249[`module`](LangRef.md#module) operation. Nesting in this sense, corresponds to
250the structural nesting within [Regions](LangRef.md#regions) of the IR.
251
252For example, the following `.mlir`:
253
254```
255module {
256  spv.module "Logical" "GLSL450" {
257    func @foo() {
258      ...
259    }
260  }
261}
262```
263
264Has the nesting structure of:
265
266```
267`module`
268  `spv.module`
269    `function`
270```
271
272Below is an example of constructing a pipeline that operates on the above
273structure:
274
275```c++
276PassManager pm(ctx);
277
278// Add a pass on the top-level module operation.
279pm.addPass(std::make_unique<MyModulePass>());
280
281// Nest a pass manager that operates on spirv module operations nested directly
282// under the top-level module.
283OpPassManager &nestedModulePM = pm.nest<spirv::ModuleOp>();
284nestedModulePM.addPass(std::make_unique<MySPIRVModulePass>());
285
286// Nest a pass manager that operates on functions within the nested SPIRV
287// module.
288OpPassManager &nestedFunctionPM = nestedModulePM.nest<FuncOp>();
289nestedFunctionPM.addPass(std::make_unique<MyFunctionPass>());
290
291// Run the pass manager on the top-level module.
292Module m = ...;
293if (failed(pm.run(m)))
294    ... // One of the passes signaled a failure.
295```
296
297The above pass manager would contain the following pipeline structure:
298
299```
300OpPassManager<ModuleOp>
301  MyModulePass
302  OpPassManager<spirv::ModuleOp>
303    MySPIRVModulePass
304    OpPassManager<FuncOp>
305      MyFunctionPass
306```
307
308These pipelines are then run over a single operation at a time. This means that,
309for example, given a series of consecutive passes on FuncOp, it will execute all
310on the first function, then all on the second function, etc. until the entire
311program has been run through the passes. This provides several benefits:
312
313*   This improves the cache behavior of the compiler, because it is only
314    touching a single function at a time, instead of traversing the entire
315    program.
316*   This improves multi-threading performance by reducing the number of jobs
317    that need to be scheduled, as well as increasing the efficiency of each job.
318    An entire function pipeline can be run on each function asynchronously.
319
320## Pass Registration
321
322Briefly shown in the example definitions of the various pass types is the
323`PassRegistration` class. This is a utility to register derived pass classes so
324that they may be created, and inspected, by utilities like mlir-opt. Registering
325a pass class takes the form:
326
327```c++
328static PassRegistration<MyPass> pass("command-line-arg", "description");
329```
330
331*   `MyPass` is the name of the derived pass class.
332*   "command-line-arg" is the argument to use on the command line to invoke the
333    pass from `mlir-opt`.
334*   "description" is a description of the pass.
335
336For passes that cannot be default-constructed, `PassRegistration` accepts an
337optional third argument that takes a callback to create the pass:
338
339```c++
340static PassRegistration<MyParametricPass> pass(
341    "command-line-arg", "description",
342    []() -> std::unique_ptr<Pass> {
343      std::unique_ptr<Pass> p = std::make_unique<MyParametricPass>(/*options*/);
344      /*... non-trivial-logic to configure the pass ...*/;
345      return p;
346    });
347```
348
349This variant of registration can be used, for example, to accept the
350configuration of a pass from command-line arguments and pass it over to the pass
351constructor. Make sure that the pass is copy-constructible in a way that does
352not share data as the [pass manager](#pass-manager) may create copies of the
353pass to run in parallel.
354
355### Pass Pipeline Registration
356
357Described above is the mechanism used for registering a specific derived pass
358class. On top of that, MLIR allows for registering custom pass pipelines in a
359similar fashion. This allows for custom pipelines to be available to tools like
360mlir-opt in the same way that passes are, which is useful for encapsulating
361common pipelines like the "-O1" series of passes. Pipelines are registered via a
362similar mechanism to passes in the form of `PassPipelineRegistration`. Compared
363to `PassRegistration`, this class takes an additional parameter in the form of a
364pipeline builder that modifies a provided `OpPassManager`.
365
366```c++
367void pipelineBuilder(OpPassManager &pm) {
368  pm.addPass(std::make_unique<MyPass>());
369  pm.addPass(std::make_unique<MyOtherPass>());
370}
371
372// Register an existing pipeline builder function.
373static PassPipelineRegistration<> pipeline(
374  "command-line-arg", "description", pipelineBuilder);
375
376// Register an inline pipeline builder.
377static PassPipelineRegistration<> pipeline(
378  "command-line-arg", "description", [](OpPassManager &pm) {
379    pm.addPass(std::make_unique<MyPass>());
380    pm.addPass(std::make_unique<MyOtherPass>());
381  });
382```
383
384Pipeline registration also allows for simplified registration of
385specifializations for existing passes:
386
387```c++
388static PassPipelineRegistration<> foo10(
389    "foo-10", "Foo Pass 10", [] { return std::make_unique<FooPass>(10); } );
390```
391
392### Textual Pass Pipeline Specification
393
394In the previous sections, we showed how to register passes and pass pipelines
395with a specific argument and description. Once registered, these can be used on
396the command line to configure a pass manager. The limitation of using these
397arguments directly is that they cannot build a nested pipeline. For example, if
398our module has another module nested underneath, with just `-my-module-pass`
399there is no way to specify that this pass should run on the nested module and
400not the top-level module. This is due to the flattened nature of the command
401line.
402
403To circumvent this limitation, MLIR also supports a textual description of a
404pass pipeline. This allows for explicitly specifying the structure of the
405pipeline to add to the pass manager. This includes the nesting structure, as
406well as the passes and pass pipelines to run. A textual pipeline is defined as a
407series of names, each of which may in itself recursively contain a nested
408pipeline description. The syntax for this specification is as follows:
409
410```ebnf
411pipeline          ::= op-name `(` pipeline-element (`,` pipeline-element)* `)`
412pipeline-element  ::= pipeline | (pass-name | pass-pipeline-name) options?
413options           ::= '{' (key ('=' value)?)+ '}'
414```
415
416*   `op-name`
417    *   This corresponds to the mnemonic name of an operation to run passes on,
418        e.g. `func` or `module`.
419*   `pass-name` | `pass-pipeline-name`
420    *   This corresponds to the command-line argument of a registered pass or
421        pass pipeline, e.g. `cse` or `canonicalize`.
422*   `options`
423    *   Options are pass specific key value pairs that are handled as described
424        in the [instance specific pass options](#instance-specific-pass-options)
425        section.
426
427For example, the following pipeline:
428
429```shell
430$ mlir-opt foo.mlir -cse -canonicalize -convert-std-to-llvm
431```
432
433Can also be specified as (via the `-pass-pipeline` flag):
434
435```shell
436$ mlir-opt foo.mlir -pass-pipeline='func(cse, canonicalize), convert-std-to-llvm'
437```
438
439In order to support round-tripping your pass to the textual representation using
440`OpPassManager::printAsTextualPipeline(raw_ostream&)`, override
441`Pass::printAsTextualPipeline(raw_ostream&)` to format your pass-name and
442options in the format described above.
443
444### Instance Specific Pass Options
445
446Options may be specified for a parametric pass. Individual options are defined
447using the [LLVM command line](https://llvm.org/docs/CommandLine.html) flag
448definition rules. These options will then be parsed at pass construction time
449independently for each instance of the pass. To provide options for passes, the
450`Option<>` and `OptionList<>` classes may be used:
451
452```c++
453struct MyPass ... {
454  /// Make sure that we have a valid default constructor and copy constructor to
455  /// make sure that the options are initialized properly.
456  MyPass() = default;
457  MyPass(const MyPass& pass) {}
458
459  // These just forward onto llvm::cl::list and llvm::cl::opt respectively.
460  Option<int> exampleOption{*this, "flag-name", llvm::cl::desc("...")};
461  ListOption<int> exampleListOption{*this, "list-flag-name",
462                                    llvm::cl::desc("...")};
463};
464```
465
466For pass pipelines, the `PassPipelineRegistration` templates take an additional
467optional template parameter that is the Option struct definition to be used for
468that pipeline. To use pipeline specific options, create a class that inherits
469from `mlir::PassPipelineOptions` that contains the desired options. When using
470`PassPipelineRegistration`, the constructor now takes a function with the
471signature `void (OpPassManager &pm, const MyPipelineOptions&)` which should
472construct the passes from the options and pass them to the pm:
473
474```c++
475struct MyPipelineOptions : public PassPipelineOptions {
476  // These just forward onto llvm::cl::list and llvm::cl::opt respectively.
477  Option<int> exampleOption{*this, "flag-name", llvm::cl::desc("...")};
478  ListOption<int> exampleListOption{*this, "list-flag-name",
479                                    llvm::cl::desc("...")};
480};
481
482
483static mlir::PassPipelineRegistration<MyPipelineOptions> pipeline(
484    "example-pipeline", "Run an example pipeline.",
485    [](OpPassManager &pm, const MyPipelineOptions &pipelineOptions) {
486      // Initialize the pass manager.
487    });
488```
489
490## Pass Statistics
491
492Statistics are a way to keep track of what the compiler is doing and how
493effective various transformations are. It is often useful to see what effect
494specific transformations have on a particular program, and how often they
495trigger. Pass statistics are instance specific which allow for taking this a
496step further as you are able to see the effect of placing a particular
497transformation at specific places within the pass pipeline. For example, they
498help answer questions like `What happens if I run CSE again here?`.
499
500Statistics can be added to a pass by using the 'Pass::Statistic' class. This
501class takes as a constructor arguments: the parent pass, a name, and a
502description. This class acts like an unsigned integer, and may be incremented
503and updated accordingly. These statistics use the same infrastructure as
504[`llvm::Statistic`](http://llvm.org/docs/ProgrammersManual.html#the-statistic-class-stats-option)
505and thus have similar usage constraints. Collected statistics can be dumped by
506the [pass manager](#pass-manager) programmatically via
507`PassManager::enableStatistics`; or via `-pass-statistics` and
508`-pass-statistics-display` on the command line.
509
510An example is shown below:
511
512```c++
513struct MyPass : public OperationPass<MyPass> {
514  Statistic testStat{this, "testStat", "A test statistic"};
515
516  void runOnOperation() {
517    ...
518
519    // Update our statistic after some invariant was hit.
520    ++testStat;
521
522    ...
523  }
524};
525```
526
527The collected statistics may be aggregated in two types of views:
528
529A pipeline view that models the structure of the pass manager, this is the
530default view:
531
532```shell
533$ mlir-opt -pass-pipeline='func(my-pass,my-pass)' foo.mlir -pass-statistics
534
535===-------------------------------------------------------------------------===
536                         ... Pass statistics report ...
537===-------------------------------------------------------------------------===
538'func' Pipeline
539  MyPass
540    (S) 15 testStat - A test statistic
541  VerifierPass
542  MyPass
543    (S)  6 testStat - A test statistic
544  VerifierPass
545VerifierPass
546```
547
548And a list view that aggregates all instances of a specific pass together:
549
550```shell
551$ mlir-opt -pass-pipeline='func(my-pass, my-pass)' foo.mlir -pass-statistics -pass-statistics-display=list
552
553===-------------------------------------------------------------------------===
554                         ... Pass statistics report ...
555===-------------------------------------------------------------------------===
556MyPass
557  (S) 21 testStat - A test statistic
558```
559
560## Declarative Pass Specification
561
562Some aspects of a Pass may be specified declaratively, in a form similar to
563[operations](OpDefinitions.md). This specification simplifies several
564mechanisms used when defining passes. It can be used for generating pass
565registration calls, defining boilerplate pass utilities, and generating pass
566documentation.
567
568Consider the following pass specified in C++:
569
570```c++
571struct MyPass : PassWrapper<MyPass, OperationPass<ModuleOp>> {
572  ...
573
574  /// Options.
575  Option<bool> option{
576      *this, "example-option",
577      llvm::cl::desc("An example option"), llvm::cl::init(true)};
578  ListOption<int64_t> listOption{
579      *this, "example-list",
580      llvm::cl::desc("An example list option"), llvm::cl::ZeroOrMore,
581      llvm::cl::MiscFlags::CommaSeparated};
582
583  /// Statistics.
584  Statistic statistic{this, "example-statistic", "An example statistic"};
585};
586
587/// Expose this pass to the outside world.
588std::unique_ptr<Pass> foo::createMyPass() {
589  return std::make_unique<MyPass>();
590}
591
592static PassRegistration<MyPass> pass("my-pass", "My pass summary");
593```
594
595This pass may be specified declaratively as so:
596
597```tablegen
598def MyPass : Pass<"my-pass", "ModuleOp"> {
599  let summary = "My Pass Summary";
600  let description = [{
601    Here we can now give a much larger description of `MyPass`, including all of
602    its various constraints and behavior.
603  }];
604
605  // A constructor must be provided to specify how to create a default instance
606  // of MyPass.
607  let constructor = "foo::createMyPass()";
608
609  // Specify any options.
610  let options = [
611    Option<"option", "example-option", "bool", /*default=*/"true",
612           "An example option">,
613    ListOption<"listOption", "example-list", "int64_t",
614               "An example list option",
615               "llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::CommaSeparated">
616  ];
617
618  // Specify any statistics.
619  let statistics = [
620    Statistic<"statistic", "example-statistic", "An example statistic">
621  ];
622}
623```
624
625We can include the generated registration calls via:
626
627```c++
628void registerMyPasses() {
629  // The generated registration is not static, so we need to include this in
630  // a location that we can call into.
631#define GEN_PASS_REGISTRATION
632#include "Passes.h.inc"
633}
634```
635
636We can then update the original C++ pass definition:
637
638```c++
639/// Include the generated base pass class definitions.
640#define GEN_PASS_CLASSES
641#include "Passes.h.inc"
642
643// Define the main class as deriving from the generated base class.
644struct MyPass : MyPassBase<MyPass> {
645  ...
646};
647
648/// Expose this pass to the outside world.
649std::unique_ptr<Pass> foo::createMyPass() {
650  return std::make_unique<MyPass>();
651}
652```
653
654### Tablegen Specification
655
656The `Pass` class is used to begin a new pass definition. This class takes as an
657argument the command line argument to attribute to the pass, as well as an
658optional string corresponding to the operation type that the pass operates on.
659It contains the following fields:
660
661*   summary
662    -   A short one line summary of the pass, used as the description when
663        registering the pass.
664*   description
665    -   A longer, more detailed description of the pass. This is used when
666        generating pass documentation.
667*   constructor
668    -   A piece of C++ code used to create a default instance of the pass.
669*   options
670    -   A list of pass options used by the pass.
671*   statistics
672    -   A list of pass statistics used by the pass.
673
674#### Options
675
676Options can be specified by the `Option` and `ListOption` classes. The `Option`
677class takes the following fields:
678
679*   C++ variable name
680    -   A name to use for the generated option variable.
681*   argument
682    -   The command line argument of the option.
683*   type
684    -   The C++ type of the option.
685*   default value
686    -   The default option value.
687*   description
688    -   A one line description of the option.
689*   additional option flags
690    -   A string containing any additional options necessary to construct the
691        option.
692
693The `ListOption` class takes the following fields:
694
695*   C++ variable name
696    -   A name to use for the generated option variable.
697*   argument
698    -   The command line argument of the option.
699*   element type
700    -   The C++ type of the list element.
701*   description
702    -   A one line description of the option.
703*   additional option flags
704    -   A string containing any additional options necessary to construct the
705        option.
706
707#### Statistic
708
709Statistics can be specified via the `Statistic`, which takes the following
710fields:
711
712*   C++ variable name
713    -   A name to use for the generated statistic variable.
714*   display name
715    -   The name used when displaying the statistic.
716*   description
717    -   A one line description of the statistic.
718
719## Pass Instrumentation
720
721MLIR provides a customizable framework to instrument pass execution and analysis
722computation. This is provided via the `PassInstrumentation` class. This class
723provides hooks into the PassManager that observe various pass events:
724
725*   `runBeforePipeline`
726    *   This callback is run just before a pass pipeline, i.e. pass manager, is
727        executed.
728*   `runAfterPipeline`
729    *   This callback is run right after a pass pipeline has been executed,
730        successfully or not.
731*   `runBeforePass`
732    *   This callback is run just before a pass is executed.
733*   `runAfterPass`
734    *   This callback is run right after a pass has been successfully executed.
735        If this hook is executed, runAfterPassFailed will not be.
736*   `runAfterPassFailed`
737    *   This callback is run right after a pass execution fails. If this hook is
738        executed, runAfterPass will not be.
739*   `runBeforeAnalysis`
740    *   This callback is run just before an analysis is computed.
741*   `runAfterAnalysis`
742    *   This callback is run right after an analysis is computed.
743
744PassInstrumentation objects can be registered directly with a
745[PassManager](#pass-manager) instance via the `addInstrumentation` method.
746Instrumentations added to the PassManager are run in a stack like fashion, i.e.
747the last instrumentation to execute a `runBefore*` hook will be the first to
748execute the respective `runAfter*` hook. Below in an example instrumentation
749that counts the number of times DominanceInfo is computed:
750
751```c++
752struct DominanceCounterInstrumentation : public PassInstrumentation {
753  unsigned &count;
754
755  DominanceCounterInstrumentation(unsigned &count) : count(count) {}
756  void runAfterAnalysis(llvm::StringRef, TypeID id, Operation *) override {
757    if (id == TypeID::get<DominanceInfo>())
758      ++count;
759  }
760};
761
762MLIRContext *ctx = ...;
763PassManager pm(ctx);
764
765// Add the instrumentation to the pass manager.
766unsigned domInfoCount;
767pm.addInstrumentation(
768    std::make_unique<DominanceCounterInstrumentation>(domInfoCount));
769
770// Run the pass manager on a module operation.
771ModuleOp m = ...;
772if (failed(pm.run(m)))
773    ...
774
775llvm::errs() << "DominanceInfo was computed " << domInfoCount << " times!\n";
776```
777
778### Standard Instrumentations
779
780MLIR utilizes the pass instrumentation framework to provide a few useful
781developer tools and utilities. Each of these instrumentations are immediately
782available to all users of the MLIR pass framework.
783
784#### Pass Timing
785
786The PassTiming instrumentation provides timing information about the execution
787of passes and computation of analyses. This provides a quick glimpse into what
788passes are taking the most time to execute, as well as how much of an effect
789your pass has on the total execution time of the pipeline. Users can enable this
790instrumentation directly on the PassManager via `enableTiming`. This
791instrumentation is also made available in mlir-opt via the `-pass-timing` flag.
792The PassTiming instrumentation provides several different display modes for the
793timing results, each of which is described below:
794
795##### List Display Mode
796
797In this mode, the results are displayed in a list sorted by total time with each
798pass/analysis instance aggregated into one unique result. This view is useful
799for getting an overview of what analyses/passes are taking the most time in a
800pipeline. This display mode is available in mlir-opt via
801`-pass-timing-display=list`.
802
803```shell
804$ mlir-opt foo.mlir -disable-pass-threading -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing -pass-timing-display=list
805
806===-------------------------------------------------------------------------===
807                      ... Pass execution timing report ...
808===-------------------------------------------------------------------------===
809  Total Execution Time: 0.0203 seconds
810
811   ---Wall Time---  --- Name ---
812   0.0047 ( 55.9%)  Canonicalizer
813   0.0019 ( 22.2%)  VerifierPass
814   0.0016 ( 18.5%)  LLVMLoweringPass
815   0.0003 (  3.4%)  CSE
816   0.0002 (  1.9%)  (A) DominanceInfo
817   0.0084 (100.0%)  Total
818```
819
820##### Pipeline Display Mode
821
822In this mode, the results are displayed in a nested pipeline view that mirrors
823the internal pass pipeline that is being executed in the pass manager. This view
824is useful for understanding specifically which parts of the pipeline are taking
825the most time, and can also be used to identify when analyses are being
826invalidated and recomputed. This is the default display mode.
827
828```shell
829$ mlir-opt foo.mlir -disable-pass-threading -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing
830
831===-------------------------------------------------------------------------===
832                      ... Pass execution timing report ...
833===-------------------------------------------------------------------------===
834  Total Execution Time: 0.0249 seconds
835
836   ---Wall Time---  --- Name ---
837   0.0058 ( 70.8%)  'func' Pipeline
838   0.0004 (  4.3%)    CSE
839   0.0002 (  2.6%)      (A) DominanceInfo
840   0.0004 (  4.8%)    VerifierPass
841   0.0046 ( 55.4%)    Canonicalizer
842   0.0005 (  6.2%)    VerifierPass
843   0.0005 (  5.8%)  VerifierPass
844   0.0014 ( 17.2%)  LLVMLoweringPass
845   0.0005 (  6.2%)  VerifierPass
846   0.0082 (100.0%)  Total
847```
848
849##### Multi-threaded Pass Timing
850
851When multi-threading is enabled in the pass manager the meaning of the display
852slightly changes. First, a new timing column is added, `User Time`, that
853displays the total time spent across all threads. Secondly, the `Wall Time`
854column displays the longest individual time spent amongst all of the threads.
855This means that the `Wall Time` column will continue to give an indicator on the
856perceived time, or clock time, whereas the `User Time` will display the total
857cpu time.
858
859```shell
860$ mlir-opt foo.mlir -pass-pipeline='func(cse,canonicalize)' -convert-std-to-llvm -pass-timing
861
862===-------------------------------------------------------------------------===
863                      ... Pass execution timing report ...
864===-------------------------------------------------------------------------===
865  Total Execution Time: 0.0078 seconds
866
867   ---User Time---   ---Wall Time---  --- Name ---
868   0.0177 ( 88.5%)     0.0057 ( 71.3%)  'func' Pipeline
869   0.0044 ( 22.0%)     0.0015 ( 18.9%)    CSE
870   0.0029 ( 14.5%)     0.0012 ( 15.2%)      (A) DominanceInfo
871   0.0038 ( 18.9%)     0.0015 ( 18.7%)    VerifierPass
872   0.0089 ( 44.6%)     0.0025 ( 31.1%)    Canonicalizer
873   0.0006 (  3.0%)     0.0002 (  2.6%)    VerifierPass
874   0.0004 (  2.2%)     0.0004 (  5.4%)  VerifierPass
875   0.0013 (  6.5%)     0.0013 ( 16.3%)  LLVMLoweringPass
876   0.0006 (  2.8%)     0.0006 (  7.0%)  VerifierPass
877   0.0200 (100.0%)     0.0081 (100.0%)  Total
878```
879
880#### IR Printing
881
882When debugging it is often useful to dump the IR at various stages of a pass
883pipeline. This is where the IR printing instrumentation comes into play. This
884instrumentation allows for conditionally printing the IR before and after pass
885execution by optionally filtering on the pass being executed. This
886instrumentation can be added directly to the PassManager via the
887`enableIRPrinting` method. `mlir-opt` provides a few useful flags for utilizing
888this instrumentation:
889
890*   `print-ir-before=(comma-separated-pass-list)`
891    *   Print the IR before each of the passes provided within the pass list.
892*   `print-ir-before-all`
893    *   Print the IR before every pass in the pipeline.
894
895```shell
896$ mlir-opt foo.mlir -pass-pipeline='func(cse)' -print-ir-before=cse
897
898*** IR Dump Before CSE ***
899func @simple_constant() -> (i32, i32) {
900  %c1_i32 = constant 1 : i32
901  %c1_i32_0 = constant 1 : i32
902  return %c1_i32, %c1_i32_0 : i32, i32
903}
904```
905
906*   `print-ir-after=(comma-separated-pass-list)`
907    *   Print the IR after each of the passes provided within the pass list.
908*   `print-ir-after-all`
909    *   Print the IR after every pass in the pipeline.
910
911```shell
912$ mlir-opt foo.mlir -pass-pipeline='func(cse)' -print-ir-after=cse
913
914*** IR Dump After CSE ***
915func @simple_constant() -> (i32, i32) {
916  %c1_i32 = constant 1 : i32
917  return %c1_i32, %c1_i32 : i32, i32
918}
919```
920
921*   `print-ir-after-change`
922    *   Only print the IR after a pass if the pass mutated the IR. This helps to
923        reduce the number of IR dumps for "uninteresting" passes.
924    *   Note: Changes are detected by comparing a hash of the operation before
925        and after the pass. This adds additional run-time to compute the hash of
926        the IR, and in some rare cases may result in false-positives depending
927        on the collision rate of the hash algorithm used.
928    *   Note: This option should be used in unison with one of the other
929        'print-ir-after' options above, as this option alone does not enable
930        printing.
931
932```shell
933$ mlir-opt foo.mlir -pass-pipeline='func(cse,cse)' -print-ir-after=cse -print-ir-after-change
934
935*** IR Dump After CSE ***
936func @simple_constant() -> (i32, i32) {
937  %c1_i32 = constant 1 : i32
938  return %c1_i32, %c1_i32 : i32, i32
939}
940```
941
942*   `print-ir-module-scope`
943    *   Always print the top-level module operation, regardless of pass type or
944        operation nesting level.
945    *   Note: Printing at module scope should only be used when multi-threading
946        is disabled(`-disable-pass-threading`)
947
948```shell
949$ mlir-opt foo.mlir -disable-pass-threading -pass-pipeline='func(cse)' -print-ir-after=cse -print-ir-module-scope
950
951*** IR Dump After CSE ***  ('func' operation: @bar)
952func @bar(%arg0: f32, %arg1: f32) -> f32 {
953  ...
954}
955
956func @simple_constant() -> (i32, i32) {
957  %c1_i32 = constant 1 : i32
958  %c1_i32_0 = constant 1 : i32
959  return %c1_i32, %c1_i32_0 : i32, i32
960}
961
962*** IR Dump After CSE ***  ('func' operation: @simple_constant)
963func @bar(%arg0: f32, %arg1: f32) -> f32 {
964  ...
965}
966
967func @simple_constant() -> (i32, i32) {
968  %c1_i32 = constant 1 : i32
969  return %c1_i32, %c1_i32 : i32, i32
970}
971```
972
973## Crash and Failure Reproduction
974
975The [pass manager](#pass-manager) in MLIR contains a builtin mechanism to
976generate reproducibles in the even of a crash, or a
977[pass failure](#pass-failure). This functionality can be enabled via
978`PassManager::enableCrashReproducerGeneration` or via the command line flag
979`pass-pipeline-crash-reproducer`. In either case, an argument is provided that
980corresponds to the output `.mlir` file name that the reproducible should be
981written to. The reproducible contains the configuration of the pass manager that
982was executing, as well as the initial IR before any passes were run. A potential
983reproducible may have the form:
984
985```mlir
986// configuration: -pass-pipeline='func(cse, canonicalize), inline'
987// note: verifyPasses=false
988
989module {
990  func @foo() {
991    ...
992  }
993}
994```
995