LLVM Intermediate Representation
LLVM IR 链接前端和后端的桥梁
1.LLVM IR的特点
2.LLVM IR的语法
3.如何写一个工具生成LLVM IR
4. LLVM IR pass的结构
5.如何写IR pass
IR对于编译器很重要,决定了优化能使用的信息量。上层的IR要方便获取源码的信息,底层的IR要能生成有利特定硬件性能的代码。
LLVM module
是LLVM IR顶级数据结构,包含一系列函数,函数中又包含一系列basic block,basic block中包含一系列指令。
LLVM module还包含其他一些项,全局变量,target data layout, external function prototypes, data structure declarations。
局部变量
用%开始的字符表示,比如%add = add nsw i32 %0,%1 表示局部变量%0加%1结果放入新的局部变量%add中。
LLVM IR 3大特点:
SSA(Static Single Assignment)
任何变量都只能在定义的时候分配一次。每一次使用该值都能追溯到定义它的那条指令。
SSA对于简化优化很有用,由于SSA创建很多use-def链,一个user对于一串definitions。
如果LLVM 不使用SSA,则需要执行一些额外的数据流分析来计算use-def chain,比如一些经典
优化算法constant propagation和common subexpression elimination.
three-address instructions
数据处理指令有2个源操作数并将结果放在不同的操作数上。
无限量虚拟寄存器
比如局部变量使用%开头的字符,后面追加数字,数字可以无限大。
target datalayout
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-
i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-
a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
e:表示小端 E:表示大端
p:64:64:64表示type:<size>:<abi>:<preferred>
64为指针,abi和preferred都是64位对齐
target triple
target triple = "x86_64-apple-macosx10.7.0"
x86_64的目标处理器使用macosx10.7.0操作系统
函数声明
define i32 @sum(i32 %a, i32 %b) #0 {
返回值为i32类型,输入参数%a, %b都为i32类型
局部变量用%前缀,全局变量用@前缀
LLVM支持的类型
iN 表示任意长度的整型,比如i32, i64, i128
float 32位单精度, double 64位双精度
Vector类型<<# elements> x <elementtype>> ,比如4个i32元素组成的vector <4xi32>
函数声明中的#0映射到一个函数特性集合
attributes #0 = { nounwind ssp uwtable "less-precisefpmad"="false"
"no-frame-pointer-elim"="true"
"no-frame-pointerelim-non-leaf"="true"
"no-infs-fp-math"="false"
"no-nans-fpmath"="false"
"unsafe-fp-math"="false"
"use-softfloat"="false" }
nounwind:表示函数或者方法无throwing exceptions
ssp表示使用stack smash protector
Basic Blocks(BBs)
函数通常被显示地分成多个BB,BB的开始处有一个label
每个BB必须有一个terminator指令结尾,用来跳转到另一个BB或者从函数返回
第一个BB,称为entry BB,不能有任何跳转指令
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
%0 = load i32* %a.addr, align 4
%1 = load i32* %b.addr, align 4
%add = add nsw i32 %0, %1
ret i32 %add
比如上面的entry BB,有一个label "entry",末尾有一个返回指令"ret"
"alloca"指令:保留当前函数栈帧的空间。比如%a.addr = alloca i32, align 4
分配一个4字节的栈元素,并4字节对齐。指向栈元素的指针被存在%a.addr
中。
store指令:将%a和%b值的值存到%a.addr和%b.addr指向的栈中位置 。
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
load指令:将%a.addr和%b.addr指向的栈中位置的值存到%0和%1.
%0 = load i32* %a.addr, align 4
%1 = load i32* %b.addr, align 4
add指令:%0和%1相加存到%add中,其中nsw表示"no signed wrap"?
%add = add nsw i32 %0, %1
Module, Function, Basic Block, Instruction, Value, User
#include <llvm/ADT/SmallVector.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/CallingConv.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/Support/ToolOutputFile.h>
LLVMContext类使用的时候保证一个线程一个context实例
保证线程安全。
LLVM IR 优化通常包括 analysis和transform两部分
Pass dependeceies

浙公网安备 33010602011771号