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