Files
2026-08-20 17:20:09 +08:00

93 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段 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 的那些)。