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

93 lines
4.2 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.
# 阶段 6:Codegen(可执行体 lowering)✅
> 2026-08-15。对应规划阶段 6。源码:`src/iree/compiler/src/iree/compiler/Codegen/`。
> **这是你之前接触过的部分,重点是建立「MLIR pass ↔ TVM schedule」的映射。**
## 1. Codegen 的职责
把 HAL 层交给它的 `flow.executable`(内含 linalg 计算)lowering 成设备代码(LLVM IR / SPIR-V)。
由 HAL 的 TargetBackend 触发(见 [07-hal.md](07-hal.md) 第 3 节)。
按后端组织:
- `LLVMCPU/` —— CPU(x86/ARM)
- `LLVMGPU/` —— GPU(CUDA via NVVM、ROCm via ROCDL)
- `SPIRV/` —— Vulkan
- `VMVX/` —— 简单可移植参考后端
- `WGSL/` —— WebGPU
- `Common/` —— 跨后端共享逻辑
## 2. 关键 lowering 链(LLVMCPU,来自阶段 2 pass 序列)
```
LLVMCPUSelectLoweringStrategy # 选 tiling/向量化策略(对应 TVM 选 schedule)
→ TileAndDistributeToWorkgroups # workgroup 级 tiling
→ LLVMCPUTileAndFuseProducerConsumer # tile-and-fuse(对应 TVM 的 compute_at + fuse)
→ LLVMCPUTile # tiling
→ LLVMCPUPeel # loop peeling
→ LLVMCPUTileToVectorSize # tile 到向量大小
→ GenericVectorization # 向量化(对应 TVM 的 vectorize)
→ IREEComprehensiveBufferize # bufferize:tensor → memref(对应 TVM storage lowering)
→ LLVMCPUVirtualVectorLowering # 向量 lowering
→ ConvertToLLVM # 转 LLVM IR
```
## 3. MLIR pass ↔ TVM schedule 对照(你的主场)
| TVM 0.6 schedule 原语 | IREE codegen 的 MLIR pass |
|---|---|
| `split`(循环拆分) | `LLVMCPUTile` + `LLVMCPUTileToVectorSize` |
| `reorder`(循环重排) | tiling pass 里隐含 |
| `fuse` + `compute_at` | `LLVMCPUTileAndFuseProducerConsumer` |
| `vectorize` | `GenericVectorization` |
| `unroll` | `LLVMCPUPeel` + 向量 lowering |
| buffer 分配 / storage | `IREEComprehensiveBufferize`(tensor→memref) |
| codegen(LLVM/CUDA) | `ConvertToLLVM` / `ConvertToNVVM` / `ConvertToROCDL` |
**核心差异**:TVM 的 schedule 是**用户手写/自动搜索**的显式变换序列;IREE 的 codegen 是
**声明式 pass pipeline**,策略由 `LLVMCPUSelectLoweringStrategy` 基于 op 类型/shape 自动选择。
(IREE 也有 `transform` dialect 支持手写 schedule,但那是在 linalg 之上。)
## 4. Dispatch ABI(运行时↔可执行体的接口,关键)
codegen 出来的 LLVM 函数(阶段 2 dump 见过)签名是:
```mlir
llvm.func @matmul_dispatch_0_matmul_2x2x4_f32(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm.ptr) -> i32
```
- 参数不是直接传 buffer,而是通过 `iree_hal_executable_dispatch_state_v0_t` 结构体(`DispatchABI.cpp` 定义)
取 bindings —— 这是运行时和编译出的 kernel 之间的固定 ABI
- 对应 TVM 里 kernel 的参数打包(`TVMArgs` / 显式参数)
## 5. 关键文件
| 文件 | 作用 |
|---|---|
| `LLVMCPU/LLVMCPUSelectLoweringStrategy.cpp` | 选策略(tiling 尺寸、向量化方案)——核心 |
| `LLVMCPU/LLVMCPUTileAndFuseProducerConsumer.cpp` | tile-and-fuse |
| `LLVMCPU/LLVMCPUTile.cpp` / `LLVMCPUPeel.cpp` | tiling / peeling |
| `LLVMCPU/LLVMCPUTileToVectorSize.cpp` | tile 到向量 |
| `LLVMCPU/LLVMCPUVirtualVectorLowering.cpp` | 向量 lowering |
| `LLVMCPU/DispatchABI.cpp` | dispatch ABI |
| `LLVMCPU/ConvertToLLVM.cpp` / `LLVMCPULowerExecutableTarget.cpp` | 转 LLVM |
| `LLVMGPU/ConvertToNVVM.cpp` / `ConvertToROCDL.cpp` | GPU 后端 |
| `LLVMGPU/KernelConfig.cpp` | GPU kernel 配置 |
## 6. 源码阅读路径
```
src/iree/compiler/src/iree/compiler/Codegen/
├── Common/ # 跨后端共享
├── Interfaces/ # 接口
├── LLVMCPU/ # CPU 后端
│ ├── LLVMCPUSelectLoweringStrategy.cpp # 先读这个(策略选择)
│ ├── LLVMCPUTileAndFuseProducerConsumer.cpp
│ └── DispatchABI.cpp
├── LLVMGPU/ # GPU 后端(NVVM/ROCDL)
├── SPIRV/ # Vulkan
└── Transforms/ # 通用变换
```
> 学习建议:你有 codegen 经验,重点看 `LLVMCPUSelectLoweringStrategy.cpp` 理解「策略怎么选」,
> 以及 `DispatchABI.cpp` 理解「kernel 和运行时怎么对接」。GPU 后端看 `LLVMGPU/KernelConfig.cpp`。