# 阶段 7:运行时(VM + iree-runtime)✅ > 2026-08-15。对应规划阶段 7。分两部分: > **编译侧** `src/iree/compiler/src/iree/compiler/Dialect/VM/`(生成字节码) > **运行时** `src/iree/runtime/src/iree/`(C 实现)。 ## 1. 整体图景 编译的最后一步是把 HAL 模块序列化成 **VM 字节码**(`.vmfb`),运行时加载并解释执行: ``` HAL 模块 → VM 转换(HALToVM)→ vm.module(字节码 IR)→ 序列化 → .vmfb 文件 ↓ iree-runtime 加载 → VM 解释器 → 调 hal.* import → HAL driver 执行 ``` ## 2. VM = 紧凑字节码虚拟机(编译侧) VM dialect 定义了一套**字节码级的 IR**,核心 op(`IR/VMOps.td`): | op | 作用 | |---|---| | `vm.module` | 顶层字节码模块 | | `vm.func` | VM 函数 | | `vm.import` / `vm.export` | 导入外部函数(如 `hal.command_buffer.dispatch`)/ 导出 | | `vm.call` / `vm.call.variadic` / `vm.call.yieldable` | 调用(含可让出调用,协作式调度) | | `vm.branch` / `vm.cond_branch` / `vm.branch_table` | 字节码级控制流 | | `vm.global.load/store.ref` | 全局引用变量 | | `vm.const.ref.rodata/zero` | 常量 | | `vm.list.*` / `vm.buffer.*` | 列表 / buffer 操作 | | `vm.discard.refs` | **引用计数回收**(显式 GC) | ### 字节码格式 用 **FlatBuffers** 定义(`runtime/src/iree/schemas/bytecode_module_def.fbs`), 是紧凑、可直接 mmap 加载的二进制格式。阶段 2 用 `iree-dump-module` 看到的就是反汇编: ``` Required Types: i32, i64, !hal.allocator, !hal.buffer, !hal.buffer_view, !hal.command_buffer, !hal.device, !hal.executable, !hal.fence, !vm.buffer Module Dependencies: hal, version >= 6 Imported Functions: [ 7] hal.command_buffer.dispatch(...) -> () [11] hal.device.queue.execute.indirect(...) -> () [16] hal.fence.await(i32, i64, tuple>...) -> (i32) ``` ## 3. iree-runtime(C 运行时) `runtime/src/iree/` 目录: | 目录 | 作用 | |---|---| | `vm/` + `vm/bytecode/` | **VM 解释器**(字节码解码 + 分发执行) | | `hal/` + `hal/drivers/` | HAL 运行时 + 各设备驱动 | | `task/` | 多线程任务调度系统(local-task driver 的基础) | | `base/` | 基础工具(status、allocator、logging) | | `builtins/` / `modules/` | VM 内置函数 / 内置模块(如 hal 模块) | | `schemas/` | FlatBuffers schema(字节码 + 各后端可执行体格式) | | `runtime/` | 顶层 API(`iree_runtime_instance` 等) | | `io/` | 参数/文件 IO | ### HAL drivers(真正的设备后端) `hal/drivers/` 下每个目录是一个设备实现: | driver | 设备 | |---|---| | `local_task` | **CPU 多线程**(基于 task 系统)—— 默认 | | `local_sync` | CPU 同步(调试用) | | `cuda` / `hip` / `amdgpu` | NVIDIA / AMD GPU | | `vulkan` | Vulkan | | `metal` | Apple Metal | | `webgpu` | WebGPU | | `null` | 空设备(测试) | > 当前环境只装了 base 包,运行时只有 local-task/local-sync。CUDA driver 需要额外构建。 ## 4. 与 TVM 0.6 对照 | IREE | TVM 0.6 | |---|---| | VM 字节码(.vmfb) | graph runtime / relay VM 的序列化 | | vm.import(hal.*) | 生成的 kernel 调用 | | HAL driver(local-task/cuda/vulkan) | DeviceAPI(CPU/CUDA/OpenCL/Metal) | | task 系统 | CPU 线程池 runtime | | 引用计数 GC | 无(TVM 用 DLTensor 引用计数) | **核心差异**:IREE 的 VM 是**完整字节码虚拟机**(带控制流、全局变量、yieldable 调用), 而 TVM 的 graph runtime 只是「按拓扑顺序执行节点」。IREE 的 VM 更接近一个真正的 VM。 ## 5. 源码阅读路径 ``` # 编译侧(字节码生成) src/iree/compiler/src/iree/compiler/Dialect/VM/ ├── IR/VMOps.td # VM op 定义 ├── Conversion/HALToVM/ # HAL → VM 转换 └── Target/ # 序列化到字节码 # 运行时(C) src/iree/runtime/src/iree/ ├── vm/ # VM 解释器 ├── hal/drivers/local_task/ # CPU 多线程 driver(默认) ├── hal/drivers/cuda/ # CUDA driver ├── task/ # 任务调度 └── schemas/bytecode_module_def.fbs # 字节码格式 ``` ## 6. 全流程回顾(7 个阶段串起来) ``` 输入(StableHLO/TOSA) → [前端] → linalg → [Flow] dispatch 划分 → [Stream] 异步调度 → [HAL] 设备抽象 + 触发 codegen → [Codegen] linalg→LLVM/SPIR-V → [VM] 字节码 → [runtime] 执行 ``` 你现在已经把 IREE 从输入到运行时**完整走了一遍**。每个阶段都有对应笔记和源码路径。 ## 下一步(阶段 8 实践,可选) - 写一个自定义 pass(如自定义 fusion 规则),需要源码构建 - 配 CUDA 后端,看 GPU 的 codegen(LLVMGPU → NVVM) - 深入某一层读源码(建议 Stream 或 Codegen)