標籤:
LLVM 是什麼
LLVM 是 low level virtual machine(底層虛擬機器)的簡稱,它是一個開源的編譯器架構,已經被成功應用到多個應用領域。LLVM 的主要作用是它可以作為多種語言的後端,它可以提供可程式化語言無關的最佳化和針對很多種CPU的代碼產生功能。LLVM 核心庫提供了與編譯器相關的支援,可以作為多種語言編譯器的後台來使用。能夠進行程式語言的編譯期最佳化、連結最佳化、線上編譯最佳化、代碼產生。LLVM的項目是一個模組化和可重複使用的編譯器和工具技術的集合。LLVM是伊利諾大學的一個研究項目,提供一個現代化的,基於SSA的編譯策略能夠同時支援靜態和動態任意程式設計語言的編譯目標。自那時以來,已經成長為LLVM的主幹項目,由不同的子項目組成,其中許多正在生產中使用的各種 商業和開源的項目,以及被廣泛用於學術研究。
LLVM 常用命令工具
llvm-as 將可讀的 .ll 檔案彙編成位元組代碼
llvm-dis 將位元組代碼檔案反編成可讀的 .ll 檔案
opt 在一個位元組代碼檔案上運行一系列的 LLVM 到 LLVM 的最佳化
llc 為一個位元組代碼檔案產生本機器代碼
lli 直接運行使用 JIT 編譯器或者解譯器編譯成位元組代碼的程式
llvm-link 將幾個位元組代碼檔案串連成一個
llvm-ar 打包位元組代碼檔案
llvm-ranlib 為 llvm-ar 打包的檔案建立索引
llvm-nm 在 位元組代碼檔案中列印名字和符號類型
llvm-prof 將 ‘llvmprof.out‘ raw 資料格式化成人類可讀的報告
llvm-ld 帶有可裝載的運行時最佳化支援的一般目標連接器
llvm-config 列印出配置時 LLVM 編譯選項、庫、等等
llvmc 一個通用的可定製的編譯器驅動
llvm-diff 比較兩個模組的結構
bugpoint 自動案例測試減速器
llvm-extract 從 LLVM 位元組代碼檔案中解壓出一個函數
llvm-bcanalyzer 位元組程式碼分析器 (分析二進位編碼本身,而不是它代表的程式)
FileCheck 靈活的檔案驗證器,廣泛的被測試載入器利用
tblgen 目標描述閱讀器和產生器
lit LLVM 整合測試器,用於運行測試
LLVM IR
根據編譯原理可知,編譯器不是直接將源語言翻譯為目標語言,而是翻譯為一種“中繼語言”,即“IR”。之後再由中繼語言,利用後端程式和裝置翻譯為目標平台的組合語言。由於中繼語言相當於一款編譯器前端和後端的“橋樑”,不同編譯器的中繼語言IR是不一樣的,而IR可以說是集中體現了這款編譯器的特徵。
LLVM IR主要有三種格式:一種是在記憶體中的編譯中繼語言;一種是硬碟上儲存的二進位中繼語言(以.bc結尾),最後一種是可讀的中間格式(以.ll結尾)。這三種中間格式是完全相等的。
LLVM IR是LLVM最佳化和進行代碼產生的關鍵。根據可讀的IR,我們可以知道再最終產生目標代碼之前,我們已經產生了什麼樣的代碼。而且根據IR,我們可以選擇使用不同的後端而產生不同的可執行代碼。同時,因為使用了統一的IR,所以我們可以重用LLVM的最佳化功能,即使我們使用的是自己設計的程式設計語言。
結構化編譯器前端 Clang 介紹
Clang ( 發音為 /kl??/) 是 LLVM 的一個編譯器前端,它目前支援 C, C++, Objective-C 以及 Objective-C++ 等程式設計語言。Clang 對來源程式進行詞法分析和語義分析,並將分析結果轉換為 Abstract Syntax Tree ( 抽象文法樹 ) ,最後使用 LLVM 作為後端代碼的產生器。
Clang 的開發目標是提供一個可以替代 GCC 的前端編譯器。與 GCC 相比,Clang 是一個重新設計的編譯器前端,具有一系列優點,例如模組化,代碼簡單易懂,佔用記憶體小以及容易擴充和重用等。由於 Clang 在設計上的優異性,使得 Clang 非常適合用於設計原始碼層級的分析和轉化工具。Clang 也已經被應用到一些重要的開發領域,如 Static Analysis 是一個基於 Clang 的靜態程式碼分析工具。
由於 GNU 編譯器套裝 (GCC) 系統龐大,而且 Apple 大量使用的 Objective-C 在 GCC 中優先順序較低,同時 GCC 作為一個純粹的編譯系統,與 IDE 配合并不優秀,Apple 決定從零開始寫 C family 的前端,也就是基於 LLVM 的 Clang 了。Clang 由 Apple 公司開發,原始碼授權使用 BSD 的開源授權。
Clang 的特性:
相比於 GCC,Clang 具有如下優點:
1. 編譯速度快:在某些平台上,Clang 的編譯速度顯著的快過 GCC。
2. 佔用記憶體小:Clang 產生的 AST 所佔用的記憶體是 GCC 的五分之一左右。
3. 模組化設計:Clang 採用基於庫的模組化設計,易於 IDE 整合及其他用途的重用。
4. 診斷資訊可讀性強:在編譯過程中,Clang 建立並保留了大量詳細的中繼資料 (metadata),有利於調試和錯誤報表。
5. 設計清晰簡單,容易理解,易於擴充增強。與代碼基礎古老的 GCC 相比,學習曲線平緩。
當前 Clang 還處在不斷完善過程中,相比於 GCC, Clang 在以下方面還需要加強:
1. 支援更多語言:GCC 除了支援 C/C++/Objective-C, 還支援 Fortran/Pascal/Java/Ada/Go 和其他語言。Clang 目前支援的語言有 C/C++/Objective-C/Objective-C++。
2. 加強對 C++ 的支援:Clang 對 C++ 的支援依然落後於 GCC,Clang 還需要加強對 C++ 提供全方位支援。
3. 支援更多平台:GCC 流行的時間比較長,已經被廣泛使用,對各種平台的支援也很完備。Clang 目前支援的平台有 Linux/Windows/Mac OS。
本段內容參考:http://www.ibm.com/developerworks/cn/opensource/os-cn-clang/
Clang 編譯選項
clang [-c|-S|-E] -std=standard -g
[-O0|-O1|-O2|-O3|-Ofast|-Os|-Oz|-O|-O4]
-Wwarnings... -pedantic
-Idir... -Ldir...
-Dmacro[=defn]
-ffeature-option...
-mmachine-option...
-o output-file
-stdlib=library
input-filenames
大部分選項與 gcc 類似:
-c 只是編譯不連結,產生目標檔案“.o”
-S 只是編譯不彙編,產生彙編代碼
-E 只進行先行編譯,不做其他處理
-g 在可執行程式中包含標準調試資訊
-o file 把輸出檔案輸出到file裡
-I dir 在標頭檔的搜尋路徑列表中添加dir目錄
-L dir 在庫檔案的搜尋路徑列表中添加dir目錄
中間碼的建立與轉化
編譯產生二進位的 .bc 檔案(bitcode file): clang -emit-llvm -c xx.c -o xx.bc
編譯產生 LLVM 的彙編代碼 .ll 檔案( LLVM assembly code): clang -emit-llvm -S xx.c -o xx.ll
.bc 和 .ll 檔案都可以直接用 lli 來執行。
將 .ll 檔案轉化為 .bc 檔案: llvm-as test.ll
將 .bc 檔案轉化為 .ll 檔案: llvm-dis test.bc
將 .bc 或 .ll 檔案轉化為本機平台的彙編代碼: llc test.bc llc test.ll llc test.bc -o test.s
即時編譯器 JIT 簡介
LLVM 中間碼的執行需要用到 Jit。那麼,JIT到底是個什麼東西呢。其實,JIT 是一個即時編譯器,即 Just-in-time Compiler。對於 JIT 的瞭解我也知之勝少,它的作用大概就是對中間碼進行編譯作業,像 JAVA 這種跨平台的語言也是通過 JIT 實現的。在執行 LLVM 的 lli 工具時,會去調用 JIT 將中間碼編譯成本機架構的機器碼再執行。
至於 jit 與 mcjit 的區別,大概是 jit 是 LLVM 舊版本的支援,而 mcjit 是對 jit 新的支援。mc是機器碼的意思,即 Machine Code。在 Wikipedia 看到說,以前的 LLVM 會依賴與本機系統的彙編器或者提供一套工具鏈,然後再翻譯成機器碼。而通過整合過的 LLVM MC 能夠支援大多數的機器架構,包括 x86, x86-64, ARM, ARM64 以及 大部分的 MIPS 架構等。
構架編譯器架構系統 LLVM 使用簡介