LLVM平臺,短短幾年間,改變了眾多編程語言的走向,也催生了一大批具有特色的編程語言的出現,不愧為編譯器架構的王者,也榮獲2012年ACM軟件系統獎 —— 題記
版權聲明:本文為 西風逍遙游 原創文章,轉載請注明出處 西風世界 [http://blog.csdn.net/xfxyy_sxfancy](http://blog.csdn.net/xfxyy_sxfancy)
### 現代編譯器架構
編譯器技術,作為計算機科學的皇后,從誕生起,就不斷推進著計算機科學的發展,編譯器的發展史,簡直就是計算機發展史的縮影,而編譯器的架構也逐句變得更加優雅,獨立性更強。
但說到編譯器的架構,可能還留存著編譯原理課程的印象,5個經典流程:
詞法分析 -> 語法分析 -> 語義分析 -> 中間代碼優化 -> 目標代碼生成
一般,我們會將編譯器分為一個前端,一個后端,前端負責處理源代碼,后端負責生成目標代碼。
但軟件工程,就是在不斷的抽象和分層,分層解決問題是重要的特點,分層能夠增加層之間的獨立性,更好的完成任務。
### LLVM中間代碼優化
LLVM的一大特色就是,有著獨立的、完善的、嚴格約束的中間代碼表示。這種中間代碼,就是LLVM的字節碼,是LLVM抽象的精髓,前端生成這種中間代碼,后端自動進行各類優化分析,讓用LLVM開發的編譯器,都能用上最先見的后端優化技術。

LLVM另外一大特色就是自帶JIT,要知道,這可是在原來很難想象的技術,一個編譯器要想實現JIT,是需要進行大量努力的,即時翻譯代碼,還要兼顧效率和編譯時間,可不是一件簡單的事情。
但如果你用上了LLVM,JIT只是其中的副產品,直接就可以使用的。
LLVM將中間代碼優化這個流程做到了極致,LLVM工具鏈,不但可以生成所支持的各個后端平臺的代碼,更可以方便的將各語言的前端編譯后的模塊鏈接到一起,你可以方便的在你的語言中調用C函數。

### 可讀的中間代碼
LLVM中間代碼是非常易讀的,而且擁有很多高級結構,例如類型和結構體、元數據等,使用起來非常方便。
~~~
; Declare the string constant as a global constant.
@.str = private unnamed_addr constant [13 x i8] c"hello world\0A\00"
; External declaration of the puts function
declare i32 @puts(i8* nocapture) nounwind
; Definition of main function
define i32 @main() { ; i32()*
; Convert [13 x i8]* to i8 *...
%cast210 = getelementptr [13 x i8], [13 x i8]* @.str, i64 0, i64 0
; Call puts function to write out the string to stdout.
call i32 @puts(i8* %cast210)
ret i32 0
}
; Named metadata
!0 = !{i32 42, null, !"string"}
!foo = !{!0}
~~~
這是一段HelloWorld的LLVM字節碼,我們發現很清晰,而且幾乎所有的位置都有注明類型,這也是在強調,LLVM是強類型的,每個變量和臨時值,都要有明確的類型定義。
下面是結構體的聲明:
~~~
%mytype = type { %mytype*, i32 }
~~~
非常遺憾的是,這個結構體的定義只有類型序列信息,沒有對應子成員的名稱,這是讓編譯器前端自行保存和查表,來記錄這些信息。
C函數的調用非常方便,只需要簡單的聲明
~~~
declare i32 @printf(i8* noalias nocapture, ...)
declare i32 @atoi(i8 zeroext)
~~~
你可以將源碼用LLVM編譯成.bc,然后用llc編譯成.o,再拿Clang鏈接上各個庫就可以了。