MLIR再深入 —— CodeGen 总结

本文探讨了MLIR中的代码生成流程,特别是针对深度学习框架如TensorFlow的编译过程。文章分析了几种常见的编译管线,如TensorFlowKernelGenerator、IREECompiler以及PolyhedralCompiler,并讨论了LinalgDialect在编译管线中的核心地位。

前言

最近学习了 MLIR 的 Toy Tutorial,并且整理了两篇相关博客。

MLIR初识 —— Dialect及Operation详解

MLIR深入 —— 转换流程详解(以Toy接入为例)

在我的第二篇博客较为详细地介绍了 Toy语言 接入 MLIR,经过多次 pass,最后 lower 成 LLVM IR的流程。但 Toy 接入 MLIR 流程本质上还是高级语言的转换流程,对于深度学习框架接入 MLIR 后的 CodeGen 描述较少。

本文主要以 tensorflow 为例,介绍了其接入 MLIR 后的 CodeGen 过程,以及简要分析了一些现在常用的 CodeGen pipeline。本文是本人在结合博客(Codegen Dialect Overview - MLIR - LLVM Discussion Forums)以及相关资料而写成,主体内容来源于翻译。

在这里插入图片描述

现状

Classification

MLIR 中与代码生成相关的 dialects 大致可以沿着两个轴进行分解:tensor/bufferpayload/structure

dialect 在 tensor/buffer 轴上的分解可以体现出它主要的数据抽象形式,要么是 ML 框架中的 tensor,要么是传统低级编译器预期的 memory buffer。tensors 被视为不一定与内存相关联的不可变值 (immutable values),也就是说,对 tensor 的操作通常不会产生副作用 (side effect)。此类操作之间的数据流可以使用基于 SSA(static single assignment) 格式的用户自定义链(use-definition chains )进行表达。这使得张量操作的重写变得更加简易可行,也是为什么 MLIR 能称为 ML 程序的强大转换工具。另一方面,buffer 是可变的,可能会受到混叠的影响(多个对象可能指向同样的底层存储位置)。这种情况下,数据流只能依据额外的依赖关系和别名分析(aliasing analyses)来提取。tensor 抽象和 buffer 抽象之间的转换由 bufferization 过程来实现,该过程会逐步将两类抽象关联起来,并最终完成替换。一些 dialects(如Linalg和Standard)既有对 tensor 的操作,也有对 buffer 的操作,甚至 Linalg Dialect 中的一些操作可以同时对 tensor 和 buffer 进行处理。

dialect 在 payload/structure 轴上的分解可以体现出,它是描述应该执行怎样的操作(payload),还是描述应该如何执行(structure)。举例来说,在 Standard Dialect 中许多数学操作指定了要执行的计算(e.g., the arctangent, without further detail)。而 SCF Dialct 中定义了如何执行包含的计算(e.g., repeated until some runtime condition is met)。类似的,Async Dialect 表示适用于不同负载粒度(payload granularity)级别的通用执行模型。

dialect 在上述轴上的分解并不是二进制表示的,尤其对于那些更高的抽象级别。许多操作会多多少少都指定了结构(structure)。例如, vector dialect 的操作意味着 SIMD 执行模型。在编译过程中,“如何执行”的描述会越来越详细并且用用低级表述。同时,抽象堆栈的较低层级倾向于将structure操作和payload操作分开,以便在仅仅转换structure操作的同时,又保留对payload操作的抽象理解。

在这里插入图片描述

Dialects of Interest

MLIR 代码生成管道(code generation pipeline)需要经过一系列中间步骤,这个步骤的特点就是使用最近引入的 dialect,例如从高级别的 tensor 表示,到低级别(贴近硬件层面)的 buffer 表示。

dialects 可以根据其 feature 的抽象级别 粗略地组织到一个堆栈中。将较高级别的抽象表示 lower 到较低级别的抽象表示通常较为简单,但反过来就不是这样了。

在编译器一系列转换程序的过程中,越来越多的高层次的简明信息被打散,转换为低层次的细碎指令,这个过程被称为代码表示递降lowerinng ,与之相反的过程被称为代码表示递升raising 。raising远比lowering困难,因为需要在庞杂的细节中找出宏观脉络。

在这里插入图片描述

大多数 pipeline 通过 Linalg Dialect 进入 in

优化LLVM、TVM和MLIR等中间表示层(Intermediate Representation,IR)的性能与结构,是提升编译器效率、程序优化能力和跨平台适配能力的重要手段。以下从不同IR的特点出发,分别探讨优化策略和技术手段。 ### LLVM的优化策略 LLVM IR的优化主要依赖其模块化设计和丰富的Pass机制。为了提升性能,可以从以下几个方面入手: 1. **Pass Pipeline优化**:LLVM的Pass管理机制允许开发者根据目标平台和程序特性自定义优化流程。通过分析程序结构,选择性地启用或禁用某些Pass,例如Loop Unrolling、Function Inlining和Dead Code Elimination,可以显著提升生成代码的性能[^1]。 2. **基于Profile Guided Optimization (PGO)**:利用运行时收集的性能数据指导优化决策,例如分支预测、热点代码优化等,可以更精准地提升性能[^1]。 3. **LLVM IR的结构调整**:通过IR简化、常量传播和控制流优化等手段,减少冗余指令和控制流复杂度,从而提升后续优化阶段的效率。 ### TVM的优化策略 TVM是一个专注于深度学习编译的框架,其IR设计支持多级优化和自动调度。优化TVM IR可以从以下几个方面入手: 1. **自动调度优化(Auto-Scheduler)**:TVM的Auto-Scheduler可以根据硬件特性自动探索最优的执行计划,包括内存访问模式、并行化策略和指令级并行等[^2]。 2. **Operator Fusion**:将多个算子合并为一个复合算子,减少内存访问和调度开销,从而提升执行效率[^2]。 3. **内存优化**:通过内存重用、缓存优化和数据布局调整等手段,减少内存带宽压力。 ### MLIR的优化策略 MLIR的核心优势在于其多级IR架构和Dialect系统,支持从高层语言到低层硬件的多级优化。优化MLIR IR的关键在于: 1. **Dialect转换与融合**:MLIR的Dialect允许不同层次的IR在统一命名空间中进行转换和优化。通过将高层Dialect逐步转换为低层Dialect,并在转换过程中进行语义保留的优化,可以提升整体性能[^3]。 2. **多级IR协同优化**:MLIR支持多级IR的协同优化,例如在高级IR中进行控制流优化,在低级IR中进行寄存器分配和指令调度。这种分层优化策略可以更有效地利用不同层级的优化机会[^3]。 3. **基于MLIR的自定义优化Pass**:利用MLIR提供的Pass框架,开发者可以实现自定义的优化Pass,针对特定应用场景(如深度学习、嵌入式计算)进行定制化优化。 ### 跨IR优化的可能性 LLVM、TVM和MLIR虽然各有侧重,但它们的IR设计都支持模块化优化。通过将MLIR作为前端IR,TVM作为深度学习优化中间层,LLVM作为后端代码生成器,可以构建一个端到端的优化流水线。这种架构允许在不同层级进行协同优化,例如: - 在MLIR中进行高层语义优化; - 在TVM中进行深度学习算子优化; - 在LLVM中进行底层代码生成和优化。 这种跨IR的优化策略可以充分发挥各层IR的优势,实现整体性能的提升[^4]。 ### 示例代码:MLIR中的Dialect转换 以下是一个简单的MLIR示例,展示如何定义和转换Dialect: ```mlir // 定义一个简单的Dialect def MyDialect : Dialect { let name = "mydialect"; let cppNamespace = "mydialect"; } // 使用该Dialect定义一个操作 def MyOp : Op<MyDialect, "my_op"> { let arguments = (ins F32:$input); let results = (outs F32:$output); let assemblyFormat = "$input attr-dict `->` $output"; } // 在MLIR中使用该操作 func @example() { %0 = mydialect.my_op %input : f32 -> f32 return %0 : f32 } ``` 通过定义和转换Dialect,可以在MLIR中实现多级IR优化。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值