主页

索引

模块索引

搜索页面

LLVM

https://img.zhaoweiguo.com/knowledge/images/cores/compilers/LLVM_logo.png

caption

LLVM 元素:

1. 模块
    LLVM 程序是由模块构成的,这个文件就是一个模块。
    模块里可以包括函数、全局变量和符号表中的条目。
    链接的时候,会把各个模块拼接到一起,形成可执行文件或库文件。

    在模块中,你可以定义目标数据布局(target datalayout):
        例:
            target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
        说明:
            开头的小写 “e” 是低字节序(Little Endian)的意思
            对超过一字节的数据,低位字节排放在内存的低地址端,高位字节排放在内存的高地址端
    “target triple” 用来定义模块的目标主机,它包括架构、厂商、操作系统三个部分
        例:
            target triple = "x86_64-apple-macosx10.14.0"

2. 函数
    以 define 开头的函数的声明,还带着花括号
    函数声明时可以带很多修饰成分,比如链接类型、调用约定等
    缺省值:
        链接类型是 external
        调用约定也有很多种选择,缺省是 “ccc”
            C 语言的调用约定(C Calling Convention)
            “swiftcc” 则是 swift 语言的调用约定
3. 标识符
    分为全局的(Glocal)和本地的(Local)
        全局标识符以 @开头,包括函数和全局变量
        本地标识符以 % 开头

    有的标识符是有名字的,比如 @fun1 或 % a
    有的是没有名字的,用数字表示就可以了,如 %1

4. 操作码
    alloca: 栈上分配空间
    store:  写入内存
    load:   从内存中读取
    add:    加法运算
    ret:    从过程中返回
5. 类型系统
    汇编是无类型的,LLVM 汇编则带有一个类型系统
    LLVM 汇编类型系统包括`基础数据类型`、`函数类型`和 `void 类型`

6. 全局变量和常量
7. 元数据
8. 基本块

类型系统

1. 基础数据类型
2. 函数类型
    包括对返回值和参数的定义,比如:i32 (i32)
3. void 类型
    不代表任何值,也没有长度
  1. 基础数据类型:

    a. iN 表示各种长度的整形
    
         1) i1: 1比特整形
         2) i32: 32位整形
    
    b. 多种精度的浮点型
    
         1) half: 16位浮点
         2) float: 32位浮点
         3) double: 64位浮点
         4) fp128: 128位浮点
    
    c. 指针:
    
         1) [4*i32]*: 指向4个i32整形的数组指针
         2) i32(i32*)*: 函数指针, 一个 i32整形指针参数, 返回一个i32值
    
    d. 向量
    
         1) <4 x float>: 4个浮点数的向量
    
    f. 数组
    
         1) [4 x i32]: 4个 i32整数的数组
    
    g. 结点体
    
         1) 普通结构体: {float, i32(i32)*}
                两个元素的结构体,一个浮点数,一个整数
         2) 紧凑结构体: <{i8, i32}>: 比普通结构体多了一个尖括号
                它的元素在存储时是紧挨着的,不考虑内存对齐
                这个结构体占40比特
    
    i. 其他
    
         1) 标签类型
         2) Token 类型
         3) 元数据类型
    

小例子

fun1.c:

int fun1(int a, int b){
  int c = 10;
  return a + b + c;
}

自动生成的LLLM 汇编码:

; ModuleID = 'fun1.c'
source_filename = "fun1.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.14.0"
; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @fun1(i32, i32) #0 {
  %3 = alloca i32, align 4        // 为 3 个变量申请空间
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  store i32 %0, i32* %3, align 4  // 参数 1 赋值给变量 1
  store i32 %1, i32* %4, align 4  // 参数 2 赋值给变量 2
  store i32 10, i32* %5, align 4  // 常量 10 赋值给变量 3
  %6 = load i32, i32* %3, align 4 //
  %7 = load i32, i32* %4, align 4
  %8 = add nsw i32 %6, %7
  %9 = load i32, i32* %5, align 4
  %10 = add nsw i32 %8, %9
  ret i32 %10
}
attributes #0 = { noinline nounwind optnone ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 10, i32 14]}
!1 = !{i32 1, !"wchar_size", i32 4}
!2 = !{i32 7, !"PIC Level", i32 2}
!3 = !{!"Apple LLVM version 10.0.1 (clang-1001.0.46.4)"}

优化后的LLLM 汇编码:

define i32 @fun1(i32, i32) local_unnamed_addr #0 {
  %3 = add i32 %0, 10
  %4 = add i32 %3, %1
  ret i32 %4
}

后端技术的重用

两个编译器后端框架:

1. LLVM:
    开源的编译器基础设施项目,主要聚焦于编译器的后端功能(代码生成、代码优化、JIT……)
    它最早是美国伊利诺伊大学的一个研究性项目
    核心主持人员是 Chris Lattner(克里斯・拉特纳)

    a. 编译器 Clang 就是基于 LLVM 的
        最新的 Swift 编程语言也是基于 LLVM,支撑了无数的移动应用和桌面应用
    b. 开发语言 Kotlin,也支持基于 LLVM 编译成本地代码
    c. Mozilla 公司开发的系统级编程语言 RUST
    d. 一门相对小众的科学计算领域的语言,叫做 Julia
        它既能像脚本语言一样灵活易用,又可以具有 C 语言一样的速度
        在数据计算方面又有特别的优化
    e. OpenGL 和一些图像处理领域
    f. TensorFlow 框架,在后端也是用 LLVM 来编译
        把机器学习的 IR 翻译成 LLVM 的 IR,然后再翻译成支持 CPU、GPU 和 TPU 的程序
2. GCC:

LLVM 优点:

1. LLVM 有良好的模块化设计和接口
2. LLVM 同时支持 JIT(即时编译)和 AOT(提前编译)两种模式
3. 有很多可以学习借鉴的项目。Swift、Rust、Julia
4. 全过程优化的设计思想
    Lattner 和 Adve 最早关于 LLVM 设计思想的文章《LLVM: 一个全生命周期分析和转换的编译框架》
5. LLVM 的授权更友好

主页

索引

模块索引

搜索页面