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

1
    lli test.ll

2. 把llvm IR 編譯成assembly code

1
    llc test.ll

產生出 test.s 利用clang把assembly轉成machine code

1
    clang test.ll

執行

1
    ./test.ll

結論

用llvm學習compiler,不需考慮暫存器分配(assembly code geneate),但需要考慮SSA。

參考資料

神人投影片 llvm reference