LLVM 中间语言参考

#概述

LLVM is a Static Single Assignment (SSA) based representation that provides type safety, low-level operations, flexibility, and the capability of representing ‘all’ high-level languages cleanly

更严谨, 更formal的 C 语言

LLVM IR 有三种形态: 位于llvm工具内存中, 以二进制格式存储(.bc文件), 以文本格式存储(.ll文件). 用 llvm-as 可以把 .ll 格式转换为 .bc 格式, llvm-dis 反之

LLVM IR 由和高级语言类似的语句组成.

变量采用 SSA 模式, 不能被重复赋值

#注释

从 ; 到行尾的部分是注释

#局部变量

LLVM IR 中的变量存储临时结果

变量名字以 % 开头, 变量名中可以有 . 等字符, 可以是纯数字

变量不需要提前声明, 赋值即定义变量

1
2
%1 = mul i32 %0, 7          ; v1 = v0 * 7
%2 = zext i1 %1 to i32 ; v2 = (int)v1

#全局变量

全局变量名字以 @ 开头, 其他与局部变量类似

#类型

LLVM IR 必须指定每个变量, 函数的类型

不会发生自动类型转换 避免歧义

#函数

declare 声明函数

1
2
3
declare <ResultType> @Name (argument*)

argument ::= <type> [parameter Attrs] [name]

define 定义函数

1
2
3
4
5
define <ResultType> @Name (argument*) {
...
}

argument ::= <type> [parameter Attrs] [name]

#字符串

和c语言的一样

#标签 label

LLVM IR 的标签和 C 语言中类似

#类型系统

  • void 无值 无大小

  • iN N位整数

  • half/bfloat/float/double/fp128 浮点数

  • <ty>* 指针类型

  • label 标签类型

  • token token类型

  • [<size> x <ty>] 数组类型

    1
    @array = global [42 x i32] zeroinitializer
  • type { <ty> [, <ty>]* } 结构体类型

  • type <{ <ty> [, <ty>]* }> 压缩结构体类型 不做对齐

#常量 Const

  • true/false i1类型
  • null 指针类型
  • none token类型

#指令系统

#控制流指令

  • ret
  • br
  • switch
  • indirectbr
  • invoke

#算术指令

  • fneg
  • add/fadd
  • sub/fsub
  • mul/fmul
  • udiv/sdiv/fdiv
  • urem/srem/frem
  • shl
  • lshr/ashr
  • and/or/xor

#内存指令

#alloca 分配栈内存

1
%ptr = alloca <type>

背后是栈指针的改变

#load store 读取/写入值

1
2
3
<result> = load [volatile] <ty>, ptr <pointer>[, align <alignment>]

store [volatile] <ty> <value>, ptr <pointer>[, align <alignment>]

#指针偏移 Get Element Pointer (GEP)

1
2
<result> = getelementptr <ty>, <ty>* <ptrval>, [i32 <idx>]+
; 语法: getelementptr 结果类型 数组类型* 数组变量 索引(可以有多个)

GEP 仅计算指针加上偏移后的值, 本身并不进行任何数据的访问或修改

偏移按照指向对象的类型, 相当于 C 语言里面的 数组+偏移量 的模式

#类型转换指令

  • trunc … to
  • zext … to
  • sext … to

#杂项指令

  • icmp 整数向量比较
  • fcmp 浮点数向量比较
  • select 类似三元表达式
  • freeze : stop propagation of undef and poison values
  • call 函数调用
  • va_arg 变长参数

#Phi 指令

有时需要对已经定义的变量赋一个新的值 (例如循环变量)

SSA 不允许这样做 -> phi 运算

1
<result> = phi <ty> [<val0>, <label0>], [<val1>, <label1>] …

根据前一个基本块是哪一个 选择对应的值

#内置函数

  • va_start/va_end/va_copy
  • abs/max/min/sin/cos/…
  • ctlz/fshl/…