LLVM的編譯流程
在介紹編譯流程之前,首先回顧一下LLVM:
LLVM是一個(gè)模塊化的、可重用的編譯器和工具鏈技術(shù)的集合,Clang 是 LLVM 的子項(xiàng)目援制,是 C,C++ 和 Objective-C 編譯器丰刊,它的編譯速度比GCC快3倍隘谣,其中clang static analyzer主要進(jìn)行語法分析、語義分析以及生成中間代碼啄巧,在這個(gè)過程中會(huì)對(duì)代碼進(jìn)行檢查寻歧,對(duì)于出錯(cuò)以及警告的代碼會(huì)給與標(biāo)記。此外秩仆,LLVM核心庫(kù)還提供一個(gè)優(yōu)化器码泛,對(duì)流行的CPU做生成代碼的支持(如x86等機(jī)器)。lld是Clang/LLVM的內(nèi)置鏈接器澄耍,clang必須調(diào)用鏈接器來產(chǎn)生可執(zhí)行文件噪珊。
LLVM相對(duì)于其它編譯器的特殊性在于它提供一種代碼編寫良好的中間表示IR,這意味著它可以作為多種語言的后端齐莲,這樣它就可以在提供語言無關(guān)的優(yōu)化的同時(shí)還可以針對(duì)不同的硬件設(shè)備(CPU)生成對(duì)應(yīng)的機(jī)器代碼痢站。
在介紹LLVM的編譯流程之前,對(duì)于編譯器的編譯鏈接過程需要有一定的了解选酗,可以參閱這些文章
快速開始——介紹LLVM編譯流程
我們從一個(gè)例子開始阵难,觀察一次編譯過程是如何完成的。首先我們編寫如下的代碼:
#import <Foundation/Foundation.h>
#define DEFINEEight 8
int main(){
@autoreleasepool {
int eight = DEFINEEight;
int six = 6;
NSString* site = [[NSString alloc] initWithString:@"starming"];
int rank = eight + six;
NSLog(@"%@ rank %d", site, rank);
}
return 0;
}
可以看到這段代碼輸出一個(gè)字符串和相加后的數(shù)字芒填。將此代碼保存為main.m
文件呜叫。然后使用clang對(duì)其進(jìn)行編譯:
clang -ccc-print-phases main.m
可以看到編譯過程輸出如下:
- 0步驟獲得源代碼
main.m
空繁,是OC語言。 - 1步驟是預(yù)處理階段朱庆,做相應(yīng)處理(后面會(huì)提到)
- 2步驟是編譯階段
- 3步驟通過后端進(jìn)行匯編前的處理
- 4步驟匯編階段
- 5步驟鏈接階段盛泡,做相應(yīng)處理
- 6步驟綁定相應(yīng)變量(或常量等)到硬件機(jī)器上(如寄存器)
通過如上步驟可以了解到整個(gè)過程以及過程中的一些信息。例如首先進(jìn)行的預(yù)處理操作可以使用如下命令查看具體信息:
clang -E main.m
執(zhí)行完后可以看到預(yù)處理后的樣子:
這個(gè)過程包括宏的替換娱颊,頭文件的導(dǎo)入等等傲诵。在預(yù)處理完成后會(huì)進(jìn)行詞法分析,在此步驟會(huì)把代碼切成一個(gè)個(gè)Token维蒙,比如大小括號(hào)掰吕,等于號(hào)還有字符串等。通過如下命令可以看到詞法分析后的結(jié)果:
clang -fmodules -fsyntax-only -Xclang -dump-tokens main.m
詞法分析結(jié)果如下:
接下來是語法分析颅痊,驗(yàn)證程序的語法是否正確,然后將所有的節(jié)點(diǎn)組成抽象語法樹AST:
clang -fmodules -fsyntax-only -Xclang -ast-dump main.m
這些步驟完成之后就要開始進(jìn)行IR中間代碼的生成了局待,代碼生成器CodeGen會(huì)負(fù)責(zé)將語法樹自頂向下遍歷逐步翻譯成LLVM IR斑响,IR就是編譯過程的前端的輸出以及后端的輸入:
clang -S -fobjc-arc -emit-llvm main.m -o main.ll
此步驟LLVM會(huì)去做些優(yōu)化工作,在Xcode的編譯設(shè)置里也可以設(shè)置優(yōu)化的級(jí)別-01钳榨,-03舰罚,-0s等,還可以通過編寫自己的pass自定制優(yōu)化解決方案薛耻,編寫自己的Pass請(qǐng)參閱[這篇文章]
clang -O3 -S -fobjc-arc -emit-llvm main.m -o main.ll
什么是pass呢营罢,可以將pass理解為L(zhǎng)LVM優(yōu)化工作的一個(gè)節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)做一些事饼齿,把這些節(jié)點(diǎn)加起來就構(gòu)成了LLVM完整的優(yōu)化器了饲漾。而且當(dāng)你在Xcode里開啟了bitcode的話還會(huì)做進(jìn)一步的優(yōu)化工作:對(duì)于新的后端架構(gòu)可以使用這份優(yōu)化后的bitcode去生成。這也是LLVM靈活性的一個(gè)體現(xiàn)吧缕溉。
開啟bitcode優(yōu)化:
clang -emit-llvm -c main.m -o main.bc
生成匯編的命令:
clang -S -fobjc-arc main.m -o main.s
再生成目標(biāo)文件:
clang -fmodules -c main.m -o main.o
最后生成可執(zhí)行文件:
clang main.o -o main
這樣通過執(zhí)行./main
就可以看到程序的執(zhí)行結(jié)果啦考传!starming rank 14
那么以上就是LLVM的整個(gè)編譯流程了。對(duì)于具體的Clang編譯過程中的細(xì)節(jié)問題证鸥,將在后續(xù)的文章中進(jìn)行介紹和討論僚楞。歡迎關(guān)注!