MLIR 的强大之处在于它的多层方言栈。通过不同层级的方言,MLIR 可以从高级的算法描述一直转换到最底层的机器码。
按照从"高级/抽象"到"低级/具体"的顺序,以下是 MLIR 中最常用的方言:
1. 高层方言 (High-Level / Domain Specific)
这类方言通常靠近算法逻辑,比如深度学习。
-
TOSA(Tensor Operator Set Architecture): -
用途:提供了一套标准化的张量算子(如卷积、池化、激活)。
-
地位:它是很多模型转换器的入口(如 TensorFlow/PyTorch 导入 MLIR 后通常先转为 TOSA)。
-
Linalg(Linear Algebra): -
用途:处理结构化控制流和线性代数。
-
核心:它既可以表示张量计算,也可以表示内存计算。它能自动生成嵌套循环,是生成高性能代码的关键层。
2. 中层/通用方言 (Mid-Level / Infrastructure)
这类方言是 MLIR 的"粘合剂",几乎在所有程序中都会用到。
-
Arith(Arithmetic): -
用途:基础算术运算。处理整数和浮点数的加减乘除、位运算、常量定义。
-
Func(Function): -
用途:处理函数定义、调用、返回。是构建程序结构的基础。
-
ControlFlow(CF): -
用途 :处理分支跳转(
br)、条件判断(cond_br)等原始控制流。 -
SCF(Structured Control Flow): -
用途 :提供高级的结构化循环(
scf.for、scf.if、scf.while)。比起 CF 更加易于分析和优化。
3. 数据与内存方言 (Data Management)
决定了数据在硬件中是如何存放和访问的。
-
Tensor: -
特点:不可变(Immutable)的数据抽象。主要用于高层图优化,不涉及具体内存地址。
-
MemRef(Memory Reference): -
特点:可变(Mutable)的内存引用。它描述了数据在内存里的布局(形状、步长、偏移)。
-
转换 :通常由
Tensor方言通过Bufferization(缓冲化)转换而来。 -
Index: -
用途:专门用于表示数组下标、循环索引的类型,屏蔽了不同硬件上 32 位或 64 位整数的区别。
4. 底层/硬件方言 (Low-Level / Target Specific)
这类方言已经非常接近汇编语言。
-
LLVM: -
用途:MLIR 的"最后一公里"。它几乎与 LLVM IR 对应,用于最后交给 LLVM 后端生成机器码。
-
Vector: -
用途:处理 SIMD(单指令多数据)指令。它是高性能计算的核心,负责把普通计算映射到 CPU 的专用向量寄存器(如 AVX512)。
-
GPU: -
用途 :抽象了 GPU 的并行逻辑(如 Kernel 发射、线程块、共享内存)。它可以进一步转换为
NVVM(NVIDIA) 或ROCDL(AMD)。
总结:一个典型的编译路线图
当你编译一个模型时,数据通常是这样"降级"(Lowering)的:
- 输入:PyTorch 模型
- TOSA/Linalg:描述"我要做一个卷积"。
- SCF / Affine :把卷积拆解成"几层
for循环"。 - Vector / MemRef:把循环里的计算变成"向量加法",并分配物理内存。
- LLVM:变成 LLVM IR。
- 输出:二进制可执行文件。