在编译器和 AI 编译领域,经常会听到 Graph IRSSA IR。 它们并不是“新旧关系”,而是解决不同问题的两类中间表示(IR)

本文用直观的方式解释它们的区别,以及各自适合做什么。


1. 什么是 Graph IR?

直观理解

Graph IR 像一张“算子连接图”

  • 节点(Node)是算子(MatMul、Add、Softmax)
  • 边(Edge)是 Tensor
  • 整体是一个 有向无环图(DAG)

一个简单示例

Q ──┐
    ├─ MatMul ── Softmax ── MatMul ── Out
K ──┘                      ▲

                           V

这在 ONNX、TensorFlow Graph、Pytorch 中看到的形式。


Graph IR 擅长什么?

  • 算子级调度
  • 算子融合(Op Fusion)
  • 跨设备/跨算子执行规划
  • 粗粒度内存规划

一句话:擅长“调度算子”


Graph IR 的局限

Graph IR 不知道

  • 算子内部是否有循环
  • 哪一维是 reduction
  • 是否可以做 tiling
  • 中间结果能否复用
  • 是否存在循环携带依赖

在 Graph IR 中,算子内部是 黑盒


2. 什么是 SSA IR?

直观理解

SSA IR 是“一段可分析、可重写的程序”

SSA(Static Single Assignment)要求:

  • 每个值只定义一次
  • 所有依赖关系显式可追踪

一个简单示例

%a = load %A
%b = load %B
%c = arith.mulf %a, %b
%d = arith.addf %c, %bias

这里的每个 %x 都是一个有生命周期的变量


SSA IR 擅长什么?

  • 循环分析与变换
  • Tiling / Fusion / Unrolling
  • Reduction 重写
  • 数据复用分析
  • 生成 micro-kernel

一句话:擅长“重写程序”


3. 一个关键区别:算子 vs 程序

对比维度Graph IRSSA IR
表达单元算子语句 / 循环
控制流
Loop
Reduction 语义
数据依赖隐式显式
程序重写

本质区别在于:

Graph IR 表达的是 “做什么算子” SSA IR 表达的是 “怎么算”


4. 用 Attention 举一个直观对比

在 Graph IR 中

MatMul(Q, K)
 → Scale
 → Softmax
 → MatMul(·, V)

编译器只能:

  • 调整算子顺序
  • 尝试算子融合

在 SSA IR 中

Attention 会被展开成:

  • 显式的多重循环
  • 明确的 reduction 维度
  • 可分析的中间变量

因此可以:

  • Tile Q/K/V
  • 将 Softmax 改写为 Online Softmax
  • 融合成一个 micro-kernel(如 FlashAttention)

FlashAttention 在 Graph IR 中几乎不可表达,在 SSA IR 中是一次程序重写。


5. 为什么现代 AI 编译器需要两者?

现实中的编译器并不是“二选一”,而是:

Graph IR  →  SSA IR  →  低级 IR

各自分工明确

  • Graph IR
    • 模型结构表达
    • 算子级优化
    • 全局调度
  • SSA IR
    • 循环与数据局部性优化
    • Tiling / Fusion
    • Micro-kernel 生成

6. 一句话总结

Graph IR 是“算子调度的语言”, SSA IR 是“程序优化的语言”。

如果只想“连算子”,Graph IR 足够; 如果想“榨干硬件性能”,SSA IR 不可或缺。