xref: /llvm-project/mlir/docs/Tools/mlir-reduce.md (revision 286a7a4023361aa63230596e88366c3d86776921)
1# MLIR Reduce
2
3[TOC]
4
5An MLIR input may trigger bugs after series of transformations. To root cause
6the problem or help verification after fixes, developers want to be able to
7reduce the size of a reproducer for a bug. This document describes
8`mlir-reduce`, which is similar to
9[bugpoint](https://llvm.org/docs/CommandGuide/bugpoint.html), a tool that can
10reduce the size of the input needed to trigger the error.
11
12`mlir-reduce` supports reducing the input in several ways, including simply
13deleting code not required to reproduce an error, applying the reducer
14patterns heuristically or run with optimization passes to reduce the input. To
15use it, the first thing you need to do is, provide a command which tells if an
16input is interesting, e.g., exhibits the characteristics that you would like to
17focus on. For example, you may want to see if `mlir-opt` invocation fails after
18it runs on the certain MLIR input. Afterwards, select your reduction strategy
19then `mlir-reduce` will do the remaining works for you.
20
21## How to Use it
22
23`mlir-reduce` adopts the reduction-tree algorithm to reduce the input. It
24generates several reduced outputs and further reduces in between them according
25to the tree traversal strategy. The different strategies may lead to different
26results and different time complexity. You can run as
27`-reduction-tree='traversal-mode=0'` to select the mode for example.
28
29### Write the script for testing interestingness
30
31As mentioned, you need to provide a command to `mlir-reduce` which identifies
32cases you're interested in. For each intermediate output generated during
33reduction, `mlir-reduce` will run the command over the it, the script should
34returns 1 for interesting case, 0 otherwise. The sample script,
35
36```shell
37mlir-opt -convert-vector-to-spirv $1 | grep "failed to materialize"
38if [[ $? -eq 1 ]]; then
39  exit 1
40else
41  exit 0
42fi
43```
44
45The sample usage will be like, note that the `test` argument is part of the mode
46argument.
47
48```shell
49mlir-reduce $INPUT -reduction-tree='traversal-mode=0 test=$TEST_SCRIPT'
50```
51
52## Available reduction strategies
53
54### Operation elimination
55
56`mlir-reduce` will try to remove the operations directly. This is the most
57aggressive reduction as it may result in an invalid output as long as it ends up
58retaining the error message that the test script is interesting. To avoid that,
59`mlir-reduce` always checks the validity and it expects the user will provide a
60valid input as well.
61
62### Rewrite patterns into simpler forms
63
64In some cases, rewrite an operation into a simpler or smaller form can still
65retain the interestingness. For example, `mlir-reduce` will try to rewrite a
66`tensor<?xindex>` with unknown rank into a constant rank one like
67`tensor<1xi32>`. Not only produce a simpler operation, it may introduce further
68reduction chances because of precise type information.
69
70MLIR supports dialects and `mlir-reduce` supports rewrite patterns for every
71dialect as well. Which means you can have the dialect specific rewrite patterns.
72To do that, you need to implement the `DialectReductionPatternInterface`. For
73example,
74
75```c++
76#include "mlir/Reducer/ReductionPatternInterface.h"
77
78struct MyReductionPatternInterface : public DialectReductionPatternInterface {
79  virtual void
80  populateReductionPatterns(RewritePatternSet &patterns) const final {
81    populateMyReductionPatterns(patterns);
82  }
83}
84```
85
86`mlir-reduce` will call `populateReductionPatterns` to collect the reduction
87rewrite patterns provided by each dialect. Here's a hint, if you use
88[DRR](../DeclarativeRewrites.md) to write the reduction patterns, you can
89leverage the method `populateWithGenerated` generated by `mlir-tblgen`.
90
91### Reduce with built-in optimization passes
92
93MLIR provides amount of transformation passes and some of them are useful for
94reducing the input size, e.g., Symbol-DCE. `mlir-reduce` will schedule them
95along with above two strategies.
96
97## Build a custom mlir-reduce
98
99In the cases of, 1. have defined a custom syntax, 2. the failure is specific to
100certain dialects or 3. there's a dialect specific reducer patterns, you need to
101build your own `mlir-reduce`. Link it with `MLIRReduceLib` and implement it
102like,
103
104```c++
105#include "mlir/Tools/mlir-reduce/MlirReduceMain.h"
106using namespace mlir;
107
108int main(int argc, char **argv) {
109  DialectRegistry registry;
110  registerMyDialects(registry);
111  // Register the DialectReductionPatternInterface if any.
112  MLIRContext context(registry);
113  return failed(mlirReduceMain(argc, argv, context));
114}
115
116```
117
118## Future works
119
120`mlir-reduce` is missing several features,
121
122*   `-reduction-tree` now only supports `Single-Path` traversal mode, extends it
123with different traversal strategies may reduce the input better.
124*   Produce the optimal result when interrupted. The reduction process may take
125a quite long time, it'll be better to get an optimal result so far while an
126interrupt is triggered.
127