LLVM項目是子產品化、可重用的編譯器以及工具鍊技術的集合。
美國計算機協會 (ACM) 将其2012 年軟體系統獎項頒給了LLVM,之前曾經獲得此獎項的軟體和技術包括:Java、Apache、 Mosaic、the World Wide Web、Smalltalk、UNIX、Eclipse等等
創始人:Chris Lattner,亦是Swift之父
趣聞:Chris Latter本來隻是想寫一個底層的虛拟機,這也是LLVM名字的由來,low level virtual machine,跟Java的JVM虛拟機一樣,可是後來,llvm從來沒有被用作過虛拟機,哪怕LLVM的名氣已經傳開了。是以人們決定仍然叫他LLVM,更多的時候隻是當作“商标”一樣的感覺在使用,其實它跟虛拟機沒有半毛錢關系。官方描述如下 The name "LLVM" itself is not an acronym; it is the full name of the project. “LLVM”這個名稱本身不是首字母縮略詞; 它是項目的全名。
傳統編譯器架構
Frontend:前端
詞法分析、文法分析、語義分析、生成中間代碼
Optimizer:優化器
中間代碼優化
Backend:後端
生成機器碼
LLVM架構
不同的前端後端使用統一的中間代碼LLVM Intermediate Representation (LLVM IR)
如果需要支援一種新的程式設計語言,那麼隻需要實作一個新的前端
如果需要支援一種新的硬體裝置,那麼隻需要實作一個新的後端
優化階段是一個通用的階段,它針對的是統一的LLVM IR,不論是支援新的程式設計語言,還是支援新的硬體裝置,都不需要對優化階段做修改
相比之下,GCC的前端和後端沒分得太開,前端後端耦合在了一起。是以GCC為了支援一門新的語言,或者為了支援一個新的目标平台,就 變得特别困難
LLVM現在被作為實作各種靜态和運作時編譯語言的通用基礎結構(GCC家族、Java、.NET、Python、Ruby、Scheme、Haskell、D等)
LLVM項目的一個子項目,基于LLVM架構的C/C++/Objective-C編譯器前端。
相比于GCC,Clang具有如下優點
編譯速度快:在某些平台上,Clang的編譯速度顯著的快過GCC(Debug模式下編譯OC速度比GGC快3倍)
占用記憶體小:Clang生成的AST所占用的記憶體是GCC的五分之一左右
子產品化設計:Clang采用基于庫的子產品化設計,易于 IDE 內建及其他用途的重用
診斷資訊可讀性強:在編譯過程中,Clang 建立并保留了大量詳細的中繼資料 (metadata),有利于調試和錯誤報告
設計清晰簡單,容易了解,易于擴充增強

Clang與LLVM
LLVM整體架構,前端用的是clang,廣義的LLVM是指整個LLVM架構,一般狹義的LLVM指的是LLVM後端(包含代碼優化和目标代碼生成)。
源代碼(c/c++)經過clang--> 中間代碼(經過一系列的優化,優化用的是Pass) --> 機器碼
這裡用Xcode建立一個Test項目,然後cd到main.m的上一路徑。
指令行檢視編譯的過程:$ clang -ccc-print-phases main.m
0.找到main.m檔案
1.預處理器,處理include、import、宏定義
2.編譯器編譯,編譯成ir中間代碼
3.後端,生成目标代碼
4.彙編
5.連結其他動态庫靜态庫
6.編譯成适合某個架構的代碼
檢視preprocessor(預處理)的結果:$ clang -E main.m
這個指令敲出,終端就會列印許多資訊,大緻如下:
詞法分析,生成Token: $ clang -fmodules -E -Xclang -dump-tokens main.m
将代碼分成一個個小單元(token)
舉例如下:
可以看出,詞法分析的時候,将上面的代碼拆分一個個token,後面數字表示某一行的第幾個字元,例如第一個void,表示第18行第一個字元。
文法分析,生成文法樹(AST,Abstract Syntax Tree): $ clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
通過文法樹,我們能知道這個代碼是做什麼的。
還是剛剛的test函數
生成文法樹如下:
在終端敲出的時候,終端很直覺的幫我們用顔色區分。我們可以用圖形顯示如下:
test函數的文法樹
LLVM IR有3種表示形式(本質是等價的)
text:便于閱讀的文本格式,類似于彙編語言,拓展名.ll, $ clang -S -emit-llvm main.m
memory:記憶體格式
bitcode:二進制格式,拓展名.bc, $ clang -c -emit-llvm main.m
我們以text形式編譯檢視:
IR基本文法
注釋以分号 ; 開頭
全局辨別符以@開頭,局部辨別符以%開頭
alloca,在目前函數棧幀中配置設定記憶體
i32,32bit,4個位元組的意思
align,記憶體對齊
store,寫入資料
load,讀取資料
官方文法參考 https://llvm.org/docs/LangRef.html
我們的開發都是基于源碼開發,是以我們首先要進行源碼下載下傳和編譯。
源碼下載下傳
源碼編譯
這裡我們在終端敲出的clang是xcode預設内置clang編譯器,我們自己要進行LLVM開發的話,需要編譯屬于我們自己的clang編譯器
接下來依次執行編譯、安裝指令
然後到這裡我們的編譯就完成了。
另一種方式是通過Xcode編譯,生成Xcode項目再進行編譯,但是速度很慢(可能需要1個多小時)。
應用與實踐的參考
libclang、libTooling
官方參考:https://clang.llvm.org/docs/Tooling.html
應用:文法樹分析、語言轉換等
Clang插件開發
官方參考
1、https://clang.llvm.org/docs/ClangPlugins.html
2、https://clang.llvm.org/docs/ExternalClangExamples.html
3、https://clang.llvm.org/docs/RAVFrontendAction.html
應用:代碼檢查(命名規範、代碼規範)等
Pass開發
官方參考:https://llvm.org/docs/WritingAnLLVMPass.html
應用:代碼優化、代碼混淆等
開發新的程式設計語言
1、 https://llvm-tutorial-cn.readthedocs.io/en/latest/index.html
2、https://kaleidoscope-llvm-tutorial-zh-cn.readthedocs.io/zh_CN/latest/