5.0 KiB
5.0 KiB
阶段 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 已见,精简)
// 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 的那些)。