Lines Matching full:pass
1 # Pass Infrastructure
6 This document provides an overview of the pass infrastructure in MLIR and how to
16 ## Operation Pass
19 [operation](LangRef.md/#operations). As such, the pass manager is designed to
21 paragraphs, we refer to the operation that a pass operates on as the "current
24 The structure of the [pass manager](#pass-manager), and the concept of nesting,
40 * Must not maintain mutable pass state across invocations of `runOnOperation`.
41 A pass may be run on many different operations with no guarantee of
43 * When multithreading, a specific pass instance may not even execute on
44 all operations within the IR. As such, a pass should not rely on running
48 pass.
50 * Multiple instances of the pass may be created by the pass manager to
55 By default, an operation pass is `op-agnostic`, meaning that it operates on the
56 operation type of the pass manager that it is added to. This means a pass may operate
58 they do not make assumptions on the operation they run on. Examples of this type of pass are
61 To create an agnostic operation pass, a derived class must adhere to the following:
66 A simple pass may look like:
82 ### Filtered Operation Pass
84 If a pass needs to constrain its execution to specific types or classes of operations,
85 additional filtering may be applied on top. This transforms a once `agnostic` pass into
87 execution of a pass, and different contexts in which filtering may apply:
89 ### Operation Pass: Static Schedule Filtering
92 pass may be scheduled on. This type of filtering generally allows for building more
96 applies to all instances of that operation type. Below is an example of a pass that only
102 /// pass may be scheduled on the given operation type.
109 // that our pass is only executed on operations implementing that interface.
115 When a pass with static filtering is added to an [`op-specific` pass manager](#oppassmanager),
116 it asserts that the operation type of the pass manager satisfies the static constraints of the
117 pass. When added to an [`op-agnostic` pass manager](#oppassmanager), that pass manager, and all
118 passes contained within, inherits the static constraints of the pass. For example, if the pass
120 implement `FunctionOpInterface` will be considered when executing **any** passes within the pass
121 manager. This invariant is important to keep in mind, as each pass added to an `op-agnostic` pass
135 If we were to apply the op-agnostic pipeline, `any(cse,my-function-pass)`, to the above MLIR snippet
136 it would only run on the `foo` function operation. This is because the `my-function-pass` has a
138 that this constraint is inherited by the entire pass manager, so we never consider `someModule` for
141 #### Operation Pass: Static Filtering By Op Type
144 that a pass may be scheduled on. Sugar is provided on top of that mechanism to simplify the definition
145 of passes that are restricted to scheduling on a single operation type. In these cases, a pass simply
162 #### Operation Pass: Static Filtering By Interface
165 that a pass may be scheduled on. Sugar is provided on top of that mechanism to simplify the definition
166 of passes that are restricted to scheduling on a specific operation interface. In these cases, a pass
188 loaded before starting the execution of a multi-threaded pass pipeline. To this
189 end, a pass that may create an entity from a dialect that isn't guaranteed to
197 In certain situations, a Pass may contain state that is constructed dynamically,
198 but is potentially expensive to recompute in successive runs of the Pass. One
201 runtime. In these situations, a pass may override the following hook to
206 This hook is executed once per run of a full pass pipeline, meaning that it does
211 In case of an error during initialization, the pass is expected to emit an error
212 diagnostic and return a `failure()` which will abort the pass pipeline execution.
303 Analyses that are constructed after being queried by a pass are cached to avoid
305 analyses, all analyses are assumed to be invalidated by a pass. To avoid
306 invalidation, a pass must specifically mark analyses that are known to be
309 * All Pass classes automatically provide the following utilities for
316 // Mark all analyses as preserved. This is useful if a pass can guarantee
327 ## Pass Failure
330 of the pass was broken, potentially leaving the IR in some invalid state. If
331 such a situation occurs, the pass can directly signal a failure to the pass
332 manager via the `signalPassFailure` method. If a pass signaled a failure when
344 ## Pass Manager
348 be used to configure and schedule a pass pipeline. There are two main classes
349 related to pass management, the `PassManager` and the `OpPassManager`. The
351 configurations used for the entire pass pipeline. The `OpPassManager` class is
358 operations at a given level of nesting. A pass manager may be `op-specific`
361 anchor pass managers must adhere to the following requirement:
371 Passes can be added to a pass manager via `addPass`.
375 former method takes the operation type that the nested pass manager will operate on.
376 The latter method nests an `op-agnostic` pass manager, that may run on any viable
408 // Add a pass on the top-level module operation.
411 // Nest a pass manager that operates on `spirv.module` operations nested
416 // Nest a pass manager that operates on functions within the nested SPIRV
421 // Nest an op-agnostic pass manager. This will operate on any viable
427 // Run the pass manager on the top-level module.
433 The above pass manager contains the following pipeline structure:
459 ## Dynamic Pass Pipelines
461 In some situations it may be useful to run a pass pipeline within another pass,
464 [Inliner Pass](Passes.md/#-inline) may want to run
469 Pass::runPipeline(OpPassManager &, Operation *)` method. This method returns
489 The mechanism described in this section should be used whenever a pass pipeline
491 scheduled statically along with the rest of the main pass pipeline. More
493 within a `Pass`. Using `runPipeline` also ensures that all analyses,
494 [instrumentations](#pass-instrumentation), and other pass manager related
497 ## Instance Specific Pass Options
500 its behavior. These options are parsed at pass construction time independently
501 for each instance of the pass. Options are defined using the `Option<>` and
514 MyPass(const MyPass& pass) {}
523 For pass pipelines, the `PassPipelineRegistration` templates take an additional
528 which should construct the passes from the options and pass them to the pm:
532 // The structure of these options is the same as those for pass options.
542 // Initialize the pass manager.
547 ## Pass Statistics
552 Pass statistics are specific to each pass instance, which allow for seeing the
553 effect of placing a particular transformation at specific places within the pass
557 Statistics can be added to a pass by using the 'Pass::Statistic' class. This
558 class takes as a constructor arguments: the parent pass, a name, and a
564 the [pass manager](#pass-manager) programmatically via
565 `PassManager::enableStatistics`; or via `-mlir-pass-statistics` and
566 `-mlir-pass-statistics-display` on the command line.
575 MyPass(const MyPass& pass) {}
577 // This is the argument used to refer to the pass in
582 // This is a brief description of the pass.
601 A pipeline view that models the structure of the pass manager, this is the
605 $ mlir-opt -pass-pipeline='any(func.func(my-pass,my-pass))' foo.mlir -mlir-pass-statistics
608 ... Pass statistics report ...
620 A list view that aggregates the statistics of all instances of a specific pass
624 $ mlir-opt -pass-pipeline='any(func.func(my-pass,my-pass))' foo.mlir -mlir-pass-statistics -mlir-pass-statistics-display=list
627 ... Pass statistics report ...
633 ## Pass Registration
635 Briefly shown in the example definitions of the various pass types is the
636 `PassRegistration` class. This mechanism allows for registering pass classes so
638 [textual pass pipeline description](#textual-pass-pipeline-specification). An
647 * `MyPass` is the name of the derived pass class.
648 * The pass `getArgument()` method is used to get the identifier that will be
649 used to refer to the pass.
650 * The pass `getDescription()` method provides a short summary describing the
651 pass.
654 optional argument that takes a callback to create the pass:
659 []() -> std::unique_ptr<Pass> {
660 std::unique_ptr<Pass> p = std::make_unique<MyParametricPass>(/*options*/);
661 /*... non-trivial-logic to configure the pass ...*/;
668 configuration of a pass from command-line arguments and pass it to the pass
671 Note: Make sure that the pass is copy-constructible in a way that does not share
672 data as the [pass manager](#pass-manager) may create copies of the pass to run
675 ### Pass Pipeline Registration
677 Described above is the mechanism used for registering a specific derived pass
678 class. On top of that, MLIR allows for registering custom pass pipelines in a
706 ### Textual Pass Pipeline Specification
708 The previous sections detailed how to register passes and pass pipelines with a
710 configure a pass manager from a string description. This is especially useful
711 for tools like `mlir-opt`, that configure pass managers from the command line,
713 [dynamic pass pipelines](#dynamic-pass-pipelines).
715 To support the ability to describe the full structure of pass pipelines, MLIR
716 supports a custom textual description of pass pipelines. The textual description
717 includes the nesting structure, the arguments of the passes and pass pipelines
724 pipeline-element ::= pipeline | (pass-name | pass-pipeline-name) options?
730 pass manager. This is either the name of an operation to run passes on,
731 e.g. `func.func` or `builtin.module`, or `any`, for op-agnostic pass
733 can be used to anchor a pass manager).
734 * `pass-name` | `pass-pipeline-name`
735 * This corresponds to the argument of a registered pass or pass pipeline,
739 pass or pass pipeline, as described in the
740 ["Instance Specific Pass Options"](#instance-specific-pass-options)
749 Can also be specified as (via the `-pass-pipeline` flag):
753 $ mlir-opt foo.mlir -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm{use-bare-ptr-memref-call-conv=1})'
756 $ mlir-opt foo.mlir -pass-pipeline='builtin.module(any(cse,canonicalize),convert-func-to-llvm{use-bare-ptr-memref-call-conv=1})'
759 In order to support round-tripping a pass to the textual representation using
761 Pass::getArgument()` to specify the argument used when registering a pass.
763 ## Declarative Pass Specification
765 Some aspects of a Pass may be specified declaratively, in a form similar to
767 used when defining passes. It can be used for generating pass registration
768 calls, defining boilerplate pass utilities, and generating pass documentation.
770 Consider the following pass specified in C++:
791 /// Expose this pass to the outside world.
792 std::unique_ptr<Pass> foo::createMyPass() {
796 /// Register this pass.
802 This pass may be specified declaratively as so:
805 def MyPass : Pass<"my-pass", "ModuleOp"> {
806 let summary = "My Pass Summary";
832 Using the `gen-pass-decls` generator, we can generate most of the boilerplate
838 each pass, the generator produces a `registerPassName` where
844 // Tablegen options: -gen-pass-decls -name="Example"
864 The second is to provide a way to configure the pass options. These classes are
865 named in the form of `MyPassOptions`, where `MyPass` is the name of the pass
868 passes by defining the `GEN_PASS_DECL` macro, or on a per-pass basis by defining
896 std::unique_ptr<::mlir::Pass> createMyPass();
897 std::unique_ptr<::mlir::Pass> createMyPass(const MyPassOptions &options);
904 passes, containing most of the boiler plate related to pass definitions. These
906 `impl` namespace, where `MyPass` is the name of the pass definition in
907 tablegen. We can update the original C++ pass definition as so:
912 /// Include the generated base pass class definitions.
927 These definitions can be enabled on a per-pass basis by defining the appropriate
929 uppercase version of the name of the pass definition in tablegen.
931 constructors are also defined and expect the name of the actual pass class to
934 Using the `gen-pass-doc` generator, markdown documentation for each of the
940 The `Pass` class is used to begin a new pass definition. This class takes as an
941 argument the registry argument to attribute to the pass, as well as an optional
942 string corresponding to the operation type that the pass operates on. The class
946 - A short one-line summary of the pass, used as the description when
947 registering the pass.
949 - A longer, more detailed description of the pass. This is used when
950 generating pass documentation.
952 - A list of strings representing the `Dialect` classes this pass may
955 - A code block used to create a default instance of the pass.
957 - A list of pass options used by the pass.
959 - A list of pass statistics used by the pass.
981 def MyPass : Pass<"my-pass"> {
1004 def MyPass : Pass<"my-pass"> {
1025 def MyPass : Pass<"my-pass"> {
1032 ## Pass Instrumentation
1034 MLIR provides a customizable framework to instrument pass execution and analysis
1039 * This callback is run just before a pass pipeline, i.e. pass manager, is
1042 * This callback is run right after a pass pipeline has been executed,
1045 * This callback is run just before a pass is executed.
1047 * This callback is run right after a pass has been successfully executed.
1050 * This callback is run right after a pass execution fails. If this hook is
1062 [PassManager](#pass-manager) instance via the `addInstrumentation` method.
1085 // Add the instrumentation to the pass manager.
1090 // Run the pass manager on a module operation.
1100 MLIR utilizes the pass instrumentation framework to provide a few useful
1102 available to all users of the MLIR pass framework.
1104 #### Pass Timing
1109 pass has on the total execution time of the pipeline. Users can enable this
1118 pass/analysis instance aggregated into one unique result. This view is useful
1124 $ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm)' -mlir-timing -mlir-timing-display=list
1149 $ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm)' -mlir-timing -mlir-timing-display=list -mlir-output-format=json
1170 the internal pass pipeline that is being executed in the pass manager. This view
1176 $ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm)' -mlir-timing
1199 $ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm)' -mlir-timing -mlir-output-format=json
1223 ##### Multi-threaded Pass Timing
1225 When multi-threading is enabled in the pass manager the meaning of the display
1234 $ mlir-opt foo.mlir -pass-pipeline='builtin.module(func.func(cse,canonicalize),convert-func-to-llvm)' -mlir-timing
1237 ... Pass execution timing report ...
1256 When debugging it is often useful to dump the IR at various stages of a pass
1258 instrumentation allows for conditionally printing the IR before and after pass
1259 execution by optionally filtering on the pass being executed. This
1264 * `mlir-print-ir-before=(comma-separated-pass-list)`
1265 * Print the IR before each of the passes provided within the pass list.
1267 * Print the IR before every pass in the pipeline.
1270 $ mlir-opt foo.mlir -pass-pipeline='func.func(cse)' -mlir-print-ir-before=cse
1280 * `mlir-print-ir-after=(comma-separated-pass-list)`
1281 * Print the IR after each of the passes provided within the pass list.
1283 * Print the IR after every pass in the pipeline.
1286 $ mlir-opt foo.mlir -pass-pipeline='func.func(cse)' -mlir-print-ir-after=cse
1296 * Only print the IR after a pass if the pass mutated the IR. This helps to
1299 and after the pass. This adds additional run-time to compute the hash of
1307 $ mlir-opt foo.mlir -pass-pipeline='func.func(cse,cse)' -mlir-print-ir-after=cse -mlir-print-ir-after-change
1317 * Only print IR after a pass failure.
1322 $ mlir-opt foo.mlir -pass-pipeline='func.func(cse,bad-pass)' -mlir-print-ir-after-failure
1332 * Always print the top-level module operation, regardless of pass type or
1338 $ mlir-opt foo.mlir -mlir-disable-threading -pass-pipeline='func.func(cse)' -mlir-print-ir-after=cse -mlir-print-ir-module-scope
1365 the output corresponding to each pass will be printed to a file in the
1367 pass reflects the nesting structure of the IR and the pass pipeline.
1368 * The below example illustrates the file tree created by running a pass
1375 numeric prefix using the counter value for the op that the pass is
1385 $ mlir-opt foo.mlir -pass-pipeline="$pipeline" -mlir-print-ir-tree-dir=/tmp/pipeline_output
1424 The [pass manager](#pass-manager) in MLIR contains a builtin mechanism to
1426 [pass failure](#pass-failure). This functionality can be enabled via
1428 `mlir-pass-pipeline-crash-reproducer`. In either case, an argument is provided that
1430 written to. The reproducible contains the configuration of the pass manager that
1455 and adjusting the necessary opt state, e.g. configuring the pass manager, context, etc.
1465 `mlir-pass-pipeline-local-reproducer` on the command line, that signals that the pass
1467 generate a reproducer containing IR right before the pass that fails. This is
1468 useful for situations where the crash is known to be within a specific pass, or
1475 For example, if the failure in the previous example came from the `canonicalize` pass,