1. 程式人生 > >GNU編譯優化級別-O -O1 -O2 -O3

GNU編譯優化級別-O -O1 -O2 -O3

轉自:https://blog.csdn.net/hemmingway/article/details/51470486
最近做一個演算法的GPU加速,發現實際上使用gcc的-O3(最高階編譯優化)選項,可以獲得很高的加速比,我的程式裡達到了3倍的樣子,有時效果甚至比GPU加速好。因此小小學習了下GNU的編譯優化。
附言一句,在進行除錯的時候,最好關閉編譯優化,不然程式自動優化,執行的步驟可能稍有變化。

GNU編譯器提供-O選項供程式優化使用:
-O 提供基礎級別的優化
-O2 提供更加高階的程式碼優化,會佔用更長的編譯時間
-O3 提供最高階的程式碼優化
不同的優化級別使用的優化技術也可以單獨的應用於程式碼。 可以使用-f命令列選項引用每個
單獨的優化技術。

1, 編譯器優化級別1
在優化的第一個級別執行基礎程式碼的優化。 這個級別試圖執行9種單獨的優化功能:
-fdefer-pop: 這種優化技術與組合語言程式碼在函式完成時如何進行操作有關。 一般
情況下, 函式的輸入值被儲存在堆疊中並且被函式訪問。 函式返回時, 輸入值還在
堆疊中。 一般情況下, 函式返回之後, 輸入值被立即彈出堆疊。這樣做會使堆疊中
的內容有些雜亂。

-fmerge-constans: 使用這種優化技術, 編譯器試圖合併相同的常量. 這一特性有
時候會導致很長的編譯時間, 因為編譯器必須分析c或者c++程式中用到的每個常量,
並且相互比較他們.

-fthread-jumps: 使用這種優化技術與編譯器如果處理彙編程式碼中的條件和非條件
分支有關。 在某些情況下, 一條跳轉指令可能轉移到另一條分支語句。 通過一連串
跳轉, 編譯器確定多個跳轉之間的最終目標並且把第一個跳轉重新定向到最終目標。

-floop-optimize: 通過優化如何生成組合語言中的迴圈, 編譯器可以在很大程式上
提高應用程式的效能。 通常, 程式由很多大型且複雜的迴圈構成。 通過刪除在迴圈
內沒有改變值的變數賦值操作, 可以減少迴圈內執行指令的數量, 在很大程度上提高
效能。 此外優化那些確定何時離開迴圈的條件分支, 以便減少分支的影響。

-fif-conversion: if-then語句應該是應用程式中僅次於迴圈的最消耗時間的部分。
簡單的if-then語句可能在最終的組合語言程式碼中產生眾多的條件分支。 通過減少
或者刪除條件分支, 以及使用條件傳送 設定標誌和使用運算技巧來替換他們, 編譯
器可以減少if-then語句中花費的時間量。

-fif-conversion2: 這種技術結合更加高階的數學特性, 減少實現if-then語句所
需的條件分支。

-fdelayed-branch: 這種技術試圖根據指令週期時間重新安排指令。 它還試圖把
儘可能多的指令移動到條件分支前, 以便最充分的利用處理器的治理快取。

-fguess-branch-probability: 就像其名稱所暗示的, 這種技術試圖確定條件分支最可
能的結果, 並且相應的移動指令, 這和延遲分支技術類似。 因為在編譯時預測程式碼的安排,
所以使用這一選項兩次編譯相同的c或者c++程式碼很可能會產生不同的組合語言程式碼, 這取決
於編譯時編譯器認為會使用那些分支。 因為這個原因, 很多程式設計師不喜歡採用這個特性, 並且
專門地使用-fno-guess-branch-probability選項關閉這個特性

-fcprop-registers: 因為在函式中把暫存器分配給變數, 所以編譯器執行第二次檢查以便減少
排程依賴性(兩個段要求使用相同的暫存器)並且刪除不必要的暫存器複製操作。

2, 編譯器優化級別2
結合了第一個級別的所有優化技術, 再加上一下一些優化:
-fforce-mem: 這種優化再任何指令使用變數前, 強制把存放再記憶體位置中的所有變數都複製到暫存器
中。 對於只涉及單一指令的變數, 這樣也許不會有很大的優化效果. 但是對於再很多指令(必須數學操作)
中都涉及到的變數來說, 這會時很顯著的優化, 因為和訪問記憶體中的值相比 ,處理器訪問暫存器中的值要
快的多。

-foptimize-sibling-calls: 這種技術處理相關的和/或者遞迴的函式呼叫。 通常, 遞迴的函式呼叫
可以被展開為一系列一般的指令, 而不是使用分支。 這樣處理器的指令快取能夠載入展開的指令並且
處理他們, 和指令保持為需要分支操作的單獨函式呼叫相比, 這樣更快。

-fstrength-reduce: 這種優化技術對迴圈執行優化並且刪除迭代變數。 迭代變數是捆綁到迴圈計數器
的變數, 比如使用變數, 然後使用迴圈計數器變數執行數學操作的for-next迴圈。

-fgcse: 這種技術對生成的所有組合語言程式碼執行全域性通用表示式消除歷程。 這些優化操作試圖分析
生成的組合語言程式碼並且結合通用片段, 消除冗餘的程式碼段。如果程式碼使用計算性的goto, gcc指令推薦
使用-fno-gcse選項。

-fcse-follow-jumps: 這種特別的通用子表示式消除技術掃描跳轉指令, 查詢程式中通過任何其他途徑都不
會到達的目的碼。 這種情況最常見的例子就式if-then-else語句的else部分。

-frerun-cse-after-loop: 這種技術在對任何迴圈已經進行過優化之後重新執行通用子表示式消除例程。
這樣確保在展開迴圈程式碼之後更進一步地優化還編程式碼。

-fdelete-null-pointer-checks: 這種優化技術掃描生成的組合語言程式碼, 查詢檢查空指標的程式碼。編譯
器假設間接引用空指標將停止程式。 如果在間接引用之後檢查指標, 它就不可能為空。

-fextensive-optimizations: 這種技術執行從編譯時的角度來說代價高昂的各種優化技術,但是它可能
對執行時的效能產生負面影響。

-fregmove: 編譯器試圖重新分配mov指令中使用的暫存器, 並且將其作為其他指令運算元, 以便最大化
捆綁的暫存器的數量。

-fschedule-insns: 編譯器將試圖重新安排指令, 以便消除等待資料的處理器。 對於在進行浮點運算時有
延遲的處理器來說, 這使處理器在等待浮點結果時可以載入其他指令。

-fsched-interblock: 這種技術使編譯器能夠跨越指令塊排程指令。 這可以非常靈活地移動指令以便等待
期間完成的工作最大化。

-fcaller-saves: 這個選項指示編譯器對函式呼叫儲存和恢復暫存器, 使函式能夠訪問暫存器值, 而且不必
儲存和恢復他們。 如果呼叫多個函式, 這樣能夠節省時間, 因為只進行一次暫存器的儲存和恢復操作, 而
不是在每個函式呼叫中都進行。

-fpeephole2: 這個選項允許進行任何計算機特定的觀察孔優化。

-freorder-blocks: 這種優化技術允許重新安排指令塊以便改進分支操作和程式碼區域性性。

-fstrict-aliasing: 這種技術強制實行高階語言的嚴格變數規則。 對於c和c++程式來說, 它確保不在資料
型別之間共享變數. 例如, 整數變數不和單精度浮點變數使用相同的記憶體位置。

-funit-at-a-time: 這種優化技術指示編譯器在執行優化例程之前讀取整個組合語言程式碼。 這使編譯器可以
重新安排不消耗大量時間的程式碼以便優化指令快取。 但是, 這會在編譯時花費相當多的記憶體, 對於小型計算機可能
是一個問題。

-falign-functions: 這個選項用於使函式對準記憶體中特定邊界的開始位置。大多數處理器按照頁面讀取記憶體,
並且確保全部函式程式碼位於單一記憶體頁面內, 就不需要叫化程式碼所需的頁面。

-fcrossjumping: 這是對跨越跳轉的轉換程式碼處理, 以便組合分散在程式各處的相同程式碼。 這樣可以減少
程式碼的長度, 但是也許不會對程式效能有直接影響。

3, 編譯器優化級別3
它整合了第一和第二級別中的左右優化技巧, 還包括一下優化:
-finline-functions: 這種優化技術不為函式建立單獨的組合語言程式碼,而是把函式程式碼包含在排程程式的
程式碼中。 對於多次被呼叫的函式來說, 為每次函式呼叫複製函式程式碼。 雖然這樣對於減少程式碼長度不利, 但是
通過最充分的利用指令快取程式碼, 而不是在每次函式呼叫時進行分支操作, 可以提高效能。

-fweb: 構建用於儲存變數的偽暫存器網路。 偽暫存器包含資料, 就像他們是暫存器一樣, 但是可以使用各種
其他優化技術進行優化, 比如cse和loop優化技術。