first commit

This commit is contained in:
ylhan
2026-08-20 17:20:09 +08:00
commit 8049b6f58d
14 changed files with 1649 additions and 0 deletions
+123
View File
@@ -0,0 +1,123 @@
# 阶段 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<!vm.ref<?>>...) -> (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)