簡介
LLVM是一套提供編譯器基礎設施的開源專案,是用 C++ 撰寫,包含一系列模塊化的編譯器組件和工具鏈,用來開發編譯器前端和后端,它是為了任意一種編程語言而寫成的程式,利用虛擬技術創造出編譯時期、鏈接時期、執行時期以及“閑置時期”的優化,
LLVM的命名源自于底層虛擬機(Low Level Virtual Machine)的首字母縮寫,導致不了解它的人以為它是類似于 JVM(Java Virtual Machine) 的虛擬機,實際上這個專案的范圍并不局限于創建一個虛擬機,而是包括 LLVM 中介碼(LLVM IR)、LLVM除錯工具、LLVM C++ 標準庫等一系列編譯工具及低端工具技術的集合,
傳統的靜態編譯器設計是三階段設計,其主要組件是前端、優化器和后端,

前端負責詞法分析、語法分析、語意分析、生成中間代碼等功能,
優化器負責進行各種轉換以嘗試提高代碼的運行時間,例如消除冗余計算,并且通常或多或少獨立于語言和目標,
后端(也稱為代碼生成器)負責將代碼映射到目標指令集,除了撰寫正確的代碼外,它還負責生成利用所支持架構的不尋常特性的良好代碼,編譯器后端的常見部分包括指令選擇、暫存器分配和指令調度,
該模型同樣適用于解釋器和 JIT 編譯器,JVM 也是該模型的一個實作,它使用 Java 位元組碼作為前端和優化器之間的介面,
而 LLVM 被設計為支持多種源語言或目標架構,它提供了一套適合編譯器系統的中間語言,如果編譯器在其優化器中使用這個中間語言表示,則可以為任何可以編譯到它的語言撰寫前端,并且可以為任何可以從它編譯的目標撰寫后端,

使用這種設計,移植編譯器以支持新的源語言只需要實作新的前端,即可以重用現有的優化器和后端;同樣想增加支持新的目標架構也只需要實作新的后端,而如果按傳統設計,前端和后端實際是耦合在一起,實作新的源語言或支持新的目標架構將需要從頭開始,要支持 N 目標和 M 源語言將需要 N*M 個編譯器,
LLVM IR
LLVM提供了一套適合編譯器系統的中間語言(Intermediate Representation,IR),有大量變換和優化都圍繞其實作,經過變換和優化后的中間語言,可以轉換為目標平臺相關的匯編語言代碼,
該中間語言與具體的語言、指令集、型別系統無關,其中每條指令都是靜態單賦值形式(SSA), 即每個變數只能被賦值一次,這有助于簡化變數之間的依賴分析,
以下是簡單的 LLVM IR 代碼:
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
}
上述代碼對應的 C 語言代碼為:
unsigned add1(unsigned a, unsigned b) {
return a+b;
}
unsigned add2(unsigned a, unsigned b) {
if (a == 0) return b;
return add2(a-1, b+1);
}
從這個例子可以看出,LLVM IR 是一種強型別的精簡指令集( RISC ),像真正的 RISC 指令集一樣,它支持簡單指令的線性序列,如加法、減法、比較和分支,這些指令采用三地址形式,這意味著它們接受一定數量的輸入并在不同的暫存器中產生結果,LLVM IR 支持標簽,通常看起來像一種奇怪的匯編語言形式,
與大多數 RISC 指令集不同,LLVM 使用簡單的型別系統進行強型別化(例如,i32 是一個 32 位整數,i32** 是一個指向 32 位整數的指標),并且機器的一些細節被抽象掉了,例如,呼叫約定是通過指令和顯式引數 call 抽象出來的,ret 與機器代碼的另一個顯著區別是 LLVM IR 不使用一組固定的命名暫存器,它使用一組無限的以 % 字符命名的臨時暫存器,
LLVM IR 支持三種表達形式:人類可讀的匯編、在C++中物件形式、序列化后的 bitcode 形式,
編譯
LLVM允許代碼被靜態的編譯,包含在傳統的GCC系統底下,者通過實時編譯(JIT)機制將中間表示轉換為機器碼(類似 Java),
LLVM 型別系統包含基本型別(整數或是浮點數)及五個復合型別(指標、陣列、向量、結構及函式),在LLVM具體語言的型別建制可以以結合基本型別來表示,舉例來說,C++所使用的class可以被表示為結構、函式及函式指標的陣列所組成,
LLVM 提供了 Clang 作為官方的編譯器前端,同時支持 C、C++、Objective-C 和 Objective-C++ 語言,主要來自 Apple 公司的贊助支持,Clang 的目的用以取代 GCC 系統底下的 C / Objective-C 編譯器,在當代的系統,它較為容易與集成開發環境(IDE)集成,而且對于執行緒有更好的支持,許多 GCC 的前端也已經可以與其運行,LLVM目前支持 Ada、C語言、C++、D語言、Fortran、Haskell、Julia、Objective-C、Rust 及 Swift 等語言的編譯,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/433291.html
標籤:其他
