MLIR 层次化编译规范

MLIR 层次化编译规范

一、核心设计思想

MLIR(Multi-Level Intermediate Representation)的核心方法论是分层渐进式降阶(Progressive Lowering):将复杂的 AI 编译问题拆解为多个抽象层次,每层只关注单一维度的语义表达与优化,通过明确的边界和约束实现可维护、可扩展的编译器架构。

Google IREE(Intermediate Representation Execution Environment)作为 MLIR 生态中最具代表性的 AI 编译器工程落地,完整践行了这一设计哲学。


二、六层层次规范

总体流向

Plain 复制代码
用户模型 → 高层语义层 → 算子语义层 → 调度语义层 → 内存语义层 → 硬件语义层 → 代码生成 → 可执行文件
  ONNX   →  图级 IR   → 张量级 IR  → 调度级 IR  → 内存级 IR  →  硬件级 IR

第 1 层:高层语义层(Top Dialect / 图级)

核心职责:忠实表达前端模型的计算图语义,保留完整的算子拓扑与控制流结构,不涉及底层实现细节。

代表 Dialect:StableHLO / MHLO / TOSA / ONNX

关键 Invariants(不变约束)

  • 所有操作均以 tensor 类型为操作数,无显式内存分配

  • 算子语义与前端框架定义严格对齐,数值等价性可验证

  • 保留完整的计算图结构(节点、边、控制依赖)

  • 形状信息完整可推导(静态或动态 shape)

IREE 对应阶段:InputConversion 管线,负责将各前端输入统一转换为标准高层 IR,执行全局图优化(算子融合、常量折叠、形状推导、转置传播等)。


第 2 层:算子语义层(Linalg / 张量级)

核心职责:将高层算子解构为可组合的计算原语,以张量级别的循环嵌套语义表达计算逻辑,为调度优化提供统一的操作界面。

代表 Dialect:Linalg / LinalgExt / Tensor

关键 Invariants

  • 所有计算以 linalg.generic 或命名算子(linalg.matmullinalg.conv_2d 等)表达,具备明确的迭代域与索引映射

  • 操作数仍为 tensor 类型(Value Semantics),无副作用

  • 循环嵌套结构规范,可进行 tiling、fusion、 interchange 等变换

  • 算子计算语义与硬件无关,纯算法表达

IREE 对应实践:IREE 约 99% 的计算调度基于 Linalg on Tensors 开展,仅少量特殊算子使用 LinalgExt 扩展。这一层是调度优化的核心舞台。


第 3 层:调度语义层(调度级)

核心职责:为计算算子附加并行划分、分块策略、执行顺序等调度信息,完成计算任务到硬件执行单元的映射规划。

代表 Dialect:IREE Flow / Stream / SCF + 调度属性

关键 Invariants

  • 计算被划分为独立的 dispatch region(调度区域),区域间无数据依赖冲突

  • 每个 dispatch 内部的并行度、分块尺寸、向粒度明确

  • 调度决策以属性(attribute)或嵌套结构形式附加,不破坏计算语义

  • 跨 dispatch 的数据流与依赖关系可追踪

IREE 对应实践

  • Flow Dialect:建模执行数据流与分区,创建 dispatch region,进行算子融合与任务划分

  • Stream Dialect:建模执行分区与调度,管理并发执行、资源分配与命令队列编排

  • 调度决策不依赖具体硬件指令集,属于架构无关的宏观调度


第 4 层:内存语义层(Memref / 内存级)

核心职责:完成张量值语义到缓冲区内存语义的转换(Bufferization),显化内存分配、布局、别名与生命周期。

代表 Dialect:MemRef / Bufferization / Affine

关键 Invariants

  • 所有操作数从 tensor 转为 memref,具备明确的内存布局与地址空间

  • 内存分配与释放成对出现,无内存泄漏

  • 缓冲区别名关系清晰,读写依赖可静态分析

  • 内存布局(stride、padding、memory space)明确可查

IREE 对应实践:在 dispatch region 内部执行 One-Shot Bufferization,将 Linalg on tensors 降阶为 Linalg on memrefs,随后展开为循环嵌套(SCF),并进行向量化与内存访问优化。


第 5 层:硬件语义层(硬件级)

核心职责:将通用计算表达映射为目标硬件的指令集模型或执行模型,引入硬件特有操作与约束。

代表 Dialect

  • CPU:LLVM / X86Vector / ArmSME

  • GPU:SPIR-V / NVVM / ROCDL

  • 专用加速器:自定义 Hardware Dialect

  • 抽象层:IREE HAL Dialect

关键 Invariants

  • 操作集合限定在目标硬件支持的范围内

  • 向量宽度、寄存器组织、内存层级与硬件规格匹配

  • 硬件特有约束(如对齐、bank 冲突、指令延迟)可被 verifier 检查

  • 可直接翻译为目标汇编 / 字节码

IREE 对应实践

  • HAL Dialect:硬件抽象层,统一描述可执行文件、命令缓冲区、事件、内存分配等运行时概念

  • 各后端独立降阶路径:LLVM(CPU)、SPIR-V(Vulkan)、NVVM(CUDA)、VMVX(可移植向量解释器)


第 6 层:代码生成层(CodeGen)

核心职责:将硬件语义 IR 翻译为目标可执行代码,经过汇编 / 链接生成最终二进制。

输出产物

  • 源文件:.c / .ll / .spvasm / PTX 汇编

  • 目标文件:.o / .cubin / .spv

  • 可执行文件:ELF / 扁平缓冲区模块(.vmfb)

IREE 对应实践

  • 设备端 kernel:经 LLVM/SPIR-V 等编译为机器码

  • 主机端调度逻辑:编译为 VM 字节码,由 IREE 运行时解释执行

  • 最终打包为 .vmfb(VM FlatBuffer)统一部署格式


三、六大设计原则

1. 每层职责单一

每一层只聚焦一个抽象维度的问题,不跨层承担职责:

  • 高层不关心内存布局,底层不关心算子业务语义

  • 调度层只做任务划分,不修改计算逻辑

  • 内存层只管理缓冲区,不引入新的计算语义

IREE 体现 :Dialect 目录严格按职责划分(InputConversion/Codegen/Dialect/Flow/Dialect/HAL/Dialect/VM/),每个 dialect 仅维护自身语义范畴内的操作与类型。

2. 向下单向流动

信息只能从高层向底层逐层降阶,不允许逆向依赖:

  • 低层可以引用高层的分析结果,但高层 pass 不得依赖低层 dialect

  • 每层转换是单调的:信息只增不减,语义只细化不丢失

  • 避免跨层 "抄近道",保证架构的可演进性

3. 每层有明确的 Invariants 与 Verifier

每一层都定义了该层必须始终成立的约束条件,由 MLIR 的 Operation Verifier 自动检查:

  • 类型约束:操作数 / 结果的类型、形状、秩

  • 结构约束:区域嵌套规则、后继块数量

  • 语义约束:属性取值范围、内存空间合法性

  • Pass 执行前后 invariants 保持成立,可用于回归验证

这一机制使得每层都是 "自验证" 的,错误在最早出现的层级被捕获,而不是传导到下游引发难以调试的问题。

4. 转换 Pass 边界清晰

Pass 是层与层之间的转换单元,遵循以下规范:

  • 命名规范ConvertXToY 模式明确标识源与目标 dialect

  • 输入输出明确:每个 pass 声明输入 dialect 集合与输出 dialect 集合

  • 可组合性:pass 可按 pipeline 编排,支持插入自定义 pass

  • 幂等性与可重入:canonicalization 模式下重复执行不产生副作用

IREE 体现 :编译管线被拆分为 InputConversionPipelineFlowTransformPassPipelineStreamTransformPassPipelineHALTransformPassPipelineVMTransformPassPipeline 等独立阶段,边界清晰,可单独调试与替换。

5. 调试友好

分层架构天然支持调试能力:

  • 每层 IR 均可独立 dump,便于定位问题出在哪一次降阶

  • MLIR 提供 -print-ir-after-all-print-ir-before-all 等调试标志

  • 每层 invariants 出错即停,错误信息精确到操作级别

  • IREE 提供 --mlir-print-ir-after-failure 等工具,失败时自动留存现场 IR

6. 文档化、规范化、模板化、流程化

文档化 :每个 dialect 有官方 Rationale 与操作语义文档,每个 pass 有功能说明与示例

规范化 :命名、目录结构、ODS(Operation Definition Specification)定义统一规范

模板化 :Pass 编写、Dialect 定义、转换模式均有固定模板与脚手架

Agent 化 :结构化的 IR 与 pass 管线便于自动化工具(如搜索调度、自动降阶)进行程序化操作

流程化:编译管线可配置、可复用,支持以 pipeline 配置文件驱动编译流程

IREE 体现:所有内部 dialect 均有自动生成的参考文档;Codegen 采用可插拔的编译策略配置;调度管线支持通过编译标志灵活组合。


四、IREE 完整编译管线映射

阶段 核心 Dialect 主要工作 对应管线
输入导入 StableHLO / TOSA / Torch 前端模型转 MLIR,图优化 InputConversion
全局优化 StableHLO + Tensor 常量折叠、形状推导、算子融合 global-optimization
流划分 Flow 划分 dispatch region,数据流建模 flow
流调度 Stream 并发调度、资源分配、命令编排 stream
算子调度 Linalg + SCF Tiling、Fusion、Vectorize dispatch-creation / codegen
内存降阶 MemRef + Bufferization 缓冲区分配、布局转换 executable-sources
硬件映射 HAL + 后端 dialect 硬件抽象、目标指令集降阶 executable-targets
代码生成 LLVM / SPIR-V / VMVX 汇编、链接、生成二进制 各后端 codegen
宿主编排 VM 主机控制流字节码生成 vm

五、总结

这套层次化规范从工程上解决了 AI 编译器的三大核心难题:

  1. 复杂度可控:将 "模型→硬件" 的巨大语义鸿沟拆解为六次小跨越,每层复杂度在人力可掌握范围内

  2. 可扩展性强:新增前端只需对接高层 dialect,新增硬件只需扩展底层 codegen,中间层复用

  3. 质量可保障:每层 invariants + verifier 构成纵深防御体系,配合逐层 dump 调试能力,显著降低排错成本

IREE 作为该方法论的标杆实践,证明了基于 MLIR 分层降阶的架构能够在多前端、多后端的复杂场景下,同时保证编译效率、运行性能与工程可维护性。

相关推荐
小L~~~21 天前
MLIR学习笔记
笔记·学习·mlir
清钟沁桐2 个月前
mlir 编译器学习笔记之十 -- 数据类型
笔记·学习·mlir
清钟沁桐2 个月前
mlir 编译器学习笔记之九 -- 后端生成
笔记·学习·mlir
喜欢打篮球的普通人4 个月前
MLIR入门
数据库·mlir
greatofdream4 个月前
LLVM安装使用
笔记·mlir
Shining05964 个月前
前沿模型系列(五)《多模态智能及其应用》
人工智能·架构·大模型·mlir·infinitensor·hivm·前沿模型
喜欢打篮球的普通人4 个月前
MLIR快速入门
neo4j·mlir
Shining05964 个月前
AI 编译器系列(七)《(MLIR)AscendNPU IR 编译堆栈》
人工智能·架构·mlir·infinitensor·hivm·ascendnpu ir
读书读傻了哟7 个月前
MLIR编译安装
mlir·llvm