An MLIR input may trigger bugs after series of transformations. To root cause the problem or help verification after fixes, developers want to be able to reduce the size of a reproducer for a bug. This document describes mlir-reduce
, which is similar to bugpoint, a tool that can reduce the size of the input needed to trigger the error.
mlir-reduce
supports reducing the input in several ways, including simply deleting code not required to reproduce an error, applying the reducer patterns heuristically or run with optimization passes to reduce the input. To use it, the first thing you need to do is, provide a command which tells if an input is interesting, e.g., exhibits the characteristics that you would like to focus on. For example, you may want to see if mlir-opt
invocation fails after it runs on the certain MLIR input. Afterwards, select your reduction strategy then mlir-reduce
will do the remaining works for you.
mlir-reduce
adopts the reduction-tree algorithm to reduce the input. It generates several reduced outputs and further reduces in between them according to the tree traversal strategy. The different strategies may lead to different results and different time complexity. You can run as -reduction-tree='traversal-mode=0'
to select the mode for example.
As mentioned, you need to provide a command to mlir-reduce
which identifies cases you're interested in. For each intermediate output generated during reduction, mlir-reduce
will run the command over the it, the script should returns 1 for interesting case, 0 otherwise. The sample script,
mlir-opt -convert-vector-to-spirv $1 | grep "failed to materialize" if [[ $? -eq 1 ]]; then exit 1 else exit 0 fi
The sample usage will be like, note that the test
argument is part of the mode argument.
mlir-reduce $INPUT -reduction-tree='traversal-mode=0 test=$TEST_SCRIPT'
mlir-reduce
will try to remove the operations directly. This is the most aggressive reduction as it may result in an invalid output as long as it ends up retaining the error message that the test script is interesting. To avoid that, mlir-reduce
always checks the validity and it expects the user will provide a valid input as well.
In some cases, rewrite an operation into a simpler or smaller form can still retain the interestingness. For example, mlir-reduce
will try to rewrite a tensor<?xindex>
with unknown rank into a constant rank one like tensor<1xi32>
. Not only produce a simpler operation, it may introduce further reduction chances because of precise type information.
MLIR supports dialects and mlir-reduce
supports rewrite patterns for every dialect as well. Which means you can have the dialect specific rewrite patterns. To do that, you need to implement the DialectReductionPatternInterface
. For example,
#include "mlir/Reducer/ReductionPatternInterface.h" struct MyReductionPatternInterface : public DialectReductionPatternInterface { virtual void populateReductionPatterns(RewritePatternSet &patterns) const final { populateMyReductionPatterns(patterns); } }
mlir-reduce
will call populateReductionPatterns
to collect the reduction rewrite patterns provided by each dialect. Here's a hint, if you use DRR to write the reduction patterns, you can leverage the method populateWithGenerated
generated by mlir-tblgen
.
MLIR provides amount of transformation passes and some of them are useful for reducing the input size, e.g., Symbol-DCE. mlir-reduce
will schedule them along with above two strategies.
In the cases of, 1. have defined a custom syntax, 2. the failure is specific to certain dialects or 3. there's a dialect specific reducer patterns, you need to build your own mlir-reduce
. Link it with MLIRReduceLib
and implement it like,
#include "mlir/Tools/mlir-reduce/MlirReduceMain.h" using namespace mlir; int main(int argc, char **argv) { DialectRegistry registry; registerMyDialects(registry); // Register the DialectReductionPatternInterface if any. MLIRContext context(registry); return failed(mlirReduceMain(argc, argv, context)); }
mlir-reduce
is missing several features,
-reduction-tree
now only supports Single-Path
traversal mode, extends it with different traversal strategies may reduce the input better.