LLVM是伊利諾伊大學(xué)的一個研究項目,提供一個現(xiàn)代化的,基于SSA的編譯策略,并能夠同時支持靜態(tài)和動態(tài)的任意編程語言的編譯目標。LLVM由不同的子項目組成,其中許多是正在生產(chǎn)中使用的商業(yè)和開源的項目。它也被廣泛用于學(xué)術(shù)研究。
本書力求將LLVM基礎(chǔ)知識理論與案例實踐融合在一起進行詳細的介紹,幫助讀者理解LLVM工作原理,同時按照應(yīng)用與設(shè)備需要,使用 LLVM進行相應(yīng)的優(yōu)化與部署。本書包含大量示例和代碼片段,幫助讀者掌握LLVM的編譯器開發(fā)環(huán)境。
本書共11章,包括編譯和安裝LLVM、LLVM外部項目、LLVM編譯器、Clang前端基礎(chǔ)、Clang架構(gòu)與實踐示例、LLVM IR實踐、LLVM芯片編譯器實踐示例、LLVM編譯器示例代碼分析、LLVM優(yōu)化示例、LLVM 后端實踐,以及MLIR編譯器。
本書適合算法、軟件、編譯器、人工智能、硬件等專業(yè)方向的企業(yè)工程技術(shù)人員、高校師生、科研工作人員和技術(shù)管理人員閱讀。
這本書是關(guān)于LLVM這一強大而靈活的編譯技術(shù)的詳盡指南,它將幫助開發(fā)者理解編譯器的設(shè)計和實現(xiàn)。鼓勵每位對編譯器技術(shù)有興趣的讀者閱讀這本書,從而提升自身技術(shù)能力。
LLVM(Low Level Virtual Machine)是架構(gòu)編譯器的框架系統(tǒng),用于優(yōu)化以任意程序語言編寫的程序的編譯時間(compile-time)、鏈接時間(link-time)、運行時間(run-time)及空閑時間(idle-time),對開發(fā)者開放,并兼容已有腳本。
LLVM用C 編寫而成,能夠進行程序語言的編譯器優(yōu)化、鏈接優(yōu)化、在線編譯優(yōu)化、代碼生成。簡單來說,LLVM是一個模塊化的編譯器,可以根據(jù)需要選擇不同組件以滿足各自需求。與之形成鮮明對比的是GCC。雖然GCC的功能也很強大,但是它把所有功能都集成在包里,不能獨自拆解出來。舉個例子,假設(shè)需要一個代碼靜態(tài)檢查工具,對于GCC,就要把整個GCC包都包括進來,這樣包就大多了;而對于LLVM,只需要其中一個代碼靜態(tài)檢查組件,可想而知,包就小多了。
構(gòu)造一個編譯器是一項復(fù)雜的任務(wù)。LLVM項目為編譯器提供可重用組件。LLVM核心庫實現(xiàn)了一個優(yōu)化代碼生成器,并為所有流行的硬件設(shè)備提供了一種與源語言無關(guān)的機器代碼中間表示形式。
LLVM是一個龐大且復(fù)雜的AI編譯器框架系統(tǒng)。關(guān)于本書,作者有以下幾點想法:
1)LLVM非常重要。在多年的工作中,作者深感LLVM的重要性。LLVM幾乎完全取代了傳統(tǒng)GCC編譯器。在AI芯片、自動計算、手機等領(lǐng)域的產(chǎn)品開發(fā)中,它是關(guān)鍵模塊,也是這些產(chǎn)品開發(fā)優(yōu)化的核心模塊。
2)LLVM涉及的知識點非常多。LLVM涉及的知識點太多了,需要技術(shù)人員具有深厚的理論基礎(chǔ)與豐富的實踐經(jīng)驗。LLVM涉及的知識點包括芯片、接口、通信、底層驅(qū)動、操作系統(tǒng)、系統(tǒng)軟件、應(yīng)用軟件、AI算法、算子理論、AI框架、匯編預(yù)言、C/C /Python語言等。
3)入門學(xué)習(xí)與動手開發(fā)。本書描述了如何學(xué)習(xí)LLVM知識點,以及如何動手開發(fā),并提供了多個典型開發(fā)示例。
本書包含11章,主要內(nèi)容總結(jié)如下。
1)LLVM安裝與編譯環(huán)境配置,以及LLVM外部依賴的相關(guān)軟件工具的介紹。
2)LLVM的前端Clang的基本原理與開發(fā)實踐。
3)LLVM IR的基本原理與開發(fā)實踐。
4)LLVM后端的關(guān)鍵技術(shù)與開發(fā)示例、LLVM芯片編譯器實踐示例、LLVM優(yōu)化示例、LLVM 后端實踐。
5)基于LLVM派生的算子開發(fā)框架的原理與開發(fā)示例,以及MLIR編譯器等。
在本書寫作過程中,得到了家人的全力支持,在此,對他們表示深深的感謝。感謝機械工業(yè)出版社的編輯,因為他們的辛勤勞作和付出,本書才得以順利出版。由于作者能力有限,書中難免存在紕漏,還望廣大讀者不吝賜教。
吳建明
吳建明,上海交通大學(xué)圖像研究所博士研究生,長期在華為上海研究所工作,F(xiàn)為芯盟科技上海研發(fā)中心AI芯片總架構(gòu)師、聯(lián)合創(chuàng)始人。長期從事人工智能芯片、自動駕駛、人工智能編譯器與工具鏈、AI Framework框架、CameraISP、Audio/VideoCodec、計算機視覺、深度學(xué)習(xí)、嵌入式軟件等研究性工作。帶領(lǐng)團隊完成了自動駕駛芯片整體架構(gòu)設(shè)計、軟件系統(tǒng)整體架構(gòu)設(shè)計、人工智能框架編譯器與工具鏈設(shè)計、端到端應(yīng)用場景分析攝像頭目標檢測分析,語音識別分析,推薦系統(tǒng)分析、TensorRT/nvGraph應(yīng)用GPU部署deploy設(shè)計分析等重點項目。在核心期刊發(fā)表過10余篇論文,在各論壇有關(guān)自動駕駛和芯片設(shè)計領(lǐng)域有很高的知名度。
前言
第1章 編譯和安裝LLVM/
1.1LLVM系統(tǒng)入門/
1.1.1查看LLVM(包括Clang等子項目)/
1.1.2配置和構(gòu)建LLVM與Clang/
1.2獨立構(gòu)建/
1.3軟硬件環(huán)境要求/
1.3.1硬件環(huán)境/
1.3.2軟件環(huán)境/
1.3.3主機C 編譯器和標準庫/
1.3.4獲取流行主機C 工具鏈/
1.4LLVM入門/
1.4.1術(shù)語和符號/
1.4.2打開LLVM存檔文件/
1.4.3從Git中簽出LLVM源代碼/
1.4.4本地LLVM配置/
1.4.5編譯LLVM套件源代碼/
1.4.6交叉編譯LLVM/
1.4.7LLVM目標文件的位置/
1.4.8可選配置項目/
1.5目錄布局/
1.6使用LLVM工具鏈的示例/
1.7LLVM常見問題/
1.8LLVM相關(guān)鏈接/
第2章 LLVM外部項目/
2.1LLDB調(diào)試器/
2.1.1LLDB基礎(chǔ)知識/
2.1.2LLDB控制臺/
2.2C 標準庫libc /
2.2.1libc 庫概述/
2.2.2Ubuntu下安裝Clang和libc /
2.3compiler-rt運行時庫/
2.3.1compiler-rt項目組成/
2.3.2compiler-rt的作用/
2.3.3平臺支持/
2.3.4compiler-rt源代碼結(jié)構(gòu)/
2.3.5構(gòu)建compiler-rt/
2.4DragonEgg /
2.4.1DragonEgg將LLVM作為GCC后端/
2.4.2DragonEgg實踐/
2.5構(gòu)建RISC-V LLVM并編譯和運行test-suite/
2.5.1構(gòu)建RISC-V的前期準備/
2.5.2開始構(gòu)建/
2.5.3編譯test-suite/
2.5.4運行LLVM test-suite/
2.6Clang附加工具/
第3章 LLVM編譯器/
3.1LLVM與Clang源代碼的下載及編譯/
3.1.1下載并編譯 LLVM/
3.1.2Clang源代碼的下載與編譯/
3.2LLVM編譯器基礎(chǔ)結(jié)構(gòu)/
3.2.1LLVM工作原理/
3.2.2LLVM的主要子項目/
3.2.3LLVM與Clang語法/
3.3LLVM三段式編譯 /
3.3.1傳統(tǒng)編譯器三段式設(shè)計及其實現(xiàn)/
3.3.2LLVM的三段式設(shè)計的實現(xiàn)/
3.4LLVM與Clang架構(gòu)/
3.4.1LLVM與Clang架構(gòu)簡介/
3.4.2編譯架構(gòu)特點分析/
3.5LLVM與GCC的區(qū)別/
3.6LLVM IR/
3.6.1什么是LLVM IR/
3.6.2LLVM IR編譯流程/
3.6.3如何得到IR/
3.6.4IR文件鏈接/
3.6.5IR文件編譯流程/
3.6.6IR語法中的關(guān)鍵字/
3.7詞法分析與語法分析/
3.7.1詞法分析/
3.7.2AST結(jié)構(gòu)分析/
3.8交叉編譯器/
3.8.1主機與目標機/
3.8.2為什么要交叉編譯/
3.8.3交叉編譯難點/
3.9后端開發(fā)/
3.9.1XLA后端分析/
3.9.2SSA問題分析/
3.9.3目標信息代碼分析/
3.10LLVM示例實踐/
3.10.1如何在ARM上編譯LLVM/Clang/
3.10.2如何編寫LLVM Pass/
3.10.3基于LLVM的依賴分析方案/
3.11LLVM數(shù)據(jù)并行、時間并行和多核并行/
第4章 Clang前端基礎(chǔ)/
4.1編譯器Clang會代替GCC嗎/
4.1.1GCC概述/
4.1.2Clang概述/
4.1.3GCC基本設(shè)計與示例/
4.1.4GCC與Clang的區(qū)別/
4.2使用 Clang 靜態(tài)分析器進行分析調(diào)試/
4.2.1靜態(tài)分析器概述/
4.2.2靜態(tài)分析器庫的結(jié)構(gòu)/
4.2.3靜態(tài)分析器工作原理/
4.2.4內(nèi)部檢查器/
4.2.5關(guān)于 Clang 靜態(tài)分析器/
4.3如何進行編譯時間混編優(yōu)化/
4.4Clang模塊實現(xiàn)原理探究/
4.4.1ModuleMap 與 Umbrella/
4.4.2模塊的構(gòu)建/
4.4.3Clang模塊復(fù)用機制/
4.4.4PCH與PCM文件/
4.5使用Clang校驗AST/
4.5.1制作Clang命令行工具的初衷/
4.5.2制作Clang命令行工具主要步驟/
4.5.3環(huán)境搭建/
4.5.4開發(fā)框架選擇/
4.5.5代碼開發(fā)/
4.6LLVM與Clang的底層原理/
4.6.1傳統(tǒng)編譯器設(shè)計/
4.6.2Clang前端/
4.6.3IR的優(yōu)化/
4.6.4bitcode/
4.6.5編譯流程總結(jié)示例/
4.7自定義Clang命令,利用LLVM Pass實現(xiàn)對Objective-C函數(shù)的靜態(tài)插樁/
4.7.1Objective-C中的常見的函數(shù)hook實現(xiàn)思路/
4.7.2什么是LLVM Pass/
4.7.3編譯過程/
4.8指令系統(tǒng)/
4.8.1指令系統(tǒng)概述/
4.8.2指令格式/
4.8.3指令的尋址方式/
4.8.4指令的類型與功能/
4.8.5CISC和RISC的比較/
第5章 Clang架構(gòu)與實踐示例/
5.1C語言編譯器Clang/
5.1.1Clang和GCC編譯器架構(gòu)/
5.1.2Clang起源/
5.2Clang模塊內(nèi)部實現(xiàn)原理及源代碼分析/
5.2.1編譯參數(shù)分析/
5.2.2預(yù)處理/
5.3好用的代碼檢查工具/
5.4Clang在Objective-C中的使用/
5.4.1終端使用特點/
5.4.2Clang的簡單使用/
5.5Clang重排對象類結(jié)構(gòu)分析/
5.5.1概述/
5.5.2根類、超類、子類/
5.6使用Clang編譯C程序并在安卓設(shè)備中執(zhí)行/
5.7分析Swift高效的原因/
5.7.1Swift的函數(shù)派發(fā)機制/
5.7.2結(jié)構(gòu)體定義的內(nèi)存分配/
5.7.3編譯SIL/
5.7.4Clang編譯流程的缺點/
5.7.5Swift的特點及其編譯器的使用流程/
5.8LLVM中矩陣的實現(xiàn)分析/
5.8.1背景說明/
5.8.2功能實現(xiàn)/
5.8.3舉例說明/
第6章 LLVM IR實踐/
6.1LLVM架構(gòu)簡介/
6.1.1LLVM IR的演變/
6.1.2LLVM IR是什么/
6.1.3LLVM架構(gòu)/
6.1.4前端生成中間代碼/
6.1.5LLVM后端優(yōu)化IR/
6.1.6LLVM后端生成匯編代碼/
6.2獲取LLVM IR/
6.2.1LLVM IR的三種形式/
6.2.2LLVM IR結(jié)構(gòu)/
6.2.3標識符與變量/
6.3LLVM IR實踐Hello world/
6.3.1LLVM IR程序設(shè)計方法概述/
6.3.2最基本的程序/
6.3.3基本概念解釋/
6.3.4主程序/
6.4LLVM IR數(shù)據(jù)表示/
6.4.1匯編層次的數(shù)據(jù)表示/
6.4.2LLVM IR中的數(shù)據(jù)表示/
6.4.3鏈接類型/
6.4.4可見性/
6.4.5寄存器/
6.5LLVM IR類型系統(tǒng)/
6.5.1類型系統(tǒng)/
6.5.2元數(shù)據(jù)類型/
6.5.3屬性/
6.6LLVM IR控制語句/
6.6.1匯編語言層面的控制語句/
6.6.2LLVM IR層面的控制語句/
6.7LLVM IR語法鏈接類型/
6.8LLVM IR函數(shù)/
6.8.1定義與聲明/
6.8.2傳遞參數(shù)與獲得返回值/
6.8.3內(nèi)置函數(shù)、屬性和元數(shù)據(jù)/
6.9LLVM IR異常處理/
6.9.1異常處理的要求/
6.9.2LLVM IR的異常處理/
6.9.3怎么拋/
6.9.4怎么接/
第7章 LLVM芯片編譯器實踐示例/
7.1編譯器基本概念/
7.1.1LLVM的模塊化編譯器框架/
7.1.2前端在干什么/
7.1.3后端在干什么/
7.1.4DAG下譯/
7.1.5DAG合法化/
7.1.6小結(jié)/
7.2從無到有開發(fā)/
7.2.1不必從頭開始開發(fā)/
7.2.2需要添加的文件類型/
7.2.3從文件角度看整體框架/
7.2.4從類繼承與派生角度看整體框架/
7.3芯片的整體架構(gòu)部分/
7.3.1.h類文件/
7.3.2.td類文件/
7.3.3TargetMachine.cpp和TargetMachine.h類文件/
7.3.4MCTargetDesc類文件/
7.3.5baseInfo類文件/
7.3.6TargetInfo類文件/
7.3.7Subtarget類文件/
7.3.8幾個容易混淆的概念/
7.3.9小結(jié)/
7.4寄存器信息/
7.4.1Registerinfo.td類文件/
7.4.2RegisterInfo類文件/
7.4.3SERegisterinfo類文件/
7.5指令描述的.td文件/
7.5.1InstrFormats.td類文件/
7.5.2InstrInfo.td類文件/
7.5.3依次定義指令/
7.5.4定義指令的自動轉(zhuǎn)換/
7.5.5小結(jié)/
7.6指令描述的.cpp文件/
7.6.1InstrInfo.cpp(.h)類文件/
7.6.2SEInstrInfo.cpp(.h)類文件/
7.6.3AnalyzeImmediate.cpp(.h)類文件/
第8章 LLVM編譯器示例代碼分析/
8.1建立編譯器的基礎(chǔ)框架/
8.2使用 LLVM 實現(xiàn)一個簡單編譯器/
8.2.1目標/
8.2.2詞法分析/
8.2.3語法分析/
8.2.4LLVM IR的代碼生成/
8.2.5優(yōu)化器/
8.2.6添加JIT編譯器/
8.2.7靜態(tài)單一賦值/
8.2.8控制流/
8.2.9用戶自定義操作符/
8.2.10可變變量/
第9章 LLVM優(yōu)化示例/
9.1LLVM優(yōu)化示例介紹/
9.1.1編譯器優(yōu)化目標/
9.1.2LLVM優(yōu)化Pass如何工作/
9.1.3聚集對象的標量替換/
9.1.4公共子表達式消除/
9.1.5全局變量優(yōu)化器 /
9.1.6指令合并器/
9.2改進優(yōu)化條件/
9.2.1偏轉(zhuǎn)循環(huán)移動代碼/
9.2.2運行規(guī)范化自然循環(huán)/
9.2.3歸納變量簡化/
9.2.4進行比特追蹤死代碼消除/
9.3鏈接時優(yōu)化/
9.3.1LTO基本概念/
9.3.2LTO優(yōu)化處理/
9.3.3linkmap分析/
9.4Nutshell LLVM LTO/
9.4.1ThinLTO/
9.4.2高度并行的前端處理和初始優(yōu)化/
9.5LLVM完全LTO/
9.5.1LLVM完全LTO的目標/
9.5.2LLD的整個執(zhí)行流程/
9.6LLVM核心類簡明示例/
第10章 LLVM后端實踐/
10.1LLVM后端概述/
10.1.1LLVM后端基本概念/
10.1.2使用Cpu0作為硬件的例子/
10.2LLVM新后端初始化和軟件編譯/
10.2.1新后端初始化和軟件編譯/
10.2.2LLVM 代碼結(jié)構(gòu)/
10.2.3Cpu0后端初始化/
10.2.4LLVM后端結(jié)構(gòu)/
10.2.5增加 AsmPrinter/
10.2.6增加 DAGToDAGISel/
10.2.7增加 Prologue和Epilogue 部分代碼/
10.2.8操作數(shù)模式/
10.2.9小結(jié)/
10.3算術(shù)和邏輯運算指令/
10.3.1算術(shù)運算指令/
10.3.2邏輯運算指令/
10.4生成目標文件/
10.4.1簡要說明/
10.4.2文件新增/
10.4.3文件修改/
10.4.4檢驗成果/
10.5全局變量/
10.5.1全局變量編譯選項/
10.5.2代碼修改/
10.5.3檢驗成果/
10.5.4小結(jié)/
10.6更多數(shù)據(jù)類型/
10.6.1實現(xiàn)類型/
10.6.2代碼修改/
10.6.3檢驗成果/
10.7控制流/
10.7.1控制流語句/
10.7.2消除無用的JMP指令/
10.7.3填充跳轉(zhuǎn)延遲槽/
10.7.4條件MOV指令/
10.8函數(shù)調(diào)用/
10.8.1棧幀結(jié)構(gòu)/
10.8.2傳入?yún)?shù)/
10.8.3函數(shù)調(diào)用優(yōu)化/
10.9ELF文件支持/
10.9.1ELF文件/
10.9.2支持反匯編/
10.10匯編/
10.10.1棧幀管理/
10.10.2匯編器/
10.10.3內(nèi)聯(lián)匯編/
10.11使用仿真器驗證編譯器/
10.11.1運行仿真器/
10.11.2小結(jié)/
第11章 MLIR編譯器/
11.1MLIR語言參考/
11.1.1高層結(jié)構(gòu)/
11.1.2MLIR符號/
11.1.3MLIR作用域/
11.1.4控制流和SSACFG作用域/
11.1.5類型系統(tǒng)/
11.1.6方言類型/
11.2MLIR方言及運行分析/
11.2.1MLIR簡介/
11.2.2常見的IR表示系統(tǒng)/
11.2.3MLIR的提出/
11.3方言及運行詳解/
11.3.1方言/
11.3.2運行結(jié)構(gòu)拆分/
11.3.3創(chuàng)建新的方言操作/
11.3.4將方言加載到 MLIRContext 中/
11.3.5定義操作/
11.3.6創(chuàng)建方言流程總結(jié)(使用ODS)/
11.4MLIR 運算與算子/
11.4.1MLIR 運算與算子概述/
11.4.2運算類(Operation)/
11.4.3算子類(Op)/
11.4.4MLIR OpBase.td算子類的作用/
11.4.5MLIR 運算的構(gòu)建過程/
11.4.6MLIR TableGen后端生成算子代碼/
11.5MLIR的緣起/
11.6MLIR部署/
11.6.1MLIR部署流程/
11.6.2MLIR應(yīng)用/
11.7MLIR介紹/
11.8MLIR基本數(shù)據(jù)結(jié)構(gòu)/
11.8.1MLIR源代碼目錄/
11.8.2MLIR簡易UML類圖/
11.8.3開發(fā)中用到的具體數(shù)據(jù)結(jié)構(gòu)/
11.9MLIR的出現(xiàn)背景與提供的解決方案/
11.9.1概述/
11.9.2解決方案/
11.10機器學(xué)習(xí)編譯器:MLIR方言體系/
11.10.1基礎(chǔ)組件/
11.10.2方言體系/
參考文獻/