Published on

IREE 编译命令逐项拆解

Authors
  • avatar
    Name
    alan
    Twitter

本文档对以下完整编译命令中的每个参数进行逐一拆解,说明其作用、效果和生成的文件。

iree-compile simpy_conv.mlir \
  --iree-hal-target-device=local \
  --iree-hal-local-target-device-backends=llvm-cpu \
  --iree-llvmcpu-target-cpu=host \
  --iree-hal-dump-executable-files-to=cds_test/simpy_conv/dump_executeable \
  --iree-hal-dump-executable-intermediates-to=cds_test/simpy_conv/intermediates \
  --iree-hal-dump-executable-sources-to=cds_test/simpy_conv/exe-sources \
  --iree-hal-dump-executable-binaries-to=cds_test/simpy_conv/exe-binaries \
  --dump-compilation-phases-to=cds_test/simpy_conv/phases \
  --mlir-print-ir-after-all \
  --mlir-print-ir-tree-dir=cds_test/simpy_conv/print_ir \
  -o simple_conv2d.vmfb

1. 输入与输出

simpy_conv.mlir(输入)

作用:指定要编译的 MLIR 中间表示文件。

内容:从 ONNX 模型转换而来的卷积层 IR,包含:

  • util.func public @mxnet_converted_model_extracted — 主函数
  • 权重常量(卷积 kernel 的 3×64×7×7 float32 数据)
  • linalg.conv_2d_nhwc_fhwi 算子

-o simple_conv2d.vmfb(输出)

作用:指定最终编译产物 — IREE VMFB(Virtual Machine Bytecode)文件路径。

效果:生成可被 iree-run-module 或 Python Runtime 加载执行的字节码。

文件大小:约 52K(本例中)。


2. 目标设备配置

--iree-hal-target-device=local

作用:指定编译目标设备类型为 local(本地 CPU)。

效果:告诉 IREE 编译器生成在本地 CPU 上运行的代码,而非 GPU(CUDA/ROCm/Vulkan)或其他加速器。

可选值:

值目标设备
local本地 CPU(多线程或单线程)
cudaNVIDIA GPU
rocmAMD GPU
vulkan-spirvVulkan GPU
metal-spirvApple GPU

--iree-hal-local-target-device-backends=llvm-cpu

作用:在 local 设备下,指定具体的代码生成后端为 LLVM CPU。

效果:使用 LLVM 将 MLIR lowered 后的 IR 编译为机器码(x86_64 / ARM 等 ELF 格式)。

可选值:

值说明
llvm-cpuLLVM CPU 后端(生成原生机器码)
vmvxVMVX 字节码后端(可移植但性能较低)

--iree-llvmcpu-target-cpu=host

作用:针对当前主机的 CPU 架构进行优化。

效果:编译器会探测当前 CPU 的架构(如 Apple Silicon 的 apple-m1 或 x86 的 skylake),生成利用该 CPU 特有指令集(如 AVX2、NEON)的代码。性能最优,但生成的二进制可能无法在其它 CPU 上运行。

对比:

值说明
host针对当前 CPU 优化,性能最优
generic生成通用代码,可在任何同架构 CPU 运行,性能较差

3. 可执行文件导出(Dump Executable)

以下四个参数将编译过程中产生的 可执行单元(Executable) 的不同阶段产物导出到指定目录。IREE 会将模型中的计算算子(如卷积、矩阵乘法)编译为独立的 "dispatch" 可执行文件。

--iree-hal-dump-executable-files-to=cds_test/simpy_conv/dump_executeable

作用:导出可执行单元的最终文件。

生成的文件:

文件说明
configured_module_mxnet_converted_model_extracted$async_dispatch_0.mlirdispatch 0 的配置后 IR
configured_module_mxnet_converted_model_extracted$async_dispatch_1.mlirdispatch 1 的配置后 IR
module_*_embedded_elf_x86_64_benchmark.mlir嵌入的 ELF 基准测试 IR

用途:查看每个 dispatch 算子最终被编译成的机器码表示。dispatch_0 和 dispatch_1 分别对应模型中的不同计算核(如卷积主循环和 bias 添加)。

--iree-hal-dump-executable-intermediates-to=cds_test/simpy_conv/intermediates

作用:导出 LLVM 编译链路中的中间产物。

生成的文件:

文件说明
*.codegen.llLLVM IR(代码生成阶段,优化前)
*.codegen.bcLLVM Bitcode(代码生成阶段,二进制格式)
*.linked.ll链接后的 LLVM IR
*.linked.bc链接后的 LLVM Bitcode
*.optimized.ll优化后的 LLVM IR(经过 -O2/-O3)
*.optimized.bc优化后的 LLVM Bitcode
*.o目标文件(机器码)
*.s汇编代码(人类可读的机器码)

用途:

  • .s 文件最重要:可以查看生成的具体汇编指令,分析向量化(AVX/NEON)、循环展开等优化效果。
  • .ll 文件:可以查看 LLVM IR 级别的优化。
  • .o 文件:最终链接进 VMFB 的机器码。

--iree-hal-dump-executable-sources-to=cds_test/simpy_conv/exe-sources

作用:导出可执行单元的 输入源 IR(即传给 LLVM 后端之前的 MLIR)。

生成的文件:

文件说明
module_mxnet_converted_model_extracted$async_dispatch_0.mlirdispatch 0 的源 IR
module_mxnet_converted_model_extracted$async_dispatch_1.mlirdispatch 1 的源 IR

用途:查看 IREE 代码生成器(Codegen)准备提交给 LLVM 的 IR 长什么样。这是 HAL Executable dialect 的 IR,包含 hal.executable.variant 等信息。与 intermediates 中的 .ll 文件对比,可以看到 MLIR → LLVM IR 的转换。

--iree-hal-dump-executable-binaries-to=cds_test/simpy_conv/exe-binaries

作用:导出链接后的最终可执行二进制文件。

生成的文件:

文件说明
module_simpy_conv_linked_embedded_elf_x86_64.so嵌入的 ELF 共享对象

用途:这是实际被加载到内存中执行的机器码二进制文件。可以用 nm、objdump、file 等工具分析:

file cds_test/simpy_conv/exe-binaries/*.so
nm cds_test/simpy_conv/exe-binaries/*.so

4. 编译阶段导出

--dump-compilation-phases-to=cds_test/simpy_conv/phases

作用:将整个编译流水线分为 12 个阶段,每个阶段导出一个 IR 快照。

生成的文件(按顺序):

序号文件阶段名称说明
1simpy_conv.1.input.mlirinput原始输入 IR,未经任何处理
2simpy_conv.2.abi.mlirabiABI(应用二进制接口)转换,确定函数签名
3simpy_conv.3.preprocessing.mlirpreprocessing预处理:常量折叠、死代码消除
4simpy_conv.4.global-optimization.mlirglobal-optimization全局优化:算子融合、常量传播
5simpy_conv.5.dispatch-creation.mlirdispatch-creation创建 dispatch:将算子分组为可并行执行的单元
6simpy_conv.6.flow.mlirflowFlow dialect:建模计算、分配和流
7simpy_conv.7.stream.mlirstreamStream dialect:设备放置、异步调度
8simpy_conv.8.executable-sources.mlirexecutable-sources可执行源:准备编译为机器码的 dispatch
9simpy_conv.9.executable-configurations.mlirexecutable-configurations可执行配置:设置每个 dispatch 的编译参数
10simpy_conv.10.executable-targets.mlirexecutable-targets可执行目标:指定目标后端
11simpy_conv.11.hal.mlirhalHAL dialect:硬件抽象层,缓冲区和管理
12simpy_conv.12.vm.mlirvmVM dialect:最终虚拟机字节码前的 IR

用途:

  • 调试编译问题的核心工具。如果编译失败或结果不对,逐个查看这些文件,定位是在哪个阶段出的问题。
  • 对比相邻两个文件(如 5.dispatch-creation.mlir vs 6.flow.mlir),可以理解某个 Pass 做了什么变换。
  • 典型调试流程:从 12.vm.mlir 倒着往前看,找到第一个"看起来不对"的文件,问题就在该阶段。

5. IR 打印

--mlir-print-ir-after-all

作用:在 每一个 MLIR Pass 执行完毕后,将当前完整的 IR 打印到 stderr。

效果:

  • 输出量巨大(本例产生了 277 个文件)。
  • 每个文件以 Pass 编号和名称命名,如 45_iree-flow-collapse-reduction.mlir。
  • stderr 输出时会夹杂大量 // -----// 分隔符。

与 --dump-compilation-phases-to 的区别:

参数粒度文件数用途
--dump-compilation-phases-to粗(12 个大阶段)12定位大阶段问题
--mlir-print-ir-after-all细(每个 Pass)277+精确定位具体 Pass 问题

--mlir-print-ir-tree-dir=cds_test/simpy_conv/print_ir

作用:将 --mlir-print-ir-after-all 的输出写入指定目录,而不是打印到 stderr。

生成的文件:

  • 目录结构:print_ir/builtin_module_no-symbol-name/<序号>_<pass名称>.mlir
  • 本例共 277 个文件,从 1_torch-reify-shape-calculations.mlir 到 277(最后的 VM 模块)。
  • 末尾还有一些子目录,如 hal_executable_*、util_func_*、vm_module_* 等,对应不同 IR 组件的变换过程。

典型文件序列示例:

1   torch-reify-shape-calculations    # Torch Shape 推导
10  iree-auto-input-conversion        # 自动输入转换
11  iree-import-public                # 导入 public 符号
14  iree-import-ml-prog               # 导入 ml_program dialect
50+ iree-flow-*                       # Flow dialect 变换
100+ iree-stream-*                    # Stream dialect 变换
120+ iree-util-*                      # Util 变换
200+ hal-*                            # HAL lowering
250+ vm-*                             # VM bytecode 生成

用途:

  • 精确定位哪个 Pass 引入了问题。
  • 学习 IREE 编译管线:从头到尾阅读这些文件可以理解 ONNX 模型如何一步步变成 VM 字节码。
  • 搜索特定关键字(如 linalg.conv)追踪卷积算子在各阶段的表示。

6. 整体编译流程图

simpy_conv.mlir (ONNX 转换来的 MLIR)
    │
    ▼
┌─────────────────────────────────────────┐
│ Phase 1-4: 输入 → 预处理 → 全局优化      │ ← phases/*.1-4.mlir
│ (常量折叠、算子融合、ABI 转换)            │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│ Phase 5-7: Dispatch → Flow → Stream     │ ← phases/*.5-7.mlir
│ (算子分组、设备放置、异步调度)             │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│ Phase 8-10: Executable 准备              │ ← phases/*.8-10.mlir
│ (源导出、配置、目标设定)                   │ ← exe-sources/*.mlir
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│ Phase 11-12: HAL → VM                   │ ← phases/*.11-12.mlir
│ (硬件抽象、虚拟机表示)                     │
└─────────────────────────────────────────┘
    │
    ├─── 每个 dispatch ────────────────────┐
    │                                       ▼
    │   ┌──────────────────────────────┐   │
    │   │ MLIR → LLVM IR → 机器码       │   │ ← intermediates/*.ll, *.bc, *.s, *.o
    │   └──────────────────────────────┘   │
    │                                       │
    │   ┌──────────────────────────────┐   │
    │   │ 链接为 ELF 共享对象            │   │ ← exe-binaries/*.so
    │   └──────────────────────────────┘   │
    │                                       │
    │   ┌──────────────────────────────┐   │
    │   │ 最终可执行文件导出              │   │ ← dump_executeable/*.mlir
    │   └──────────────────────────────┘   │
    └───────────────────────────────────────┘
    │
    ▼
simple_conv2d.vmfb (IREE VM 字节码)

7. 常用组合建议

目的推荐参数组合
快速编译仅需 -o + 三个 target 参数
定位编译问题加 --dump-compilation-phases-to=
精确定位 Pass 问题加 --mlir-print-ir-after-all + --mlir-print-ir-tree-dir=
分析生成的机器码加 --iree-hal-dump-executable-intermediates-to=(看 .s 文件)
分析 dispatch 划分加 --iree-hal-dump-executable-sources-to=
全面调试全部加上(如本命令)