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 

posted @ 2020-04-17 03:05  Greenbird  Views(403)  Comments(0)    收藏  举报

To further demonstrate the capabilities of KinFu Large Scale, we made another example with a room.