执行如下命令,可以看到IR经历的所有pass以及中间IR,以mnist为例:
./build/Debug/bin/onnx-mlir ./docs/mnist_example/mnist.onnx --mlir-elide-elementsattrs-if-larger=10 --mlir-print-ir-after-all &> log.log
因为默认是O0,加入参数--O3尝试一下,二者log并不一样,看起来是加入参数O3起到了优化作用。
onnx-mlir与onnx在结构上没有什么区别:
在onnx dialect层面,多个pass之后,IR变化很小,O0和O3也没有区别。个人理解onnx-mlir是为了与onnx结构对齐,作用就是使onnx可以方便、直观的转换到mlir上来,很少涉及优化的概念。
之后就是转换到krnl dialect了,O0和O3在这一步就不同了。这里mnist看起来还是有些复杂,再单独拆一个MatMul出来看吧。
打开--O3之后,调试发现会走到这里来:
void replace2x2Matmul2d(Operation *op, ONNXMatMulOpAdaptor &operandAdaptor,
...) const {...}
这里最终会转换成一个多层的循环,最底层是krnl.matmul,而--O0最底层是arith.mulf。
之后是ConvertKrnlToAffinePass,这里其实最底层调用的还是arith.mulf,和--O0一样。
之后就都是调用mlir内置pass处理内置dialect了,直到ConvertKrnlToLLVMPass有一个转换,也和matmul算子无关。
对于matmul算子,krnl dialect就是做了循环优化,还有几个问题不太清楚:①为什么是这种循环结构?(可能看到最底层的指令会有新的发现)②llvm内置的dialect和pass不能做吗?③换一种底层硬件怎么办?(有时间试一下IBM Telum)