最简加法函数需用func.func定义签名、arith.addi执行运算、func.return显式返回,且所有参数和结果必须带完整类型声明(如(i32, i32) -> i32),缺一不可;否则mlir-opt --verify-diagnostics将因verifier失败而报错。

怎么用 MLIR 写一个最简加法函数(不碰 LLVM IR)
直接结论:不用写 LLVM IR,用 MLIR 的 func.func + arith.addi 就能跑通——但必须显式声明类型、签名和返回值,缺一不可,否则 mlir-opt 会报 verifier failed。
MLIR 不是“写完就能跑”的语言,它本质是中间表示,第一步得先让 IR 合法(dialect verifier 通过)。最简加法不是 a + b 一行,而是至少包含:模块容器、函数签名、参数绑定、运算、返回。
-
func.func必须带完整类型签名,比如(i32, i32) -> i32,不能省略括号或写成i32 i32 -> i32 - 参数必须用
%arg0 : i32这种显式绑定形式,不能只写%0 - 必须有
func.return,即使只有一条arith.addi,也不能隐式返回
module {
func.func @add(%arg0: i32, %arg1: i32) -> i32 {
%0 = arith.addi %arg0, %arg1 : i32
func.return %0 : i32
}
}
怎么验证这个加法 IR 是合法的
光写对语法还不够,MLIR 要求每个 op 满足所属 dialect 的约束。比如 arith.addi 只接受整数类型,若传 f32 就会报错:'arith.addi' op requires integer-like operands。
验证命令就是最朴素的 mlir-opt --verify-diagnostics,它会在出错时打印具体位置和原因:
mlir-opt --verify-diagnostics add.mlir
- 如果漏了
func.return,报错是control flow may exit function without returning a value - 如果参数类型写成
%arg0: f32但用arith.addi,报错指向arith.addi行,提示类型不匹配 - 如果用了
arith.addf却传i32,同样触发 verifier 失败
怎么把这函数编译成可执行程序(绕过手写 LLVM)
MLIR 提供了从 func dialect 到 LLVM IR 的标准 lowering 路径,不需要手动拼 llvm.func。关键路径是:func.func → convert-func-to-llvm → reconcile-unrealized-casts → 输出 LLVM IR。
实际命令链(假设文件叫 add.mlir):
mlir-opt \ --convert-func-to-llvm \ --reconcile-unrealized-casts \ add.mlir | \ mlir-translate --mlir-to-llvmir | \ llc -filetype=obj -o add.o && \ clang add.o -o add
-
--convert-func-to-llvm是核心,它把func.func和arith.*映射为 LLVM 函数和add nsw等指令 -
--reconcile-unrealized-casts必须紧跟其后,否则会卡在类型 cast 残留上,报错unrealized_conversion_cast -
mlir-translate --mlir-to-llvmir只负责格式转换,不做 lowering,所以前面必须做完所有转换
为什么不能直接用 arith.addi 在顶层模块里
因为 arith.addi 属于 arith dialect,而顶层模块默认只允许 builtin 和部分基础 dialect;arith op 必须出现在允许它的 region 内,比如 func.func 或 affine.for 的 body 中。
常见误写:
module {
%0 = arith.addi %1, %2 : i32 // ❌ 报错:'arith.addi' op is not allowed in this region
}
- 错误信息通常是
op is not allowed in this region或region does not allow ops from 'arith' dialect - 解决方式只有两种:包进
func.func,或改用builtindialect 的unrealized_conversion_cast(不推荐,纯绕路) - MLIR 的“模块即容器”模型意味着:没函数/没控制流结构,就没地方放计算 op
真正容易被忽略的是:MLIR 的合法性检查发生在解析后、优化前,且每一步 lowering 都依赖前一步的输出满足新 dialect 的规则——不是语法对就能过,是每一层 IR 都要自洽。











