ilocker:關注 Android 安全(新手) QQ: 2597294287
LLVM 的 IR (Intermediate Representation) 是其設計中的最重要的部分。優化器在進行代碼優化時所進行的分析和轉換都是針對 IR 的。
在設計 IR 時,考慮到了很多明確的目標,包括:支持輕量級的運行時優化、交叉函數/過程間優化、整體程序分析和侵入式調整轉換等等。
原文:including supporting lightweight runtime optimizations, cross-function/interprocedural optimizations, whole program analysis, and aggressive restructuring transformations, etc.
LLVM IR 本身具備定義良好的語義,下面是一個 .ll 文件的簡單示例:
define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b }
這段 IR 對應的 c 代碼如下:
1 unsigned add1(unsigned a, unsigned b) { 2 return a+b; 3 } 4 5 unsigned add2(unsigned a, unsigned b) { 6 if (a == 0) 7 return b; 8 return add2(a-1, b+1); 9 }
從示例可以看出,LLVM IR 是一個 low-level RISC-like 虛擬指令集,支持 add、subtract (減)、compare、branch 指令。支持 label,並且通常看起來像是一種奇怪格式的匯編語言。
與大多數 RISC 指令集不同,LLVM IR 是強類型的,並具有一個簡單的類型系統。如:i32 是 32 位整數,而 i32** 是指向 32 位整數的指針的指針。
LLVM IR 抽象了一些機器細節。比如,借助 call 和 ret 指令及其顯示參數抽象了調用約定 (call convention)。
LLVM IR 不使用一套固定的命名寄存器,而是使用以 % 字符命名的臨時變量 (如:%tmp1、%a、%b)。
LLVM IR 有三種定義形式:上面示例中的文本形式;內存中的數據結構 (做優化時使用);高效的密集型的磁盤二進制“位代碼 (bitcode)”格式。
llvm-as 工具可以將 .ll 文件 (文本形式的 IR) 轉換為 .bc 文件 (位代碼格式的 IR)。llvm-dis 工具可以將 .bc 文件轉換為 .ll 文件。
優化器針對 IR 進行優化,而不用去管前端輸入的是何種編程語言,后端生成的是何種目標平台的指令。LLVM IR 在設計時必須考慮到前端能夠容易生成 IR,並且支持針對真實的目標平台執行重要的優化。