93 lines
5.0 KiB
Markdown
93 lines
5.0 KiB
Markdown
# 阶段 5:HAL(设备抽象)✅
|
||
|
||
> 2026-08-15。对应规划阶段 5。源码:`src/iree/compiler/src/iree/compiler/Dialect/HAL/`。
|
||
> HAL 既是「设备抽象层」,也是「codegen 的入口」(通过 TargetBackend)。
|
||
|
||
## 1. HAL 的职责
|
||
|
||
HAL(Hardware Abstraction Layer)把「设备」抽象成统一的概念,屏蔽 CPU/CUDA/Vulkan 等差异,
|
||
并把 Stream 层已经调度好的 `stream.cmd.*` 命令转成 `hal.*` 设备操作。
|
||
|
||
核心抽象有五个:**device、buffer/buffer_view、allocator、command_buffer、executable**(外加 channel 通信)。
|
||
|
||
## 2. 核心 op(`IR/HALOps.td`)
|
||
|
||
| 类别 | 关键 op | 作用 |
|
||
|---|---|---|
|
||
| **Device** | `hal.device.query`、`hal.device.allocator`、`hal.devices.get/count`、`hal.device.resolve` | 查询设备属性、获取设备 |
|
||
| **Buffer** | `hal.buffer.subspan/load/store/length`、`hal.buffer.assert` | 设备内存 buffer |
|
||
| **BufferView** | `hal.buffer_view.create`、`hal.buffer_view.buffer`、`hal.buffer_view.assert` | 带 shape/type 的 buffer 视图 |
|
||
| **Allocator** | `hal.allocator.allocate/import/select` | 内存分配 |
|
||
| **CommandBuffer** | `hal.command_buffer.create/dispatch/copy_buffer/fill_buffer/execution_barrier/finalize` | **记录命令**(核心) |
|
||
| **DeviceQueue** | `hal.device.queue.execute/execute.indirect/copy/fill/flush` | 提交命令队列 |
|
||
| **Executable** | `hal.executable`、`hal.executable.variant`、`hal.executable.export`、`hal.executable.binary` | 设备可执行代码 |
|
||
| **Channel** | `hal.channel.create/rank_and_count/split` | 多设备通信 |
|
||
|
||
## 3. Target Backend —— codegen 的入口(关键)
|
||
|
||
`HAL/Target/` 定义了 **TargetBackend** 抽象(`TargetBackend.cpp/h` + `TargetRegistry.cpp`):
|
||
- 每个后端(LLVM-CPU、LLVM-GPU/CUDA、SPIR-V/Vulkan 等)实现一个 TargetBackend
|
||
- 编译时按 `--iree-hal-target-backends=llvm-cpu` 选择后端
|
||
- **可执行体的 codegen 就发生在这里**:`ConfigureExecutables` → `TranslateExecutables`
|
||
会调用对应 TargetBackend,把 `flow.executable` 里的 linalg 编译成设备代码
|
||
|
||
> 这就是阶段 5(HAL)和阶段 6(codegen)的连接点:HAL 的 TargetBackend 是 codegen 的调度者。
|
||
|
||
## 4. 关键 pass(`Transforms/` + `Conversion/`)
|
||
|
||
| pass | 文件 | 作用 |
|
||
|---|---|---|
|
||
| `ConvertToHALPass` | ConvertToHAL.cpp | **Stream → HAL**(主入口) |
|
||
| `AssignTargetDevicesPass` / `MaterializeTargetDevicesPass` | 同名 | 目标设备分配 |
|
||
| `ResolveDevicePromisesPass` / `ResolveDeviceAliasesPass` | 同名 | 设备解析 |
|
||
| `ConfigureExecutablesPass` | ConfigureExecutables.cpp | 配置可执行体(选后端、变体) |
|
||
| `TranslateExecutablesPass` | TranslateExecutables.cpp | **调用后端做 codegen** |
|
||
| `LinkExecutablesPass` / `SerializeExecutablesPass` | 同名 | 链接 / 序列化可执行体 |
|
||
| `PruneExecutablesPass` / `HoistExecutableObjectsPass` | 同名 | 裁剪 / 提升可执行体对象 |
|
||
| `ElideRedundantCommandsPass` | ElideRedundantCommands.cpp | 消除冗余命令 |
|
||
|
||
**Conversion/**:
|
||
- `StreamToHAL/` —— Stream → HAL 转换
|
||
- `HALToVM/` —— HAL → VM 转换(阶段 7 的入口)
|
||
- `TypeConverter.cpp` —— 类型转换
|
||
|
||
## 5. IR 变换(阶段 2 已见,精简)
|
||
|
||
```mlir
|
||
// ConvertToHALPass 之后:stream.executable → hal.executable.variant
|
||
hal.executable private @matmul_dispatch_0 {
|
||
hal.executable.variant public @embedded_elf_x86_64 target(#executable_target_embedded_elf_x86_64) {
|
||
hal.executable.export public @matmul_dispatch_0_matmul_2x2x4_f32 ordinal(0) layout(#pipeline_layout)
|
||
attributes {workgroup_size = [1 : index, 1 : index, 1 : index]}
|
||
builtin.module { llvm.func @matmul_dispatch_0_matmul_2x2x4_f32(...) { ... } } // 已 codegen 成 LLVM
|
||
}
|
||
}
|
||
// #pipeline_layout 定义缓冲区绑定(2 ReadOnly + 1 输出 storage_buffer)
|
||
```
|
||
|
||
## 6. 与 TVM 0.6 对照
|
||
|
||
| HAL 概念 | TVM 0.6 | 说明 |
|
||
|---|---|---|
|
||
| hal.device / allocator | DeviceAPI(CPU/GPU) | 设备抽象 |
|
||
| hal.buffer / buffer_view | DLTensor / NDArray | 内存 + 元数据 |
|
||
| hal.command_buffer | 无显式对应(TVM 直接生成 kernel 调用) | IREE 显式建模命令录制 |
|
||
| hal.executable | 编译出的 kernel(.so / .ptx) | 设备代码 |
|
||
| TargetBackend | codegen 的 build_module 分派 | 后端注册 |
|
||
|
||
## 7. 源码阅读路径
|
||
|
||
```
|
||
src/iree/compiler/src/iree/compiler/Dialect/HAL/
|
||
├── IR/HALOps.td # op 定义(先读,认识五类抽象)
|
||
├── Target/TargetBackend.h # 后端抽象(codegen 入口)
|
||
├── Target/TargetRegistry.cpp # 后端注册表
|
||
├── Target/Devices/ # 具体设备
|
||
├── Transforms/ConvertToHAL.cpp # Stream → HAL
|
||
├── Transforms/TranslateExecutables.cpp # 调用后端 codegen
|
||
└── Conversion/StreamToHAL/ # 转换细节
|
||
```
|
||
|
||
> 学习建议:读 `TargetBackend.h` 理解「后端如何抽象」,这是 HAL 和 codegen 的接口。
|
||
> `hal.imports.mlir` 列出了 HAL 模块对外暴露的所有函数(就是 VM 层 import 的那些)。
|