方言转换失败是类型、操作、目标三者契约断裂所致,主因包括ConversionTarget配置不匹配、Pattern未覆盖所有非法操作变体、TypeConverter未对齐operand与result生命周期等。

方言转换失败不是“没配对”或“少写一行”这种单一原因,而是类型、操作、目标三者之间契约断裂的结果。最常见的情况是:你告诉 MLIR “这些 op 不合法”,却没提供能把它们变成合法 op 的完整路径。
ConversionTarget 配置不匹配实际 IR 结构
转换目标(ConversionTarget)必须精确反映你当前 IR 中哪些操作是“非法”的、哪些是允许保留的。比如你在处理 toy dialect 时只标记了 toy.func 为合法,但 IR 里还混着未处理的 toy.print,而你又没把它加入非法列表或提供对应 lowering 模式,转换就会卡住并报错 failed to legalize operation。
-
target.addIllegalOp<toyprintop>()</toyprintop>必须显式声明,不能靠“默认非法”假设 -
target.addLegalDialect<llvmdialect>()</llvmdialect>不等于自动接受所有 LLVM op;如果 IR 中存在affine.for却没注册affine到LLVM的 pattern,它仍会被视为非法 - 模块级操作如
ModuleOp通常需显式设为合法,否则整个顶层容器无法通过验证
Pattern 未覆盖所有非法操作的变体
一个 ToyAddOp 可能有不同 operand 类型(tensor vs memref)、不同属性(fastmath 标志)、甚至嵌套在 affine.if 里——而你写的 AddOpLowering 只处理了最简情况。MLIR 的 pattern 匹配是精确的,不自动降维或推导。
- 用
mlir::RewritePatternSet::add注册 pattern 时,若漏掉某类 shape 或 layout 的memref,对应 IR 就会 fallback 到未匹配状态 - 多个 pattern 冲突时(例如两个 pattern 都匹配
toy.transpose但重写逻辑互斥),MLIR 默认选 benefit 值高的,但不会报错提示冲突,只会静默跳过低分 pattern - pattern 中调用
rewriter.replaceOpWithNewOp时,新 op 的类型若不在 type converter 映射范围内,也会触发 legalization 失败
TypeConverter 没对齐 operand 和 result 的生命周期
类型转换器(TypeConverter)不只是做“tensor<f32></f32> → memref<f32></f32>”这种一对一映射。它要确保:block 参数类型、op operand 类型、op result 类型、region 边界处的类型,在 lowering 后全部可被目标 dialect 消化。
- 如果你用默认
LLVMTypeConverter,但它不支持你自定义的toy::TensorType,就必须重载convertType并返回std::nullopt或具体目标类型 - 当 op 有多个 result,且部分 result 被后续 op 用作 operand 时,type converter 必须保证前后类型链一致;否则会出现
operand #0 not compatible with expected type -
convertSignatureArg和convertSignatureResult若未重写,函数签名 lowering 会直接失败,哪怕 body 里的 op 全都合法
真正棘手的是:错误信息往往只说“legalization failed”,却不指明是哪个 op、在哪一层 block、因哪条 pattern 或 type 规则失败。建议在调试时打开 -debug-only=dialect-conversion,并检查 pattern 中是否遗漏了对 Region 或 successor 的类型适配——这些地方最容易被忽略,也最难从日志里定位。

















