Overview
llvm 示意圖
通過front end後程式碼會被轉為中間碼( LLVM Intermediate Representation (IR) )
紅色部分為llvm提供的功能。
出作業應該不會用到1 (要自己寫),但可能會用到
2. IR interpreter (指令lli)
3. IR compiler (指令 llc)
llvm 指令
1
2
3
|
v = operation type op1, op2 , opn
%sum = add i32 %op1, %op2
運算結果 運算元 型態 運算子們 |
llvm function
宣告
1
2
|
define i32 @add1 ( i32 %a, i32 %b )
define 回傳型態 @函數名稱( 參數列 ) |
回傳
1
2
3
|
ret i32 5 ; 回傳integer ,值為5
ret void ; 回傳void
ret { i32, i8 } { i32 4, i8 2 } ; 回傳結構 {int 32, int 8} , 值為 4 , 2 |
範例
1
2
3
4
5
|
define i32 @add1(i32 %a, i32 %b) {
entry:
%tmp1 = add i32 %a, %b
ret i32 %tmp1
} |
Identifiers
- regular expression: ‘[%@][a-zA-Z$._][a-zA-Z$._0-9]*‘.
- @全域變數
- %區域變數
- 雙引號為字串,可用跳脫字元 \, 後面接ASCII code (ex: 換行為\0A, 而非\n)
- @1 $2這些應該是暫存變數(不確定)
- 全部皆為SSA(single static assigment)
利用clang front end 做測試
安裝
1
|
sudo apt-get install clang llvm
|
把C code 變成 llvm IR (以test.c為例)
1
|
clang test.c -emit-llvm -S
|
C code
1
2
3
4
5
6
7
8
|
#include<stdio.h>
int main()
{
int a, b;
a = 1;
b = a + 1;
printf("%d\n", b);
}
|
llvm IR (test.ll)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
; Function Attrs: nounwind uwtable
define i32 @main() #0 {
%a = alloca i32, align 4
%b = alloca i32, align 4
store i32 1, i32* %a, align 4
%1 = load i32* %a, align 4
%2 = add nsw i32 %1, 1
store i32 %2, i32* %b, align 4
%3 = load i32* %b, align 4
%4 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32 %3)
ret i32 0
}
declare i32 @printf(i8*, ...) #1
|
1. 用interpreter執行llvm IR
2. 把llvm IR 編譯成assembly code
產生出 test.s
利用clang把assembly轉成machine code
執行
結論
用llvm學習compiler,不需考慮暫存器分配(assembly code geneate),但需要考慮SSA。
參考資料
神人投影片
llvm reference