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