PartialConversion 适合保留高层语义做渐进式优化,FullConversion 适合最终生成可执行代码;必须用 FullConversion 时包括调用 LLVM JIT、导出原生二进制或启用 createLLVMPassPipeline,此时所有 Op 必须映射到 LLVM Dialect(如 LLVM::LLVMFuncOp),否则 verify 失败或 JIT 拒绝加载。

PartialConversion 适合保留部分高层语义做渐进式优化,FullConversion 适合最终生成可执行代码;选哪个不看“先进”,而看当前阶段是否还需要某类 Op 的高层信息。
什么时候必须用 FullConversion
当你需要调用 LLVMJIT 运行、或导出为原生二进制时,所有 Op 都得落到 LLVM::LLVMFuncOp、LLVM::AllocaOp 这类底层操作上。LLVM Dialect 不支持 toy.print 或 linalg.generic,这些未被转换的 Op 会导致 verify 失败或 JIT 拒绝加载。
-
mlir-cpu-runner只能解释 Standard/Affine/MemRef 等少数方言,不支持自定义方言(如toy) - 一旦启用
createLLVMPassPipeline,pipeline 会默认要求所有 Op 已映射到 LLVM Dialect -
LLVM::LLVMFuncOp是唯一能被ExecutionEngine编译成机器码的函数容器
PartialConversion 的真实使用场景
它不是“半吊子转换”,而是有明确保留意图:比如你正在做 loop tiling 优化,希望把 linalg.generic 先降到 Affine 层,但暂时不碰 memref.alloc——因为你要在 Affine 层分析内存访问模式,而 memref.alloc 在 LLVM 层已退化为裸指针,无法还原 shape 和 layout 信息。
- 常见组合:
linalg → Affine+Affine → Standard,但memref和arith暂不降 - 调试时常用:用
mlir-print-ir-after-all观察某一层 lowering 后的 IR 结构,避免一步到位丢失上下文 - 某些硬件后端(如 GPU Dialect)只接受特定中间层 IR,不接受 LLVM Dialect
容易踩的坑:类型和符号没对齐
PartialConversion 默认跳过未注册 pattern 的 Op,但不会报错;FullConversion 则会在第一个无法匹配的 Op 上直接失败,抛出 failed to legalize operation。这不是 bug,是设计使然——它强迫你显式处理所有剩余 Op。
- 忘记为
toy.print提供ConversionPattern?FullConversion 会卡在那条toy.print指令上 -
getOrInsertPrintf中漏掉/*isVarArg=*/true,导致生成的printf类型与 libc 不兼容,JIT 运行时报symbol lookup error - 混合使用
PartialConversion和FullConversionpass 时,注意ConversionTarget的markUnknownOpDynamicallyLegal设置冲突
最常被忽略的一点:FullConversion 不等于“终点”。它只是降到 LLVM Dialect,之后还要走 LLVMIRTranslation 才生成真正的 LLVM IR;而 PartialConversion 的输出,可能恰恰是你下一步 custom pass 的输入目标——别为了“全”而全,留着 linalg 比硬塞进 LLVM::CallOp 更利于做算子融合。

















