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