设计院来了位实习生,老师傅带他认门:“咱们院的图纸分好几种画风——建筑师画概念,结构师出计算书,施工队要精确到毫米。它们都是图纸,但接收对象各不相同。”MLIR 的故事就从这“几种画风”开始。MLIR 是 LLVM 项目发起的一套多层级中间表示(IR)框架。这里的“方言”(Dialect),正如设计院里的“制图标准”:每种标准规定自己的图例符号(Operation)、材质标注(Type)和附加说明(Attribute)。一栋楼从概念图变成施工图,要经过概念设计(Linalg)→结构计算(Affine)→机电流程(SCF)→施工图(LLVM IR)→施工(机器码)的逐级深化,每一级由一位“校审员”(Pass)把关。这套“图纸流转体系”就是 MLIR。
在 LLM 时代,谁能把 AI 模型又快又稳地“翻译”到硬件上,谁就掌握推理性能的主动权。理解 MLIR 方言,就是理解 AI 编译器这张隐形的图纸流转网;这是 AI 系统工程师区分“调包侠”与“系统专家”的关键一环。
可视化演示
演示MLIR多级中间表示体系:分层降级展示高层Linalg经Affine/SCF到LLVM IR的渐进式Lowering;核心结构展示Operation/Region/Block三层数据;自定义方言展示ODS定义扩展领域专用操作。
本节配有交互动效(进入视口后自动加载,约 3KB)。
渐进式Lowering 高层→中层→底层 Linalg→LLVM 逐层降级到机器码
认识方言体系
设计院来了位实习生,老师傅带他认门:“咱们院的图纸分好几种画风——建筑师画概念,结构师出计算书,施工队要精确到毫米。它们都是图纸,但接收对象各不相同。”MLIR 的故事就从这“几种画风”开始。MLIR 是一套多层级中间表示(IR)框架,这里的“方言”(Dialect)正如设计院里的“制图标准”:每种标准规定自己有哪些图例符号(Operation)、哪些材质标注(Type)和哪些附加说明(Attribute)。
为什么编译器这么需要“方言”?因为一段 AI 代码,从 PyTorch 的矩阵乘法到 CPU 上的加法指令,跨度实在太大。传统 LLVM 只有一种 IR,就像施工队只看得懂施工图,而 AI 框架画出的“概念图”没人接得住。MLIR 让整个链条上每一层都有自己的 IR,每套 IR 就是一种方言;各层之间通过变换函数互相翻译。
一个典型的 MLIR 工作流里,编译器把高层方言的操作逐步翻译成低层方言:例如把 linalg.matmul 变成仿射循环。每次翻译称为一次 Lowering。只要翻译保持语义——也就是计算结果不变——就可以一层层往下走。
设计院里,方案图到施工图的每一轮深化,楼的形状没变,但标注越来越密。MLIR 的方言与 Lowering,正是把这套“逐级深化图纸”的规则固化成了编译器的基础设施。
- IR_k(第 k 级中间表示)输入的中间代码,如 Linalg 方言的一段矩阵乘法。
- 变换函数 T_k一个 Lowering Pass,负责把一种方言翻译成另一种方言。
- IR_{k+1}(输出结果)翻译后的新代码,例如 Affine 方言的三层循环。
- 语义保持翻译前后计算结果不变,只是表达粒度变细了。
多层IR架构
实习生翻档案馆,发现同一栋楼有“方案图、初设图、施工图、竣工图”四套。老师傅说:“咱们院用四级图纸体系:概念图表达创意,结构图定位梁柱,机电图组织流程,施工图给工人照着做。”MLIR 也内置了类似的四套制图标准:Linalg、Affine、SCF 和 LLVM IR。
这四层并非随意排列,而是“上下游”分明。Linalg 面向张量整体运算,便于做算子融合和向量化;Affine 把循环写成仿射形式,便于做循环变换和依赖分析;SCF 提供结构化控制流,便于并行化与分布;LLVM IR 则直接对接成熟的 LLVM 后端。高层 IR 关心“优化空间大不大”,低层 IR 关心“机器能不能直接执行”。
多层 IR 的核心价值在于“渐进式 Lowering”:把一个巨大的、从张量到寄存器的问题,拆成一串小步骤。每步只拆一点,每层都保留自己那层特有的信息。好比设计院不会让一个人同时把建筑、结构、机电全画完,而是一层层深化、一层层会签。
就像四张图纸都描述同一栋楼,只是粒度不同;MLIR 的四层 IR 也描述同一个计算,只是越来越接近机器。最终施工队拿到的不是“曲面网格”,而是每根构件的精确坐标。
- L1Linalg 到 Affine:把张量的整体运算展开成循环加访存。
- L2Affine 到 SCF:把仿射循环转为通用结构化控制流。
- L3SCF 到 LLVM IR:把结构化控制流转为基本块与跳转。
- 复合管道L1 先执行,再 L2,最后 L3。
Linalg张量运算
建筑师在概念图上写:“玻璃幕墙的双曲网格由 M×N 个单元组成,每个单元通过插值生成。”他不写“先把第 1 根钢条焊上,再焊第 2 根”。这正是 Linalg 方言的思维方式:描述“算什么”,而不是“怎么算”。
Linalg 的名字来自 Linear Algebra(线性代数),是 MLIR 里的高层张量运算方言。一个 linalg.matmul 代表整个矩阵乘法,操作对象是 tensor<4x4xf32> 这样的张量类型。linalg.generic 是更通用的形式,用 indexing_maps 说明每个输入维度如何映射到输出维度,相当于概念图上标注了“这块曲面由哪些参数生成”。
这种“整体视角”带来三个好处。其一,融合:A×B+C 可以看作一次整体操作,方便复用中间结果而不必写回内存。其二,并行:看到 matmul,就知道输出的每个元素彼此独立,天然可以并行计算。其三,匹配硬件:识别出是矩阵乘法后,编译器可以针对 GPU 的 Tensor Core 或 TPU 的脉动阵列生成专门代码。一旦拆成逐条标量指令,这些信息就全丢了。
概念图的好处是一眼看懂意图,代价是工人没法直接干活。Linalg 也一样:它让优化器一眼看到“这是矩阵乘”,但 CPU 还不知道每一步做什么——所以必须交给下一层。
linalg.matmul(A, B, C) 所隐含的数学语义:结果矩阵第 i 行第 j 列元素,等于 A 的第 i 行与 B 的第 j 列做点积。- 输出位置结果矩阵的第 i 行第 j 列。
- 归约求和对 k 从 0 到 K-1 遍历累加。
- 对应乘积A 与 B 在 k 维度上的配对相乘。
- 整体封装一条 Linalg 操作等价于上述求和式。
Affine循环系统
结构工程师拿到概念图后,把曲面网格拆成“第 i 行第 j 根钢柱的位置可以用数学公式算出来”。他画的是精确定位图,上面全是循环和索引。这就是 Affine 方言:它提供 affine.for(带仿射边界的循环)、affine.load 和 affine.store(带仿射索引的访存)。
所谓“仿射”,指循环的边界和下标必须是关于循环变量的线性组合加常数,形如 a*i + b*j + c。这个限制看似死板,实则是“黄金枷锁”。因为编译器可以用整数线性代数工具做三件事:依赖分析——判断两次访存会不会碰到同一位置;循环变换——交换、分块、倾斜循环并保证语义不变;并行提取——发现无依赖的循环直接并行化。如果换成任意下标表达式(比如 A[x[i]]),所有这些数学工具就都失效了。
Affine 是 MLIR 中“高层可优化”与“低层可执行”之间的桥梁。它比 Linalg 更细:把一个大矩阵乘法拆成了三层循环;又比 SCF 更严格:循环边界必须是仿射表达式。正是这份严格,让编译器敢在它身上做各种数学上可证明的变换。
结构图上的每个数字都能用公式推出来、都可以验证。这正是 Affine 被编译器信赖的原因——数学上站得住,机器也容易推理。
- 循环变量向量例如二维循环中的 (i, j)。
- 整数矩阵规定各循环变量之间的线性组合权重。
- 整数偏置平移常数,比如
i+2里的 2。 - 具体示例下标变换 (i, j) 变为 (i, i+j+1)。
SCF控制流
机电工程师关心的不是哪根柱子,而是“电怎么从变压器流到机房、遇到控制器要分个支”。他会画流程图:每一层敷设桥架;如果这层是设备层,就加大线径。这正是 SCF 方言的活。
SCF 全称 Structured Control Flow(结构化控制流),提供 scf.for(通用循环)、scf.if(条件分支)和 scf.while(条件循环)。它比 Affine 更宽容:循环边界不需要仿射,可以是任意变量;条件分支也是结构化的,没有 goto。MLIR 里还有一个 scf.parallel,为 GPU Kernel 的并行划分提供结构基础。
为什么需要这一层“宽容”?两个原因。第一,AI 程序里大量循环无法用仿射刻画,比如 while error > eps 这种根据运行结果决定是否继续的循环。第二,结构化控制流让编译器能轻松画出控制流图(CFG)、做 SSA 分析、做并行化;如果直接坠入 llvm.br 这种裸跳转,分析难度会陡增。SCF 是 Affine 与真正的底层之间最舒适的“过渡层”。
机电流程图比结构图灵活得多,但仍然有序、可审查。SCF 也是如此:它把“走哪条路、循环几遍”说得明明白白,又不至于沦落到跳转满天飞的境地。
for 循环在语义上等价于把循环体 S 按顺序展开执行多次。- 循环边界i 从 l 到 u 但不包含 u。
- 循环体 S每次迭代执行的一组操作。
- 等价展开循环等于依次执行 S(l) 到 S(u-1)。
自定义Dialect
设计院接了一个“张拉膜体育馆”项目,标准图例画不出膜面张力节点。于是院领导说:“给这个项目定制一套张拉膜图例,并在设计软件里注册好。”MLIR 的机制与此如出一辙:自定义 Dialect。
MLIR 允许用户定义自己的方言:一套专属操作(Operation)、类型(Type)与属性(Attribute)。常用方法是 ODS(Operation Definition Specification),用 TableGen 语言声明式描述,再由工具自动生成 C++ 主体代码。一个自定义操作的声明包括:操作名(如 tpu.mma)、操作数、结果、属性,以及验证器。
声明完成后,MLIR 会自动为这个操作生成打印、解析、验证、文档等功能。你只需要实现 Pass,把这些自定义操作逐步 Lowering 到其他方言。芯片厂商常定义 rocm.*、tpu.* 这类方言来表达自家指令;AI 框架也可以定义自己的方言来承载框架级语义。这就是 MLIR 被称为“编译器的编译器”的原因。
定制图例必须被全院登记认可,才能与其他专业的图纸混用。自定义方言也必须注册进 MLIRContext,才能参与整个编译流程的流转。
- 操作数参与运算的输入,例如矩阵 A 和 B。
- 属性编译期已知的常量参数,如转置标记。
- 结果操作产生的输出。
- 验证器判定操作是否合法,非法则拒绝进入 IR。
Lowering管道
设计院有一套“校对→审核→审定”的出图流程。每位校审员只查一个专业,但按固定顺序过一遍,最终图纸质量就有保证。MLIR 的 Lowering Pass 管道,就是这套校审流程。
Pass 是 MLIR 中“一次 IR 变换或优化”的独立单元。比如“仿射展开 Pass”把 affine.for 变成 scf.for,“死代码消除 Pass”删掉没有用的代码。Pass 按顺序执行就形成管道(Pipeline)。用 mlir-opt 工具时,命令行写什么标志,就是选什么管道:
Pass 之间并非完全孤立:MLIR 有 AnalysisManager,上游 Pass 的分析结果可以传给下游复用。比如依赖分析的结果,可以直接喂给循环分块 Pass,避免重复计算。管道的设计是 MLIR 工程的核心艺术:Pass 太碎片化则开销大,太粗犷则难以组合复用。
校审员各有分工,但串联成流程后,整条链路就可靠了。MLIR 不要求一个 Pass 干完所有事,而是用小而专的 Pass 组合出强大管道——这正是渐进式 Lowering 的工程化体现。
- 单个 Pass一次原子的 IR 变换或优化。
- 复合管道多个 Pass 串行执行。
- 顺序敏感性改变 Pass 顺序可能带来不同结果。
--linalg-to-affine --affine-to-scf --convert-scf-to-cf --convert-cf-to-llvmLLVM生态整合
图纸最后流转到施工队项目经理手里,他看一眼就喊:“按图施工,标准工艺,没问题。”施工队有成熟的模板、机具和验收标准——这就是 LLVM。
MLIR 的 llvm 方言与 LLVM IR 几乎一一对应:llvm.load、llvm.add、llvm.br 等。把 SCF、CF 等方言转换到 llvm 方言后,交给 LLVM 就完成了从中间表示到目标机器码的最后一步。这一步是真正的“施工”:指令选择、寄存器分配、指令调度、机器码生成,全部由 LLVM 后端包办。
LLVM 给 MLIR 送来两样大礼。其一是成熟的优化器:指令合并、循环展开、向量化,这些经过十多年打磨的优化直接可用。其二是遍布 x86、ARM、RISC-V、NVIDIA 等平台的后端代码生成器。MLIR 因此不必重建编译器最苦最累的机械工作,而是专注于“高层语义的表达与转换”。这就是为什么一个 PyTorch 模型能从 torch.matmul 开始,经由 MLIR 缓缓下沉,最终变成 GPU 上的一条条指令。
施工队把标准施工工艺都包了,设计院只需要把图画到底。MLIR 专注“高层的图怎么画”,LLVM 负责“最底层的活怎么干”——这对黄金搭档撑起了现代 AI 编译器的半壁江山。
- 输入 LLVM IRMLIR 逐层下沉后产出的低级中间表示。
- 目标架构例如 x86、AArch64、NVIDIA。
- 代码生成函数包含指令选择、寄存器分配、指令调度。
- 输出机器码芯片真正执行的可执行指令。
AI 应用场景
AI芯片编译器的方言桥
阶段:模型编译与推理优化
解决的问题:NVIDIA、AMD、寒武纪等芯片要用自家指令计算矩阵乘加,PyTorch 代码不能直接跑在自研芯片上。传统做法是给每个框架各写一套后端,工作量大且难维护。MLIR 提供了一条“方言桥”:芯片厂商自定义 tpu.* 方言表达硬件算子,再写 Lowering Pass 将 Linalg 等高层方言逐步下沉到自研方言,最后交 LLVM 后端。就像设计院为特殊材料定制图例,再纳入统一图纸流转。
具体案例:某 AI 芯片公司新增了一个“块状稀疏矩阵乘”硬件单元。编译器团队用 ODS 定义一个 sparse.mma 方言操作,写一个 Pass 把 Linalg 的 linalg.matmul 识别为稀疏模式并替换,再经过常规 Lowering 管道落到 LLVM 方言,最终生成芯片指令。
大模型推理引擎的热点优化
阶段:推理部署与性能调优
解决的问题:vLLM、TensorRT-LLM 等推理引擎要对注意力机制做算子融合、对 KV Cache 做内存优化。手动写 CUDA Kernel 改一处就要重新编译,迭代极慢。工程师用 MLIR 在 Linalg 层把注意力里的多个算子融合成一个大 Kernel,再逐层 Lowering 到 CUDA 代码。融合是“把多张图纸合成一张施工图”,减少中间搬运。
具体案例:某推理框架团队发现在 Linalg 层可以将 QK^T、Softmax、PV 三段融合为一个算子。他们在 MLIR 中写了一个融合 Pass,把三个 linalg.generic 合并为一个,内存读写减少 40%,端到端推理吞吐提升 18%。
新硬件架构的快速适配
阶段:异构计算平台开发
解决的问题:AI 芯片新增了专用激活函数单元,标准 LLVM 完全不认识。没有 MLIR 时,要改 LLVM 后端、加内建函数、改框架代码,至少数月。有了 MLIR,开发者只需定义一个新 Dialect 描述该指令的语义,写一个 Pass 将其 Lowering 到 LLVM 方言,再借助内联汇编或 LLVM 内建机制接住。设计院的“新图例”几天就能上线。
具体案例:某自动驾驶芯片团队增加了一个“行归一化加速器”。他们用 ODS 定义了 ada.norm 方言操作,用 2000 行 TableGen 与 C++ 完成定义与 Lowering,两周内让全栈 AI 框架跑通该加速器。
Python 演示
# mini-mlir.py# 演示 MLIR 渐进式 Lowering: 向量加法 a = b + c 在四层方言中的形态变化 class MiniIR: LEVELS = ['linalg', 'affine', 'scf', 'llvm'] def __init__(self, text, level): self.text = text self.level = level self.templates = [ # level 0 -> 1: linalg.generic 展开为仿射循环 "affine.for %i = 0 to 4 {\n" " %vb = affine.load %b[%i] : memref<4xf32>\n" " %vc = affine.load %c[%i] : memref<4xf32>\n" " %v = addf %vb, %vc\n" " affine.store %v, %a[%i] : memref<4xf32>\n" "}", # level 1 -> 2: 仿射循环转为通用 scf 循环 "scf.for %i = 0 to 4 step 1 {\n" " %vb = scf.load %b[%i] : memref<4xf32>\n" " %vc = scf.load %c[%i] : memref<4xf32>\n" " %v = addf %vb, %vc\n" " scf.store %v, %a[%i] : memref<4xf32>\n" "}", # level 2 -> 3: scf 转为 llvm 基本块与跳转 "llvm.br ^bb1\n" "^bb1:\n" " %i = llvm.phi ...\n" " %vb = llvm.load %b[%i]\n" " %vc = llvm.load %c[%i]\n" " %v = llvm.add %vb, %vc\n" " llvm.store %v, %a[%i]\n" " llvm.cond_br %cond, ^bb1, ^bb2" ] @property def level_name(self): return MiniIR.LEVELS[self.level] def lower(self): # 下降一级, 返回新的 MiniIR 实例 if self.level >= len(MiniIR.LEVELS) - 1: return self return MiniIR(self.templates[self.level], self.level + 1) def main(): print("=== MLIR 渐进式 Lowering 演示: a = b + c (向量加法) ===") ir = MiniIR( "linalg.generic {\n" " indexing_maps = [affine_map<(i)->(i)>,\n" " affine_map<(i)->(i)>,\n" " affine_map<(i)->(i)>]\n" "} ins(%b, %c: tensor<4xf32>) outs(%a: tensor<4xf32>)", 0 ) while True: print("\n----- " + ir.level_name.upper() + " -----") print(ir.text) if ir.level == len(MiniIR.LEVELS) - 1: break ir = ir.lower() if __name__ == "__main__": main()
class MiniIR:定义一个迷你 IR 对象,level表示当前方言层级。self.templates预置三次降级的文本模板,对应 Linalg→Affine→SCF→LLVM 的三跳。def lower(self):下降一级并返回新实例,模拟一个 Lowering Pass 的产物。while True:循环打印每一层形态,直到抵达最低层 LLVM。if __name__ == "__main__":提供可执行入口,让脚本可以直接运行。
常见误区
误区MLIR 是像 PyTorch 一样的深度学习框架,可以直接加载模型、做训练和推理。
正解MLIR 不训练、不推理,它是一套“编译器积木”,帮助把各种框架的代码最终翻译成芯片指令。比喻:设计院本身不盖楼,它管理图纸的流转与深化。PyTorch 是建筑师,MLIR 是图纸流转系统,LLVM 是施工队。
为何常见:MLIR 常出现在 AI 芯片与框架优化论文中,名字又带"ML",容易被误认为是又一个端到端的 AI 框架。
误区既然 MLIR 被称为“下一代编译器基础设施”,它迟早完全取代 LLVM。
正解MLIR 的下沉链路末端就是 LLVM IR,MLIR 负责高层表达与优化,LLVM 负责底层后端代码生成,两者是上下游互补关系,不是替代关系。比喻:设计院把图画到施工图,但真正施工还得靠经验丰富的施工队。
为何常见:MLIR 与 LLVM 同出 LLVM 项目,名称相似,初学者容易把它们放在同一个生态位里比较。
误区代码经过越多层变换就越低效,应该一步到位从高层 IR 直接生成机器码。
正解多层 IR 不是多余的中间环节,而是每一层都保留了不同粒度的优化机会,让每个 Pass 只做一件简单的事,总成本反而更低。比喻:写文章一稿到位容易逻辑混乱,逐章修改反而更稳妥。
为何常见:直觉上“中间步骤少=开销少”,忽略了编译器分析复杂度的指数级增长;一次性完成全部 Lowering 的 Pass 几乎无法编写和验证。
误区用 MLIR 自定义一个方言至少要手写几千行 C++ 基础设施,普通人根本碰不了。
正解用 ODS/TableGen 声明式描述后,生成器会自动产出打印、解析、验证等大量样板代码,这是 MLIR 的核心卖点之一。比喻:设计院定了新图例后,制图软件会自动生成符号库和校验规则,不用手工刻印章。
为何常见:MLIR 的 C++ 源码庞大,初学者点开源码看到海量模板代码就望而生畏,忽略了框架本身已替你完成了大部分机械工作。
面试题
Q1. MLIR 中用“方言(Dialect)”指代什么?
- A.一套图纸校审流程
- B.一套制图标准体系← 正确答案
- C.一个模型训练框架
- D.一台代码优化机器
答案:B。方言是 MLIR 中一组操作、类型与属性的集合,类似设计院中“各专业的制图标准”。选项 A 比喻的是 Pass,C 是 PyTorch,D 是 LLVM 优化器,都不符合“方言”的定义。
Q2. 渐进式 Lowering 的核心含义是?
- A.高层IR逐步拆成低层IR← 正确答案
- B.一次性翻译成机器码
- C.反向提升IR抽象级别
- D.只检查语法不改变IR
答案:A。Lowering 是一层层把高层中间表示拆解成低层中间表示,像设计院把概念图逐步深化为施工图。B 是“一步到位”式做法,C 方向反了,D 是校验而非转换。
Q3. 以下四种方言按抽象层级从高到低排列,正确的是?
- A.LLVM IR, SCF, Affine, Linalg
- B.Linalg, Affine, SCF, LLVM IR← 正确答案
- C.SCF, LLVM IR, Linalg, Affine
- D.Affine, Linalg, SCF, LLVM IR
答案:B。Linalg 描述张量整体运算最抽象,Affine 暴露循环与索引,SCF 提供通用控制流,LLVM IR 最贴近机器码,对应方案图→结构图→机电图→施工图的顺序。
Q4. Linalg 方言的一大特色是?
- A.把张量运算当作整体优化← 正确答案
- B.循环边界必须为常数
- C.直接生成机器码输出
- D.只处理标量 load 指令
答案:A。Linalg 把 matmul 这类张量运算看作整体,便于算子融合与并行识别,如同建筑师把曲面网格看作整体。B 描述的是更底层的限制,C 是 LLVM 后端的工作,D 与 Linalg 的 tensor 语义相反。
Q5. Affine 循环索引的优势在于?
- A.索引满足仿射关系便于分析← 正确答案
- B.索引可以是任意哈希函数
- C.循环体内允许任意 goto
- D.不再需要对循环做分析
答案:A。仿射索引让循环的下标依赖能用整数线性代数分析,从而做依赖检测与循环变换,好比结构图的每个数字都能用公式验证。B 会破坏可分析性,C 是非结构化跳转,D 与事实相反。
Q6. 下列属于 SCF 结构化控制流的包括?
- A.scf.for 循环结构← 正确答案
- B.scf.if 条件分支结构← 正确答案
- C.llvm.br 无条件跳转
- D.scf.while 循环结构← 正确答案
答案:ABD。SCF 方言提供 for、if、while 等结构化控制流。llvm.br 属于 LLVM 方言的非结构化跳转,是 SCF 被 Lowering 之后才会出现的东西,好比施工图里的定位线已经不含设计意图。
Q7. 自定义 MLIR Dialect 通常使用?
- A.ODS 与 TableGen 声明定义← 正确答案
- B.手工编写全部解析代码
- C.修改 LLVM 后端源码
- D.使用 JSON 描述所有 Pass
答案:A。MLIR 官方推荐用 ODS(Operation Definition Specification)配合 TableGen 声明操作,自动生成大量 C++ 代码。手写全部解析与验证代码违背 MLIR 的设计初衷,JSON 也不是标准定义方式。
Q8. 关于 Pass 与 Pass 管道,正确的有?
- A.每个 Pass 只做一种变换← 正确答案
- B.管道中 Pass 顺序毫无影响
- C.管道渐进下沉到 LLVM IR← 正确答案
- D.Pass 必须一口气完成降级
答案:AC。Pass 的设计哲学是“小而专”,每个只做一种变换或优化;多个 Pass 串成管道后实现渐进式 Lowering,最终到达 LLVM IR。Pass 顺序对结果有影响,也无需一口气完成全部降级。
Q9. MLIR 下沉到 LLVM IR 之后,主要依靠?
- A.LLVM 后端的指令选择与分配← 正确答案
- B.再次手工写一遍 TOSA 方言
- C.用 Python 逐条解释执行
- D.把 IR 重新提交给前端模型
答案:A。LLVM IR 之后的工作——指令选择、寄存器分配、指令调度——全部由 LLVM 后端完成。MLIR 不必重建这些机械工作,就像设计院把施工交给成熟施工队。TOSA 是更早的方言,Python 执行与流程无关。
Q10. 为什么需要多层 IR 而非一层?
- A.高层 IR 便于整体融合优化← 正确答案
- B.低层 IR 贴近硬件指令语义← 正确答案
- C.各层可以复用 LLVM 后端← 正确答案
- D.多层 IR 只是为了展示美观
答案:ABC。高层 IR 保留张量结构便于融合与并行,低层 IR 贴近硬件便于代码生成,LLVM 后端作为最终出口被多层管道复用。D 是干扰项,多层 IR 是为了工程可维护性与优化空间,而不是为了好看。