MLIR中不能单独写arith.addi,因为它是结构化IR而非汇编:单个operation必须嵌套在func.func等容器内,否则报错“expected operation in function body”,且所有操作数和结果必须显式标注类型(如i32)。

直接用 arith.addi、arith.muli 等操作即可,但必须配合 func.func 定义函数边界,且所有值需显式标注类型(如 i32)。
为什么不能单独写 arith.addi?
MLIR 不是汇编,而是结构化 IR:单个 operation 无法独立存在。它必须嵌套在 func.func 或 linalg.generic 等容器中,否则解析会报错 error: expected operation in function body。arithmetic 操作本身不带控制流语义,也不管理内存或作用域 —— 这些由外围 dialect 承担。
常见错误现象:
- 只写
%0 = arith.addi %a, %b : i32,没包在func.func里 → 报错expected top-level operation - 漏写类型标注,比如写成
arith.addi %a, %b→ 报错missing type for operand - 混用浮点和整数操作,如用
arith.addf对i32操作 → 类型校验失败
arith 支持哪些整数运算?
核心整数 operation 都以 i 结尾(i 表示 integer),全部要求操作数与结果类型一致:
-
arith.addi:带符号整数加法(i32,i64,index均可) -
arith.muli:乘法;arith.subi:减法;arith.divsi(有符号除)、arith.divui(无符号除) -
arith.remsi/arith.remui:余数;arith.cmpi:比较(返回i1),需指定谓词如"slt"(有符号小于) -
arith.constant:必须用dense<...>或字面量,例如arith.constant 42 : i32
注意:arith 不提供位运算(如 shl、and)—— 那些属于 arith.bitwise 子集,需显式启用或查 dialect 文档。
典型合法写法长什么样?
下面是最小可运行的整数加法 MLIR 片段:
func.func @add_i32(%arg0: i32, %arg1: i32) -> i32 {
%0 = arith.addi %arg0, %arg1 : i32
func.return %0 : i32
}
关键点:
- 函数名用
@add_i32,参数和返回值类型都明确为i32 -
%0是 SSA 名,只赋值一次;后续若要再用,只能读取%0,不能重定义 - 所有
arith操作必须跟冒号 + 类型,哪怕看起来“显然”——MLIR 不推导类型
如果想做常量折叠测试,可以写 %c = arith.constant 17 : i32,但注意 arith.constant 不接受十进制浮点字面量(如 3.14),那得走 arith.constant + arith.sitofp 组合。
容易被忽略的兼容性细节
不同 MLIR 版本对 arith 的支持略有差异:
-
arith.divsi在较老版本(如 LLVM 15 之前)可能叫arith.sdivi,现在已统一 -
arith.cmpi的谓词字符串(如"eq","ne","slt")大小写敏感,且不可省略引号 - 如果你用
index类型(常用于 loop bounds),arith.addi和arith.muli都支持,但arith.divsi不接受index—— 必须先转成i64
最稳妥的做法:用 mlir-opt --verify-each 跑一遍,它会在 lowering 前就捕获类型/签名不匹配问题。

















