LLVM IR(LLVM 中介表示法)
/ EL-el-vee-em eye-arr /
許多編譯器過去是一個龐大的程式,把單一語言轉成單一晶片的程式碼,每加一個新語言或新晶片都得重寫一半。LLVM 是一個專案,把可重用的中段抽出來:一份規格明確的中介表示法,加上一大批最佳化與後端的函式庫。LLVM IR 就是那份共享表示法——Clang(給 C 與 C++)、Rust 編譯器、Swift 與許多其他語言都降階進去的共同語言。
LLVM IR 是一種低階、有型別、以 SSA 為基礎的表示法。它看起來有點像一台抽象機器的乾淨組合語言,這台機器有無限多個虛擬暫存器(以 % 開頭,如 %1、%sum)。每個值都有明確型別(i32 表示 32 位元整數、i8* 表示指向位元組的指標,依此類推)。程式碼組織成函式,每個函式由基本區塊(一連串直線執行的指令)構成,以分支相連,且因為它是 SSA 形式,在匯流處使用 phi 節點。它有三種等價形狀:人類可讀的文字(.ll 檔)、一種叫位元碼的精簡二進位(.bc)、以及記憶體中的資料結構。最佳化器與後端都操作這一份 IR。
它重要在於:LLVM IR 是你能實際「看見」最佳化器在做什麼的地方:把它傾印出來、讀它,看著常數在 -O0 與 -O2 之間被摺疊、死碼消失。它也解釋了為什麼這麼多語言共用工具鏈——它們都對應到一份 IR。一個提醒:LLVM IR 並非完美地跨 LLVM 版本或目標可移植。它帶有目標假設(指標大小、資料佈局),同一份 .ll 在不同目標上行為可能不同;把它當作內部產物,而不是穩定的交換格式。
define i32 @add(i32 %a, i32 %b) { %sum = add i32 %a, %b ret i32 %sum } $ clang -O0 -S -emit-llvm add.c -o add.ll # 寫出文字形式的 LLVM IR
LLVM IR 中完整的 add 函式:有型別的值、以 % 表示的虛擬暫存器、SSA、一個明確的回傳。
LLVM IR 不是穩定、可移植的交換格式:它嵌入了目標特定的假設(資料佈局、指標寬度)並隨 LLVM 版本變動,所以同一份 .ll 不保證在各處意義相同。