Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
FROM SOURCE TO BINARYHow Compiler WorksFrom source to binary從原始碼到二進制                 Luse Chengソースからバイナリへ               Se...
自我介紹 經歷   Compiler Eng. at MediaTek Inc. (2011~Present)   Compiler Lead at Andes Technology Corporation (2011~2011)   ...
關於今天的演講 摘要  簡短的介紹從原始碼到二進制的流程    三大步驟    Compiler Driver  從原始碼到二進制的重要推手: 編譯器    課本中的編譯器    真實世界的編譯器        GCC     ...
春秋: 微言大義 隱公元年: 夏,五月,鄭伯克段於鄢 短短幾個字,影含著諸多含意  段不弟,故不言弟  如二君,故曰克  稱鄭伯,譏失教也 為什麼要了解從原始碼到二進制  電腦科學所有的問題都可以用另外一層的抽象化來解   決 (...
微言大義:現代Linux環境, 程式啟動流程                                                  動態連結 Shell                                        ...
從原始碼到二進制:常見的誤解 從原始碼到二進制,其實不只需要 Compiler 真相: 需要很多 Tool 同心協力一起完成 (Toolchain) 真正的Compiler 其實只做下面的事…     軟體                ...
編譯 Hello world 程式的流程       C program: hello.c 原始碼      三大步驟        Compiler (CC1) 編譯器                                     ...
圖解簡易完整編譯流程                  #include <stdio.h>                  int main() {                    printf (“Hello World”);   ...
常見的誤解: GCC 是個 C 編譯器                                             gcc 答案: GCC 是一個 Compiler Driver                           ...
Example: GCC 下給 ld 的參數 collect2 version 4.4.3 (i386 Linux/ELF)  /usr/bin/ld --build-id --eh-frame-hdr -m elf_i386 --hash-...
如果有人想當你的程式碼那你怎樣才能做她的編譯器 (Compiler) ? 什麼是編譯器?   Source Language ->    Target Language Recognizer: 讀懂她 Translator: 轉譯她 ...
編譯器小歷史: First compiler (1952)    第一個編譯器    A-0, Grace Murray Hopper First complete compiler (1957)    第一個完整的編譯器    F...
先有雞還是先有蛋 先有C語言還是先有C編譯器 一個有趣的故事:   Ken Thompson : Reflections on Trusting Trust    (Compiling a compiler) Cross-compili...
編譯器的架構 (Textbook)                                      原始碼                                字彙分析 (正規語言)                     ...
編譯器技術=屠龍之技 莊子: 列禦寇第三十二  朱泙漫學屠龍於支離益,單千金之家,三年技成而無  所用其巧。 用白話說就是有個人花了很多錢和時間學了屠龍技能, 後來發現沒有龍可以殺 不過隨著硬體的發展,軟體的複雜度提升,這個世界上的龍也...
while (y < z) {    int x = a + b;    y += x;}                    How Compiler Works   T_While   T_LeftParen               ...
while (y < z) {    int x = a + b;    y += x;}                    How Compiler Works                                       ...
while (y < z) {    int x = a + b;    y += x;}                    How Compiler Works                                       ...
while (y < z) {    int x = a + b;    y += x;}                           How Compiler Works                                ...
真實世界中的編譯器GCC, the GNU Compiler Collection 海灣合作委員會 (X) GNU Compiler Collection (O)         目前最多(*)使用者使用的Compiler(?)
真實世界中的編譯器GCC, the GNU Compiler Collection 從 GNU C Compiler 到 GNU Compiler Collection   支援多種語言 (7), 多種處理器平台 (30+) (GCC 4....
GCC 的架構 課本終究還是課本 GCC 的特性與挑戰:                     int main()   GCC 支援多種語言 (前端)               {                          ...
GCC 的解決之道 (GCC 4.0 以後) C Source        C Front-EndC++ Source      C++ Front-End                                       Gene...
資料流程分析 (Data-flow analysis) 為什麼需要資料流程分析 Q: 兩個指令怎樣才能交換位置 (Code Motion) A: 如果兩個指令沒有相依性的話 資料流程分析 = 偵測指令相依性 Reaching defi...
Code Motion & Pointer Aliasing  C 語言中阻擋 Compiler 最佳化的一大原因     Pointer Aliasing: 兩個不同的指標指到同一個記憶體位置      while (y < z) {  ...
Strict Aliasing Rule & Restrict Pointer Aliasing 如果 Pointer Aliasing 無限上綱   那碰到 Pointer, Compiler 所有的最佳化都動不了 To or not ...
Static single assignment, SSA Form 什麼是 SSA Form   Social Security Administration (X)                                    ...
使用 SSA 可以加強/加快以下的最佳化 Constant propagation Sparse conditional constant propagation Dead code elimination Global value n...
SSA @ Constant propagation (常數傳遞)   用了SSA後每次 Constant propagation 都考100分        EX: GCC-3.x GCC-4.x Example GCC-3.x (No-...
GCC 前端: Source -> AST -> Generic GCC C/C++ frontend   BISON (3.x)                                               b = (a -...
GCC中端: Gimple & Tree SSA Optimizer Gimple 是從 Generic Gimplify 而來的   被限制每個運算只能有兩個運算元 (3-Address IR)     t1 = A op B ( op...
GCC後端: Register Transfer Language (RTL)                         b = a - 56(set (reg:SI 60 [b])     (plus:SI (reg:SI 61 [a]...
GCC後端: RTL Patten Match Engine                       (set (reg:SI 60 [b])    MIPS.md                 (plus:SI (reg:SI 61 [...
GCC後端 : 暫存器分配 暫存器分配其實是個著色問題 (NP-Complete)   給一個無向圖,相鄰的兩個vertex 不能著同一種顏色   每個 vertex 代表的是一個變數, 每個 edge 代表的是兩個變數的生    存時間...
GCC後端 :管線排程  以經典課本的五級Pipeline 為例子   lw $8, a      IF   ID EX ME WB   IF   ID EX ME WB   lw $9, b                         ...
GCC後端 :管線排程 (續) GCC use finite state automaton (FA) based pipeline scheduling model
GCC後端: Peephole optimization 以管窺天最佳化法 掃過整個IR, 看附近2 ~ n 個IR有沒有最佳化的機會  感覺起來就像是用奧步  可是如果奧步有用,那就得要好好使用  在某些時候, 這個最佳化很好用, ...
分很多個.c file or not 分很多個.c file 為什麼要分很多檔案?   因為要讓事情變得簡單 為什麼我們在編譯程式的時候可以下 make -j24?   因為編譯器在Compile 每個 .c 的時候視為獨立個體, 彼 ...
深入淺出 Compilation UnitCompilation Unit                             Compilation Unit 產生的限制  Internal Data  Visible Data    ...
Compilation Unit  盡可能使用區域變數static int i;                             int main()int main()                                {...
GCC 內建函式 (Built-in Function) GCC 為了進行最佳化, 會辨認標準函式(因為語意有 標準規範), 如果符合條件, 就會以處理器最適合的 方式來計算  Strcpy => x86 字串處理指令  Printf =...
IPO (Inter-Procedural Optimization) Procedure / Function: 結構化程式的主軸, 增加可用 性, 減少維護成本   副程式呼叫的執行成本     準備參數: 把變數移到到特定 Regi...
IPO (Inter-Procedural Optimization) 如何 Inline 一個 外部函式?    基本上 Compiler 無法做到        因為 Compiler 在編譯程式的時候不會去看別的          ...
21世紀的另外一種選擇: LLVM LLVM (以前稱為 Low Level Virtual Machine)   用 “現代“ C++ 寫成的 Compiler infrastructure   設計來進行全時最佳化 (compile-...
LLVM: 全時最佳化編譯器平台   GNU Toolchain 的守備範圍    知道原始碼的結構 (O)   編譯階段                          不知道變數的位址 (X)                     ...
LLVM核心觀念:LLVM is a Compiler IR 既然 Compiler framework 就是要支援多種 Front-end 和 多種 Back-end   使用 RISC-Like 平台無關的指令 (LLVM Instru...
LLVM 的架構 : 從原始碼到二進制                                  LLVM Optimizer C Front-End                          BitCode          ...
LLVM Toolchain (llvm-gcc) 既然 LLVM 只是一個 Compiler-IR, 就代表 LLVM 在剛  開始的時候是沒有辦法走完整個編譯流程的 LLVM-GCC (gcc-4.2)     利用 GCC 已經存在...
LLVM Toolchain (Clang) Clang : C, C++, Objective-C 的編譯器前端   Apple 為了取代 GCC 重新打造的 Frontend   重寫一個前端代價是非常昂貴的     其實你是 慣C...
範例: Clang Expressive Diagnostics               struct a {                 virtual int bar();               };             ...
Clang/LLVM Toolchain C Source                   CLANG                             Language                          LLVM B...
滅諸侯,成帝業,為天下一統LLVM 千秋萬世, 一統江湖 Q:挖賽, Clang + LLVM 那麼神, 其他人不是沒戲唱了嗎   A: 在這地球上還沒有人能統一天下, LLVM 當然也不行 Clang 之所以不用產生 Cross Com...
LLVM TableGen (Target Description)         Instruction Encoding (For MC Assembler)                         Input/Output   ...
完美Compiler進化論: LLVM的多變化Source 1        Frontend      LLVM IR 1             LLVM Link                                      ...
LLVM 的發展 史記: 項羽本紀第七   太史公曰:吾聞之周生曰「舜目蓋重瞳子」,又聞項羽亦重瞳子。    羽豈其苗裔邪?何興之暴也!   LLVM 也有兩個 L, 加上一家可以掌握全局垂直整合的公司在後面力    挺, LLVM 也是...
相信你的編譯器 Linux-Kongress 2009: Source Code Optimization    http://www.linux-kongress.org/2009/slides/compiler_survey_     ...
相信你的編譯器: 解答 x86 的指令是可變長度的:   b8 00 00 00 00       mov $0,%eax   83 e0 00             and $0,%eax   29 c0              ...
References http://www.redhat.com/magazine/002dec04/features/gcc/ http://gcc.gnu.org/onlinedocs/gcc http://en.wikipedia....
Any Question ?
Upcoming SlideShare
Loading in …5
×

Hcsm lect-20120913

8,798 views

Published on

新竹碼農: 20120913
From source to binary

Published in: Technology

Hcsm lect-20120913

  1. 1. FROM SOURCE TO BINARYHow Compiler WorksFrom source to binary從原始碼到二進制 Luse Chengソースからバイナリへ Sep 13, 2012 / 新竹碼農Von Quelle Zu Binären Luse ChengDe source au binaire Jim HuangDesde fuente a binario March 31, 2011 / 北科大Binarium ut a fonte
  2. 2. 自我介紹 經歷  Compiler Eng. at MediaTek Inc. (2011~Present)  Compiler Lead at Andes Technology Corporation (2011~2011)  Compiler Eng. at Andes Technology Corporation (2007~2011) 國民革命軍軍人 (Andes Technology Corporation)  從事 Compiler / Toolchain 研究, 開發  從事 Android 開發  從事 Open Source 工作 (GCC … etc) 專門打雜的 Compiler 工程師 (MediaTek Inc.)  應徵的時候是 LLVM 工程師  事實上是專門打雜, Debug 的 Compiler 工程師
  3. 3. 關於今天的演講 摘要  簡短的介紹從原始碼到二進制的流程  三大步驟  Compiler Driver  從原始碼到二進制的重要推手: 編譯器  課本中的編譯器  真實世界的編譯器  GCC  LLVM
  4. 4. 春秋: 微言大義 隱公元年: 夏,五月,鄭伯克段於鄢 短短幾個字,影含著諸多含意  段不弟,故不言弟  如二君,故曰克  稱鄭伯,譏失教也 為什麼要了解從原始碼到二進制  電腦科學所有的問題都可以用另外一層的抽象化來解 決 (All problems in computer science can be solved by another level of indirection)  了解背後的運作原理, 破解微言大義
  5. 5. 微言大義:現代Linux環境, 程式啟動流程 動態連結 Shell 靜態連結 hello ./hello ld-linux.so 動態連結器 eglibc libc_start_main main execve exit SYS_execve SYS_exitkernel 驗證執行檔 啟動loader 棄置Process 配置Process
  6. 6. 從原始碼到二進制:常見的誤解 從原始碼到二進制,其實不只需要 Compiler 真相: 需要很多 Tool 同心協力一起完成 (Toolchain) 真正的Compiler 其實只做下面的事… 軟體 硬體 Source Code HDL Source A compiler is a computer program (or set of programs) Design Compiler (DC) that transforms source codeCompiler (gcc, llvm) RTL Compiler (RC) written in a programming language (the source language) Selecting Technology into another computer Instruction Mapping language (the target language, often having a binary form Assembly Netlist known as object code) source : http://en.wikipedia.org/wiki/Compiler
  7. 7. 編譯 Hello world 程式的流程 C program: hello.c 原始碼 三大步驟 Compiler (CC1) 編譯器 編譯 Assembly File: hello.s 組合語言 Assembler (AS) 組譯器 組譯 Object File: hello.o 目的檔 連結 Linker (LD) 連結器 Executable: hello 執行檔
  8. 8. 圖解簡易完整編譯流程 #include <stdio.h> int main() { printf (“Hello World”); } stdio.h int printf (const char* fmt, …); main:Preprocess int main() { Compile LDR R1, [R2 + 12] printf (“Hello World”); BAL printf } libc.a 0x1000 <printf>: EC 00 00 12 Main: … Assemble EC 00 00 12 Linking F0 ?? ?? ?? 0x2000 <Main>: EC 00 00 12 F0 00 10 00
  9. 9. 常見的誤解: GCC 是個 C 編譯器 gcc 答案: GCC 是一個 Compiler Driver binutils gcc Source (.c and .h) glibc cpp Preprocessed source (.i or .ii) cc1 Asm (.s) as Reloadable (.o) collect2 library crt* Binary ld (Executable)link script GCC 這個執行檔, 可以當Compiler, 也能當 Preprocessor, 也能當 Assembler, 更能當 Linker
  10. 10. Example: GCC 下給 ld 的參數 collect2 version 4.4.3 (i386 Linux/ELF) /usr/bin/ld --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -z relro /usr/lib/gcc/i486-linux- gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux- gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux- gnu/4.4.3/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.4.3 - L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux- gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486- linux-gnu/4.4.3/../../.. hello.o -v -lgcc --as-needed -lgcc_s --no-as- needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486- linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux- gnu/4.4.3/../../../../lib/crtn.o GNU ld (GNU Binutils for Ubuntu) 2.20.1-system.20100303
  11. 11. 如果有人想當你的程式碼那你怎樣才能做她的編譯器 (Compiler) ? 什麼是編譯器?  Source Language -> Target Language Recognizer: 讀懂她 Translator: 轉譯她 Optimization: 調教她 High Level Language Compiler Optimized Low Level Language
  12. 12. 編譯器小歷史: First compiler (1952)  第一個編譯器  A-0, Grace Murray Hopper First complete compiler (1957)  第一個完整的編譯器  Fortran, John Backus (18-man years) Grace Hopper, inventor of A-0, COBOL, and the First multi-arch compiler (1960) term “compiler.”  第一個多平台編譯器  Cobol, Grace Murray Hopper el al. The first self-hosting compiler (1962)  第一個能自己編譯自己的編譯器  LISP, Tim Hart and Mike LevinImage source:http://www-history.mcs.st-and.ac.uk/PictDisplay/Hopper.htmlhttp://upload.wikimedia.org/wikipedia/commons/thumb/5/55/Grace_Hopper.jpg/300px-Grace_Hopper.jpg
  13. 13. 先有雞還是先有蛋 先有C語言還是先有C編譯器 一個有趣的故事:  Ken Thompson : Reflections on Trusting Trust (Compiling a compiler) Cross-compiling and Boot-strapping  用X語言 (like Fortran or ASM) 寫一個C-的編譯器  用C-寫一個C的編譯器  用 C 寫一個C的編譯器
  14. 14. 編譯器的架構 (Textbook) 原始碼 字彙分析 (正規語言) 語法分析 (Context-Free Grammar) 語法樹 語意分析 (Type Checking ..etc) 中間語言 最佳化 目標語言  屠龍刀: Syntax Directed Translator
  15. 15. 編譯器技術=屠龍之技 莊子: 列禦寇第三十二  朱泙漫學屠龍於支離益,單千金之家,三年技成而無 所用其巧。 用白話說就是有個人花了很多錢和時間學了屠龍技能, 後來發現沒有龍可以殺 不過隨著硬體的發展,軟體的複雜度提升,這個世界上的龍也越來越多了
  16. 16. while (y < z) { int x = a + b; y += x;} How Compiler Works T_While T_LeftParen 原始碼 T_Identifier y T_Less 字彙分析 (正規語言) T_Identifier z T_RightParen 語法分析 (Context-Free Grammar) T_OpenBrace T_Int 語法樹 T_Identifier x T_Assign 語意分析 (Type Checking ..etc) T_Identifier a T_Plus 中間語言 T_Identifier b T_Semicolon T_Identifier y 最佳化 T_PlusAssign T_Identifier x 目標語言 T_Semicolon T_CloseBrace http://www.stanford.edu/class/cs143/
  17. 17. while (y < z) { int x = a + b; y += x;} How Compiler Works 原始碼 字彙分析 (正規語言) 語法分析 (Context-Free Grammar) 語法樹 語意分析 (Type Checking ..etc) 中間語言 最佳化 目標語言 http://www.stanford.edu/class/cs143/
  18. 18. while (y < z) { int x = a + b; y += x;} How Compiler Works 原始碼 字彙分析 (正規語言) 語法分析 (Context-Free Grammar) 語法樹 語意分析 (Type Checking ..etc) 中間語言 最佳化 目標語言 http://www.stanford.edu/class/cs143/
  19. 19. while (y < z) { int x = a + b; y += x;} How Compiler Works 原始碼 Loop: x=a+b y=x+y 字彙分析 (正規語言) _t1 = y < z if _t1 goto Loop 語法分析 (Context-Free Grammar) x=a+b 語法樹 Loop: y=x+y _t1 = y < z 語意分析 (Type Checking ..etc) if _t1 goto Loop 中間語言 add $1, $2, $3 loop: add $4, $1, $4 最佳化 slt $6, $1, $5 beq $6, loop 目標語言 http://www.stanford.edu/class/cs143/
  20. 20. 真實世界中的編譯器GCC, the GNU Compiler Collection 海灣合作委員會 (X) GNU Compiler Collection (O) 目前最多(*)使用者使用的Compiler(?)
  21. 21. 真實世界中的編譯器GCC, the GNU Compiler Collection 從 GNU C Compiler 到 GNU Compiler Collection  支援多種語言 (7), 多種處理器平台 (30+) (GCC 4.6.0)  GCC 4.6.0 支援 GO 程式語言 (GCC-GO)  GCC 4.6.0 超過 2 百萬行程式碼  開放原始碼編譯器平台 GCC = Compiler Driver CC1 = 真正的 C Compiler
  22. 22. GCC 的架構 課本終究還是課本 GCC 的特性與挑戰: int main()  GCC 支援多種語言 (前端) { return 0;  GCC 支援多種處理器 (後端) IamDeadCode();  Syntax Directed Translator }  程式的語法樹結構將無法和處理器架構脫鉤 仔細想想: 有些最佳化和語言跟平台都沒有關係  消除沒有用到的程式碼 (Dead code elimination) 所以 GCC 引入中間層最佳化 (編譯器相關最佳化)
  23. 23. GCC 的解決之道 (GCC 4.0 以後) C Source C Front-EndC++ Source C++ Front-End Generic 語言相關 Gimplify Gimple 編譯器相關 Tree SSA Optimizer RTL RTL 平台相關 Target ASM Optimizer Code Generator IR
  24. 24. 資料流程分析 (Data-flow analysis) 為什麼需要資料流程分析 Q: 兩個指令怎樣才能交換位置 (Code Motion) A: 如果兩個指令沒有相依性的話 資料流程分析 = 偵測指令相依性 Reaching definition for a given instruction is another instruction, the target variable of which may reach the given instruction without an intervening assignment  Compute use-def chains and def-use chains
  25. 25. Code Motion & Pointer Aliasing  C 語言中阻擋 Compiler 最佳化的一大原因  Pointer Aliasing: 兩個不同的指標指到同一個記憶體位置 while (y < z) { int t1 = a + b; int x = a + b; while (y < z) { y += x; y += t1; } } Q: How about this? void foo(int *a, int *b, int *y, int z) { while (*y < z) { int x = *a + *b; *y += x; } } A: Compiler 不能把*a + *b 移到迴圈外  因為不確定使用者會不會這樣使用: foo(&num, &num, &num, 5566);  這樣 a, b, y 互為別名, *y 的值改變會使 *a , *b 改變, 故不能提出到迴圈外
  26. 26. Strict Aliasing Rule & Restrict Pointer Aliasing 如果 Pointer Aliasing 無限上綱  那碰到 Pointer, Compiler 所有的最佳化都動不了 To or not to do:  Cross the Rubicon (O)  蒯通說韓信自立為王 (X) Strict Aliasing Rule  摩登編譯器會假設不同 type 之間的 pointer 是沒有 aliasing 的  可是世界上存在相當多原始人程式碼, 所以就造成了很多問題  Note: 使用 -fno-strict-aliasing 來關閉 Strict Aliasing Rule C99: Restrict Pointer Aliasing  使用 restrict 關鍵字 (--std=c99) 來告訴 Compiler 這個 Pointer 不會有 Pointer Aliasing
  27. 27. Static single assignment, SSA Form 什麼是 SSA Form  Social Security Administration (X) Diego Novillo, GCC Internals - IRs  靜態單賦值形式 (O)  静的単一代入 (O)  用白話講, 在這個表示法當中 每個被 Assign 的變數只會出現一次  作法 1. 每個被Assign的變數給一個 Version number 2. 使用 Φ functions Example: (From Wiki)  INPUT: y = 1, y =2, x = y  SSA: y1 = 1, y2 = 2, x1 = y2
  28. 28. 使用 SSA 可以加強/加快以下的最佳化 Constant propagation Sparse conditional constant propagation Dead code elimination Global value numbering Partial redundancy elimination Strength reduction Register allocation
  29. 29. SSA @ Constant propagation (常數傳遞)  用了SSA後每次 Constant propagation 都考100分  EX: GCC-3.x GCC-4.x Example GCC-3.x (No-SSA) int main() {main: int a = 11,b = 13, c = 5566; … int i, result; mov r4, #0 for (i = 0 ; i < 10000 ; i++).L5: result = (a*b + i) / (a*c); mov r1, #61184 return result; add r0, r4, #143 } add r1, r1, #42 add r4, r4, #1 GCC-4.x (SSA) bl __divsi3 cmp r4, r5 main: ble .L5 mov r0, #0 … bx lr
  30. 30. GCC 前端: Source -> AST -> Generic GCC C/C++ frontend  BISON (3.x) b = (a - 56) / c  Hand-written Recursive descent parser (4.x)  C++ in 2004 =  C and Objective-C in 2006 辨識 C 原始碼, 並且轉換成剖析樹 b / (Parsing) - c Abstract Syntax Tree (AST)  抽象語法樹  剖析樹 + 語意 a 56  EX: b = (a - 56) / c
  31. 31. GCC中端: Gimple & Tree SSA Optimizer Gimple 是從 Generic Gimplify 而來的  被限制每個運算只能有兩個運算元 (3-Address IR)  t1 = A op B ( op is operator like +-*/ … etc )  被限制語法只能有某些控制流程  Gimple 可以被化簡成 SSA Form  可以使用 -fdump-tree-<type>-<option> 來觀看其結構 Tree SSA Optimizer  100+ Passes  Loop, Scalar optimization, alias analysis …etc  Inter-procedural analysis, Inter-procedural optimization
  32. 32. GCC後端: Register Transfer Language (RTL) b = a - 56(set (reg:SI 60 [b]) (plus:SI (reg:SI 61 [a]) (const_int -56 [0xffffffc8]))) LISP-Style 的表示法 RTL Uses Virtual Register (無限多個 Register) Register Allocation (Virtual Register -> Hard Register) Instruction scheduling (Pipeline scheduling) GCC Built-in Operation and Arch-defined Operation Peephole optimization
  33. 33. GCC後端: RTL Patten Match Engine (set (reg:SI 60 [b]) MIPS.md (plus:SI (reg:SI 61 [a]) (const_int -56 [0xffffffc8])))(define_insn "*addsi3" [(set (match_operand:GPR 0 "register_operand" "=d,d") (plus:GPR (match_operand:GPR 1 "register_operand" "d,d") (match_operand:GPR 2 "arith_operand" "d,Q")))] "!TARGET_MIPS16" "@ addut%0,%1,%2 d代表是Register addiut%0,%1,%2" Q代表是整數 [(set_attr "type" "arith") (set_attr "mode" "si")]) 指令的屬性(用於管線排程) b = a - 56指令限制(非MIPS16才可使用) addiu $2, $3, -56
  34. 34. GCC後端 : 暫存器分配 暫存器分配其實是個著色問題 (NP-Complete)  給一個無向圖,相鄰的兩個vertex 不能著同一種顏色  每個 vertex 代表的是一個變數, 每個 edge 代表的是兩個變數的生 存時間有重疊 GCC 的暫存器分配,其實比著色問題更複雜  在有些平台,某些指令其實只能搭配某組的暫存器  其實有些變數是常數,或是 memory form,或是他是參數或回傳值,所 以只能分配到某些特定暫存器 Old GCC RA: Reload Pass  GCC 把 pseudo-registers 根據指令的限制對應到硬體暫存器的過程  其實是個複雜到極點的程式, 所以到最後就沒人看得懂了 所以後來就重寫了一個  IRA (Integrated Register Allocator) : 整合 Coalescing, Live range splitting 以及挑選較好的 Hard Register 的做法
  35. 35. GCC後端 :管線排程  以經典課本的五級Pipeline 為例子 lw $8, a IF ID EX ME WB IF ID EX ME WB lw $9, b Clock 0 mul $10,$8,$8 Clock 1add $11,$9,$10 Clock 2 lw $12,c Clock 3add $13,$12,$0 Clock 4 lw $8, a Clock 5 lw $9, b Clock 6 lw $12,c Clock 7 mul $10,$8,$8 Clock 8add $13,$12,$0
  36. 36. GCC後端 :管線排程 (續) GCC use finite state automaton (FA) based pipeline scheduling model
  37. 37. GCC後端: Peephole optimization 以管窺天最佳化法 掃過整個IR, 看附近2 ~ n 個IR有沒有最佳化的機會  感覺起來就像是用奧步  可是如果奧步有用,那就得要好好使用  在某些時候, 這個最佳化很好用, 尤其要生數據的時候 XD ;; sub rd, rn, #1 ;; cmn rd, #1 (equivalent to cmp rd, #-1) ;; bne dest ;; subs rd, rn, #1 ;; bcs dest ((unsigned)rn >= 1) ;; This is a common looping idiom (while (n--))
  38. 38. 分很多個.c file or not 分很多個.c file 為什麼要分很多檔案?  因為要讓事情變得簡單 為什麼我們在編譯程式的時候可以下 make -j24?  因為編譯器在Compile 每個 .c 的時候視為獨立個體, 彼 此之間沒有相依性  用Compiler的術語稱之為 Compilation Unit Static Global Variable vs Non-Static Global Variable  Static: 只有這個 Compilation Unit 可以看到這個變數  Non-Static: 所有Compilation Unit 可以看到這個變數  Q: 怎麼使用別的別的 Compilation Unit 內的變數  A: 使用 extern 關鍵字. EX: extern int i;
  39. 39. 深入淺出 Compilation UnitCompilation Unit  Compilation Unit 產生的限制 Internal Data Visible Data  關於沒有人使用的 Static Global External Data Reference Variable  Compiler 可以砍掉它來節省空間 Internal Function  關於沒有人使用的 Non-Static Global Variable Visible Function  Compiler 不能砍掉它  因為不能確定別的 Compilation Unit 會不會用到它 External Func Reference  Note: 如果確定沒有別的檔案 Internal Function 會使用到這個變數或函式, 請 宣告成 static
  40. 40. Compilation Unit 盡可能使用區域變數static int i; int main()int main() {{ int i; for (i = 0 ; i < 10; i++) for (i = 0 ; i < 10; i++) printf ("Hello %dn", i); printf ("Hello %dn", i);} }main: main: mov r3, #0 stmfd sp!, {r4, lr} 11 stmfd sp!, {r4, lr} mov r4, #0 movw r4, #:lower16:.LANCHOR0 .L2: movt r4, #:upper16:.LANCHOR0 mov r1, r4 mov r1, r3 ldr r0, .L4 str r3, [r4, #0] add r4, r4, #1.L2: bl printf ldr r0, .L4 cmp r4, #10 bl printf bne .L2 ldr r1, [r4, #0] ldmfd sp!, {r4, pc} add r1, r1, #1 .L4: str r1, [r4, #0] .word .LC0 cmp r1, #9 ble .L2 ldmfd sp!, {r4, pc}.L4: .word .LC0
  41. 41. GCC 內建函式 (Built-in Function) GCC 為了進行最佳化, 會辨認標準函式(因為語意有 標準規範), 如果符合條件, 就會以處理器最適合的 方式來計算  Strcpy => x86 字串處理指令  Printf => Puts, Putc  Memcpy => Block Transfer Instruction 這對開發嵌入式系統的人常造成困擾  因為開發嵌入式系統的人喜歡開發自己殘廢的printf (X)  因為開發嵌入式系統需要客製化的printf (O)  Note: 使用 -fno-builtin-XXX or -fno-builtin 來關閉這個功能
  42. 42. IPO (Inter-Procedural Optimization) Procedure / Function: 結構化程式的主軸, 增加可用 性, 減少維護成本  副程式呼叫的執行成本  準備參數: 把變數移到到特定 Register 或 push 到 Stack  呼叫副程式, 儲存和回復 Register Context  現代化程式: 有許多很小的副程式  int IsOdd(int num) { return (num & 0x1); } 最簡單的 IPO: Function inlining  簡單來說: 把整個副程式copy 一份到 caller 的程式碼去
  43. 43. IPO (Inter-Procedural Optimization) 如何 Inline 一個 外部函式?  基本上 Compiler 無法做到  因為 Compiler 在編譯程式的時候不會去看別的 Compilation Unit 的內容, 不知道內容自然就沒辦法 inline 一個看不見的函式 解法: Link Time Optimization (LTO)  或叫: Whole-Program Optimization (WPO)  關鍵 Link Time Code GenerationSource 1 Compiler IR 1 Linker Full IR CompilerSource 2 Compiler IR 2 OptimizedSource 3 Compiler IR 3 Program
  44. 44. 21世紀的另外一種選擇: LLVM LLVM (以前稱為 Low Level Virtual Machine)  用 “現代“ C++ 寫成的 Compiler infrastructure  設計來進行全時最佳化 (compile-time, link-time, run- time, and idle-time optimizations)  LLVM 起源  2000年UIUC Vikram Adve 與 Chris Lattner 的研究發展而成  後來受到蘋果重用而大發異彩  蘋果概念股 (?)  FreeBSD 10 將使用 Clang/LLVM 為預設的編譯器
  45. 45. LLVM: 全時最佳化編譯器平台 GNU Toolchain 的守備範圍  知道原始碼的結構 (O) 編譯階段  不知道變數的位址 (X)  不知道原始碼的結構 (X) 連結階段  知道變數的位址 (O)  不知道原始碼的結構 (X) 載入/安裝階段  不知道變數的位址 (X)  知道處理器有甚麼能力 (O) 執行階段 正所謂是 橫看成嶺側成峰 空閒階段 遠近高低各不同
  46. 46. LLVM核心觀念:LLVM is a Compiler IR 既然 Compiler framework 就是要支援多種 Front-end 和 多種 Back-end  使用 RISC-Like 平台無關的指令 (LLVM Instruction)和資料 (Metadata) 來表達原始碼 LLVM IR 的三變化 (等價形式)  In-Memory Form: JIT  Assembly language representation: ASM format (.ll)  Bitcode representation: Object code format (.bc) 特點  Self-contained Representation 且有良好規範的 Compiler IR  可以將 Compiler 到一半的結果序列化
  47. 47. LLVM 的架構 : 從原始碼到二進制 LLVM Optimizer C Front-End BitCode Stream-out LLVM bitcode Passes OptimizedC++ Front-End LLVM bitcode Selection DAG Passes… Front-End Machine PassesNot in LLVM LLVM C/C++ LLVM ARM LLVM x86 Back-End Back-End Back-End In LLVM C/C++ Source ARM ASM X86 ASM Use LLVM Target ARM Object X86 Object Execution (JIT) Execution (JIT)
  48. 48. LLVM Toolchain (llvm-gcc) 既然 LLVM 只是一個 Compiler-IR, 就代表 LLVM 在剛 開始的時候是沒有辦法走完整個編譯流程的 LLVM-GCC (gcc-4.2)  利用 GCC 已經存在而且眾多大眾使用的 Front-end  後來 RMS 就出來打槍這種方式 (GCC 4.3, GPLv3)  後來 Apple 就跳出來發展自己的 Front-end (Clang) C Source C Front-End GenericC++ Source C++ Front-End Gimplify Gimple LLVM BitcodeNOTE: LLVM早期的也沒有自己的 Assembler (後來有 MC) 和 Linker 來建立完整編譯流程
  49. 49. LLVM Toolchain (Clang) Clang : C, C++, Objective-C 的編譯器前端  Apple 為了取代 GCC 重新打造的 Frontend  重寫一個前端代價是非常昂貴的  其實你是 慣C? 還是 慣GCC?  GNU/Linux 世界使用了 GCC 行之有年的非標準語法  Clang 設計成模組化 Frontend : Clang C API  可以 Export AST (Ex: RenderScript 用來產生 Java 的 Binding)  可以用來實作自動完成, Refactor Tool … etc  可以用來實作靜態程式碼分析工具 (Linting tool … etc)  Clang 改善了錯誤訊息 (Expressive diagnostics )  快速編譯, 低記憶使用量, 容易學習和Hack的 Frontend
  50. 50. 範例: Clang Expressive Diagnostics struct a { virtual int bar(); }; struct foo : public virtual a { }; void test(foo *P) { return P->bar() + *P; }g++-4.7xx.cc: In function void test(foo*):xx.cc:9:24: error: no match for operator+ in (((a*)P) + ((sizetype)(*(long int*)(P->foo::<anonymous>.a::_vptr.a + -32u))))->a::bar() + * Pxx.cc:9:24: error: return-statement with a value, in function returning void [-fpermissive]clang-3.1xx.cc:9:21: error: invalid operands to binary expression (int and foo) return P->bar() + *P; ~~~~~~~~ ^ ~~
  51. 51. Clang/LLVM Toolchain C Source CLANG Language LLVM BitcodeC++ Source Optimizer Binding Script .. etc AST Stream-out Clang Compiler Driver  盡可能和 GCC 相容, 遇到不認識的Option不會停下來  不需要 Cross Compiler, 本身就有 Cross Compiler 的能力 (?)  Cross Compiler != Cross Compiler Toolchian 來源: http://www.aosabook.org/en/llvm.html
  52. 52. 滅諸侯,成帝業,為天下一統LLVM 千秋萬世, 一統江湖 Q:挖賽, Clang + LLVM 那麼神, 其他人不是沒戲唱了嗎  A: 在這地球上還沒有人能統一天下, LLVM 當然也不行 Clang 之所以不用產生 Cross Compiler 的迷思  x86/64 clang 產生出來的LLVM Bitcode, 用 i686 的 llvm backend 來產生 x86 的機器碼 (-m32)  可以產生出來, 可是不會動 XD C/C++ 不是 Portable Language, 產生出來的 Bitcode 不 Portable 不是也是很正常的事嗎  LLVM Bitcode 本身就是 Portable (X)  使用 host triple 來改變產生出來的 LLVM Bitcode (O)
  53. 53. LLVM TableGen (Target Description) Instruction Encoding (For MC Assembler) Input/Output Assembly (For ASMPrinter)def ADDPS : PI<0x58, Instruction Selection Pattern (outs VR256:$dst), (For Selection DAG) (ins VR256:$src1, VR256:$src2), "addps $src2, $src1, $dst", [(set VR256:$dst, (fadd VR256:$src1, VR256:$src2))]>; 編譯器Backend 都有一些很無聊的地方, 用另外一 種語言來表示比直接寫 C/C++ 簡單好 maintain 的  GCC RTL Pattern : (MD, Machine Description file)  LLVM TableGen : (TD, Target Description file)
  54. 54. 完美Compiler進化論: LLVM的多變化Source 1 Frontend LLVM IR 1 LLVM Link IPOed executable/Source 2 Frontend LLVM IR 2 LLVM Optimizer Share object LLVM ARMSource 3 Frontend LLVM IR 3 Backend Compile Time Link TimeSource 1 Frontend LLVM IR 1 LLVM Link LLVM ARM BackendSource 2 Frontend LLVM IR 2 LLVM Optimizer Processor Specific executable/Source 3 Frontend LLVM IR 3 Share object Compile Time Link Time Load /Installation Time LLVM IR PGOed/ Runtime Opted LLVM Optimizer LLVM ARM Backend executable/ Share objectProfile Data Idle Time Load Time
  55. 55. LLVM 的發展 史記: 項羽本紀第七  太史公曰:吾聞之周生曰「舜目蓋重瞳子」,又聞項羽亦重瞳子。 羽豈其苗裔邪?何興之暴也!  LLVM 也有兩個 L, 加上一家可以掌握全局垂直整合的公司在後面力 挺, LLVM 也是銳不可擋 最美好的時代, 最壞得的時代  LLVM Bitcode 用來當傳遞格式還有很多問題  Binary Compatibility 最為人所詬病  http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon- 20120521/143197.html CASE STUDY: OpenCL SPIR  The OpenCL Khronos group proposes to extend LLVM to be the standard OpenCL IR (called SPIR)  http://www.khronos.org/registry/cl/specs/spir_spec-1.0-provisional.pdf  Khronos SPIR For OpenCL Brings Binary Compatibility  http://www.phoronix.com/scan.php?page=news_item&px=MTE4MzM
  56. 56. 相信你的編譯器 Linux-Kongress 2009: Source Code Optimization  http://www.linux-kongress.org/2009/slides/compiler_survey_ felix_von_leitner.pdf Q: x86 中把一個暫存器清成0  mov $0,%eax  and $0,%eax  sub %eax,%eax  xor %eax,%eax 哪道指令最好?
  57. 57. 相信你的編譯器: 解答 x86 的指令是可變長度的:  b8 00 00 00 00 mov $0,%eax  83 e0 00 and $0,%eax  29 c0 sub %eax,%eax  31 c0 xor %eax,%eax So, sub or xor? Turns out, both produce a false dependency on %eax. But CPUs know to ignore it for xor.
  58. 58. References http://www.redhat.com/magazine/002dec04/features/gcc/ http://gcc.gnu.org/onlinedocs/gcc http://en.wikipedia.org/wiki/Interprocedural_optimization http://en.wikipedia.org/wiki/Link-time_optimization http://llvm.org/ http://www.aosabook.org/en/llvm.html
  59. 59. Any Question ?

×