LLVM札记1: 架构

LLVM作者在文章(LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation)对LLVM做了全面的Review。 指出LLVM是对现在JVM和托管C++的高层虚拟机的补充。是指令级别的,在IR层面和架构设计上有创新设计的。具体表现在将前端,中端,后端区分开来,做到编译时,链接时,安装时,运行时的优化。 传统的GCC构建框架,前端和后端代码是强耦合的。而用LLVM实现的编译器在前端Parser翻译好AST后,直接转换成统一的LLVM IR。在编译优化阶段通过Operation抽象的具体实现对语言进行不同处理,很好的体现了面向对象和模块化思维。

  1. 比如:TensorFlow有很多后端支持,以适配不同硬件需要。如TPU下的XLA,移动设备下的TFLite。
  2. 适配硬件的过程中,很多编译优化手段是通用的。没必要重写一遍。
  3. 针对这个问题,LLVM祭出MLIR来解决这个问题。比如A语言实现了某个常量折叠的优化。那么B语言可以复用A语言的优化时用到的数据结构。具体表现在继承一个表结构,复用操作过程。为什么可以共用,因为共享一个统一的中间层表示。你可以在插入多个IR(也是Multiple Layer Intermediate Representation的来源)来表示复杂的处理过程。这就是万能的软件中间层。
  4. LLVM IR是最底层的IR表示,它的设计创新在与可以对指针以SSA指令的方式来做算数操作。
  5. LLVM的另一个创新在于,自带一个类型系统。这个类型系统是抽象的,与上层具体语言无关的。

MLIR大概过程如下,LLVM IR作为底层表示,MLIR中间由用户扩展表示,并可以使用LLVM IR的数据结构。

mlir architecture
摘自文章

如果要分,其实还有中端。以下引用知乎的一段话”中端是最讲算法的部分,图的连通性,深度和广度优先搜索,强连通分量,最短路,拓扑排序这些基本算法全都用得上。后端思维方式是硬件思维,代码需要嵌入大量硬件相关的信息,并且有很多后端相关的优化。后端的优化相对中端更局部一些。”

MLIR目前只是个DSL工厂,社区里有各行各业的人: 硬件从业者,学者,工程师。具体分为研究算法的,设计新硬件的,做verification的,做ML的。

LLVM IR指令集:

  • 通过SSA的形式表达数据流,可以很清楚的定位代码的数据走向。
  • 显式的表达控制流(包括异常)
  • 显式的表达语言无关的类型信息
对于C代码
for (i = 0;i < N; ++i)
    Sum(&A[i],&P);

用LLVM IR来表达的样子是:

loop:
  // phi 指令位于基本块的开头,第一组是初始值,后面的组可以是label。
  %i.1 = phi int [ 0, %bb0 ], [ %i.2, %loop ]
  // 拿到 A指针 往后 偏移 i 的指针 即&A[i]
  %AiAddr = getelementptr float* %A, int %i.1
  // 调用Sum函数,这里的表示虽然是SSA形式,但表现形式很High Level
  call void %Sum(float %AiAddr, %pair* %P)
  // i变量自增1
  %i.2 = add int %i.1, 1
  //  如果 i 小于 N,那么将结果给 tmp.4 
  %tmp.4 = setlt int %i.1, %N
  // 条件跳转,如果tmp.4 为真,跳转到loop,如果为假,跳出循环。
  br bool %tmp.4, label %loop, label %outloop

发表评论

电子邮件地址不会被公开。 必填项已用*标注