MLIR 架构解析:AI 编译器的统一中间表示
摘要: Triton 编译出的是"内核代码",XLA 编译出的是"整图执行计划",而它们底层的共同地基是 MLIR——LLVM 社区为"多级中间表示"设计的编译器基础设施。本文讲清 MLIR 的核心抽象(Dialect/Operation/SSA)、降级(lowering)流水线,以及为什么 AI 编译器都选择"站在 MLIR 上"。
0. 实验目标
- 理解 MLIR 三大核心抽象:Dialect(方言)、Operation(操作)、SSA 值
- 看懂 IR 降级流水线:高层方言 → 中层方言 → LLVM IR
- 弄清 MLIR 与 Triton、XLA 的关系(谁站在谁上面)
- 会读
mlir-opt的 IR 输出(调编译器时的基本技能)
1. 为什么需要 MLIR:一层 IR 不够用
原理讲解:
- LLVM IR 是"接近机器"的表示:适合做寄存器分配、指令选择,但表达不了"这是矩阵乘"或"这是个卷积"——AI 算子在 LLVM IR 里被拆成无数标量指令,高层优化信息全丢了。
- MLIR 的核心思想:不是"一个 IR",而是一套 IR 框架——允许你定义自己的方言(Dialect),每种方言有自己的操作集,方言之间逐级降级。
- 好处:优化可以在最合适的层级做——图融合在高方言层(tosa/linalg),向量化在中层,代码生成在低层(LLVM)。
text
AI 模型(高层语义)
│ 方言:tosa / linalg(张量语义,可做算子融合/形状推断)
▼
中间方言(向量化、tiling)
│ 方言:arith / vector / scf
▼
LLVM IR(接近机器)
│
▼
机器码2. 核心抽象:Dialect / Operation / SSA
mlir
// 一段 MLIR IR 样例(tosa 方言 + arith 方言混合)
// %0、%1 是 SSA 值(不可变,数据流显式)
func.func @add_relu(%arg0: tensor<4x4xf32>, %arg1: tensor<4x4xf32>) -> tensor<4x4xf32> {
%0 = tosa.add %arg0, %arg1 : tensor<4x4xf32> // 张量加法(高层语义)
%1 = tosa.relu %0 : tensor<4x4xf32> // ReLU
return %1 : tensor<4x4xf32>
}逐段拆解:
- Dialect(方言):一组操作的集合,
tosa(张量算子)、arith(标量算术)、scf(结构化控制流)、vector(向量化)、linalg(线性代数)——每个方言是一个"语义层"。 - Operation(操作):IR 的基本单元,形如
方言名.操作名 操作数 : 类型。操作可以嵌套(区域/block)。 - SSA 值:每个值只赋值一次、不可变——数据流图天然显式,分析(活跃变量、依赖)和转换(重写)都简单。
3. 降级流水线:高层怎么变成机器码
bash
# 用 mlir-opt 跑一条降级流水线(示例:tosa → linalg → LLVM)
mlir-opt --tosa-to-linalg --linalg-bufferize --convert-linalg-to-llvm input.mlir
# 观察每步 IR 变化(调试编译器必备)
mlir-opt --tosa-to-linalg input.mlir # 看 tosa 方言如何变成 linalg原理讲解:
- Pass(变换):MLIR 的优化/降级以 pass 为单位,一个 pass 把某方言的操作重写成另一个方言(或同一方言内的优化)。
- Pipeline(流水线):多个 pass 按序执行:
tosa-to-linalg(语义降级)→linalg-bufferize(张量→缓冲区)→ 向量化 → LLVM。 - 可扩展性:新硬件接入 = 新 dialect + 新 pass,复用整个 LLVM 后端——这是 MLIR 成为 AI 编译器基建的根本原因。
4. MLIR 生态:谁站在它上面
| 编译器/框架 | 与 MLIR 的关系 | 备注 |
|---|---|---|
| XLA(TPU/GPU) | 图 IR(HLO)在 MLIR 框架内表达 | Google 系 |
| Triton | 前端方言翻译到 MLIR(tt dialect) | 本知识库 Triton 篇的底层 |
| torch-mlir | 把 torch FX 图降到 MLIR | PyTorch 编译栈的另一支 |
| IREE | 基于 MLIR 的端侧/通用编译运行时 | 移动端部署 |
工程启示:
- 学 MLIR ≠ 学某个编译器:它是"编译器的基础设施",理解 Dialect/pass 模型后,XLA/Triton/torch-mlir 的架构一眼就能读懂。
- 调
torch.compile或 Triton 遇到看不懂的报错时,打开对应编译器的 MLIR dump(如TORCH_LOGS或 Triton 的 IR 输出),在 IR 层定位问题比猜源码快。 - 接入国产硬件(昇腾/寒武纪)的编译栈普遍基于 MLIR 扩展方言——理解 MLIR 等于理解国产编译器架构(与 国产加速卡适配 篇呼应)。
5. 工程启示汇总
- MLIR 是 IR 框架不是单一 IR:方言分层,优化在最合适的层级做。
- 三大抽象:Dialect(语义层)/ Operation(基本单元)/ SSA(显式数据流)。
- 降级 = pass 流水线:高层方言逐级降到 LLVM IR,每步可观测。
- 生态格局:XLA/Triton/torch-mlir/IREE 都站在 MLIR 上。
- 调试技能:编译报错先看 IR dump,
mlir-opt单步观察。 - 国产编译栈也是 MLIR 系:理解 MLIR 即理解其架构。
- 不用精通,够读懂即可:框架工程师会读 IR、会跑 pass 验证即可。