# 阶段 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 的那些)。