文章推薦收藏:LLVM基礎(chǔ)架構(gòu)和Rust
LLVM Infrastructure and Rust
https://www.bexxmodd.com/log/llvm-infrastructre-and-rust/7
一、摘要:
前言
LLVM是許多編程語言背后的引擎。它被用來編譯C、C++、Rust、Go、Swift等語言。這篇文章與LLVM相關(guān),將探索以下主題:
LLVM基礎(chǔ)架構(gòu)是什么
LLVM如何工作
LLVM程序結(jié)構(gòu)
LLVM和Rustc
LLVM基礎(chǔ)架構(gòu)是什么
LLVM基礎(chǔ)架構(gòu)是一組模塊化和可重用的編譯器和工具鏈技術(shù)。LLVM現(xiàn)包含幾個子項目如Clang、C++、Objective-C編譯器,調(diào)試器LLDB、libc++等。
LLVM編譯器框架是一個模塊化和可重用的編譯器框架,使用LLVM基礎(chǔ)架構(gòu)提供端到端代碼編譯。它用于構(gòu)建、優(yōu)化、安全檢查和生成中間代碼(IR)或二進制(機器)代碼(BC)。
LLVM允許將上層編程語言代碼轉(zhuǎn)換為中間表示(IR),后者可以轉(zhuǎn)換為任何給定硬件架構(gòu)的二進制代碼(BC)。LLVM IR語言獨立于源語言和目標語言。
LLVM如何工作
正如前面提到,LLVM是一個模塊化和可重用的編譯器框架,支持多個前端和后端。編寫程序的生命周期包括編寫源代碼,然后將其編譯成二進制代碼以便執(zhí)行。我們感興趣的是編譯階段。當源代碼被編譯成二進制時,它將按照后續(xù)的順序經(jīng)過如下圖所示的幾個步驟。
當源代碼轉(zhuǎn)換成LLVM IR時,它可以采用三種格式之一。內(nèi)存內(nèi)格式是一種適合于編譯過程中前端部分的二進制表示。其他兩種格式是位碼Bitcode(.bc)和匯編Assembly(.ll)。位碼是一種二進制磁盤存儲格式,適合快速加載,因為它的內(nèi)存效率更高。匯編是一種便于人類閱讀的文本格式。
你可能想知道為什么要使用IR/BC而不是原生匯編格式和本地原生二進制格式?
原因是原生匯編格式與平臺的機器碼有一對一的綁定,這取決于目標的架構(gòu)例如針對X86的程序集和針對ARM的程序集是不同的。原生匯編代碼通過匯編程序轉(zhuǎn)換為主機原生二進制文件,LLVM也包含這一特性。
LLVM程序結(jié)構(gòu)
LLVM IR系統(tǒng),就像任何其他系統(tǒng)一樣,有它自己程序結(jié)構(gòu)。
頂層容器是一個Module,它對應(yīng)于前端編譯器的每個翻譯單元。模塊可以由一個或多個函數(shù)組成。每個函數(shù)有一個或多個基礎(chǔ)塊,這些基礎(chǔ)塊包含有指令。指令是單行的,在IR語言中有多種指令可用。
在IR描述中,會遇到兩種變量,局部變量,用%符號表示;全局變量,用@符號表示。
LLVM IR可以使用無限數(shù)量的臨時寄存器,而不是像原生匯編程序那樣只使用預(yù)定義數(shù)量的寄存器。
IR寄存器是由整數(shù)來定義比如1、2、3、..N。例如%2 = load i32, i32* %x表示存儲在本地變量x地址的值被加載到臨時寄存器2中。
LLVM IR另一個優(yōu)點是它利用所謂的靜態(tài)單賦值(Static Single Assignment (SSA))形式。這允許對代碼進行各種優(yōu)化。常規(guī)變量可以被重新賦值多次,而SSA中變量只能被賦值一次(注意這里不包括同一變量使用多次store指令)。這使得編譯器可以進行更有效的寄存器分配,因為在任何給定的點上都可以很容易地近似推導(dǎo)多個活動變量。它可以檢測未使用的變量,并防止程序分配不必要的指針。
例如,下面的代碼x = x * x在SSA中表示為x_2 := x_1 * x_1。如果我們進入變量不斷得到新值的循環(huán)中,SSA使用稱為Phi的節(jié)點,這些Phi節(jié)點將把變量合并到最終的值中,最終的值將從分支或循環(huán)中返回或輸出。
LLVM和Rustc
Rustc官方開發(fā)指南列出了他們?yōu)槭裁词褂肔LVM的原因:
我們不需要編寫完整的編譯器后端。這減少了實現(xiàn)和維護負擔(dān)。
我們從LLVM項目收集的高級優(yōu)化組件中獲益。
我們可以自動將Rust編譯到LLVM支持的任何平臺上。例如只要LLVM添加對wasm的支持,Rust, Clang和許多其他語言都可以編譯成wasm。
我們和其他編譯器項目互相受益。例如當發(fā)現(xiàn)Spectre和Meltdown安全漏洞時,只需要修補LLVM。
解讀Rust示例代碼為何有這樣的IR輸出
作者對上面Rust代碼如何生成IR進行較詳細解讀,比如:factorial函數(shù)中如何使用SSA和Phi節(jié)點來分配使用臨時變量等,感興趣的朋友可進一步深入學(xué)習(xí)了解;
二、讀后感及推薦:
1、這篇文章深入淺出介紹LLVM基礎(chǔ)架構(gòu)及其特點,較詳細解讀Rust示例代碼對應(yīng)生成的LLVM IR含義及要點,特別適合入門理解;
關(guān)鍵詞: LLVM基礎(chǔ)架構(gòu)和Rust