gcc優化選項-o

gcc優化選項-o

gcc編譯優化

gcc 提供了爲了滿足用戶不同程度的的優化需要,提供了近百種優化選項,用來對{編譯時間,目標文件長度,執行效率}這個三維模型進行不同的取捨和平衡。優化的方法不一而足,總體上將有以下幾類:

  • 精簡操作指令;
  • 儘量滿足cpu的流水操作;
  • 通過對程序行爲地猜測,重新調整代碼的執行順序;
  • 充分使用寄存器;
  • 對簡單的調用進行展開
    gcc提供了-o0到-o3的優化等級,可以方便我們使用

-o0

不錯任何優化

-o1

對程序做部分編譯優化,對於大函數,優化編譯佔用稍微多的時間和相當大的內存。使用本項優化,編譯器會嘗試減小生成代碼的尺寸,以及縮短執行時間,但並不執行需要佔用大量編譯時間的優化。

打開的優化選項

  • l -fdefer-pop:延遲棧的彈出時間。當完成一個函數調用,參數並不馬上從棧中彈出,而是在多個函數被調用後,一次性彈出。
  • l -fmerge-constants:嘗試橫跨編譯單元合併同樣的常量(string constants and floating point constants)
  • l -fthread-jumps:如果某個跳轉分支的目的地存在另一個條件比較,而且該條件比較包含在前一個比較語句之內,那麼執行本項優化.根據條件是true或者false,前面那條分支重定向到第二條分支的目的地或者緊跟在第二條分支後面.
  • l -floop-optimize:執行循環優化,將常量表達式從循環中移除,簡化判斷循環的條件,並且optionally do strength-reduction,或者將循環打開等。在大型複雜的循環中,這種優化比較顯著。
  • l -fif-conversion:嘗試將條件跳轉轉換爲等價的無分支型式。優化實現方式包括條件移動,min,max,設置標誌,以及abs指令,以及一些算術技巧等。
  • l -fdelayed-branch:這種技術試圖根據指令週期時間重新安排指令。 它還試圖把儘可能多的指令移動到條件分支前, 以便最充分的利用處理器的治理緩存。
  • l -fguess-branch-probability:當沒有可用的profiling feedback或__builtin_expect時,編譯器採用隨機模式猜測分支被執行的可能性,並移動對應彙編代碼的位置,這有可能導致不同的編譯器會編譯出迥然不同的目標代碼。
  • l -fcprop-registers:因爲在函數中把寄存器分配給變量, 所以編譯器執行第二次檢查以便減少調度依賴性(兩個段要求使用相同的寄存器)並且刪除不必要的寄存器複製操作。

-o2

比O1更高級的選項,進行更多的優化。Gcc將執行幾乎所有的不包含時間和空間折中的優化。當設置O2選項時,編譯器並不進行循環打開()loop unrolling以及函數內聯。與O1比較而言,O2優化增加了編譯時間的基礎上,提高了生成代碼的執行效率。

優化選項

  • l -fforce-mem:在做算術操作前,強制將內存數據copy到寄存器中以後再執行。這會使所有的內存引用潛在的共同表達式,進而產出更高效的代碼,當沒有共同的子表達式時,指令合併將排出個別的寄存器載入。這種優化對於只涉及單一指令的變量, 這樣也許不會有很大的優化效果. 但是對於再很多指令(必須數學操作)中都涉及到的變量來說, 這會時很顯著的優化, 因爲和訪問內存中的值相比 ,處理器訪問寄存器中的值要快的多。
  • l -foptimize-sibling-calls:優化相關的以及末尾遞歸的調用。通常, 遞歸的函數調用可以被展開爲一系列一般的指令, 而不是使用分支。 這樣處理器的指令緩存能夠加載展開的指令並且處理他們, 和指令保持爲需要分支操作的單獨函數調用相比, 這樣更快。
  • l -fstrength-reduce:這種優化技術對循環執行優化並且刪除迭代變量。 迭代變量是捆綁到循環計數器的變量, 比如使用變量, 然後使用循環計數器變量執行數學操作的for-next循環。
  • l -fcse-follow-jumps:在公用子表達式消元時,當目標跳轉不會被其他路徑可達,則掃描整個的跳轉表達式。例如,當公用子表達式消元時遇到if…else…語句時,當條爲false時,那麼公用子表達式消元會跟隨着跳轉。
  • l -fcse-skip-blocks:與-fcse-follow-jumps類似,不同的是,根據特定條件,跟隨着cse跳轉的會是整個的blocks
  • l -frerun-cse-after-loop:在循環優化完成後,重新進行公用子表達式消元操作。
  • l -frerun-loop-opt:兩次運行循環優化 l -fgcse:執行全局公用子表達式消除pass。這個pass還執行全局常量和copy propagation。這些優化操作試圖分析生成的彙編語言代碼並且結合通用片段, 消除冗餘的代碼段。如果代碼使用計算性的goto, gcc指令推薦使用-fno-gcse選項。
  • l-fgcse-lm:全局公用子表達式消除將試圖移動那些僅僅被自身存儲kill的裝載操作的位置。這將允許將循環內的load/store操作序列中的load轉移到循環的外面(只需要裝載一次),而在循環內改變成copy/store序列。在選中-fgcse後,默認打開。
  • l -fgcse-sm:當一個存儲操作pass在一個全局公用子表達式消除的後面,這個pass將試圖將store操作轉移到循環外面去。如果與-fgcse-lm配合使用,那麼load/store操作將會轉變爲在循環前load,在循環後store,從而提高運行效率,減少不必要的操作。
  • l -fgcse-las:全局公用子表達式消除pass將消除在store後面的不必要的load操作,這些load與store通常是同一塊存儲單元(全部或局部)
  • l-fdelete-null-pointer-checks:通過對全局數據流的分析,識別並排出無用的對空指針的檢查。編譯器假設間接引用空指針將停止程序。 如果在間接引用之後檢查指針,它就不可能爲空。
  • l -fexpensive-optimizations:進行一些從編譯的角度來說代價高昂的優化(這種優化據說對於程序執行未必有很大的好處,甚至有可能降低執行效率,具體不是很清楚)
  • l -fregmove:編譯器試圖重新分配move指令或者其他類似操作數等簡單指令的寄存器數目,以便最大化的捆綁寄存器的數目。這種優化尤其對雙操作數指令的機器幫助較大。
  • l -fschedule-insns:編譯器嘗試重新排列指令,用以消除由於等待未準備好的數據而產生的延遲。這種優化將對慢浮點運算的機器以及需要load memory的指令的執行有所幫助,因爲此時允許其他指令執行,直到load memory的指令完成,或浮點運算的指令再次需要cpu。
  • I-fschedule-insns2:與-fschedule-insns相似。但是當寄存器分配完成後,會請求一個附加的指令計劃pass。這種優化對寄存器較小,並且load memory操作時間大於一個時鐘週期的機器有非常好的效果。
  • l -fsched-interblock:這種技術使編譯器能夠跨越指令塊調度指令。 這可以非常靈活地移動指令以便等待期間完成的工作最大化。
  • l -fsched-spec-load:允許一些load指令進行一些投機性的動作。(具體不詳)相同功能的還有-fsched-spec-load-dangerous,允許更多的load指令進行投機性操作。這兩個選項在選中-fschedule-insns時默認打開。
  • l -fcaller-saves:通過存儲和恢復call調用周圍寄存器的方式,使被call調用的value可以被分配給寄存器,這種只會在看上去能產生更好的代碼的時候才被使用。(如果調用多個函數, 這樣能夠節省時間, 因爲只進行一次寄存器的保存和恢復操作, 而不是在每個函數調用中都進行。)
  • l -fpeephole2:允許計算機進行特定的觀察孔優化(這個不曉得是什麼意思),-fpeephole與-fpeephole2的差別在於不同的編譯器採用不同的方式,由的採用-fpeephole,有的採用-fpeephole2,也有兩種都採用的。
  • l -freorder-blocks:在編譯函數的時候重新安排基本的塊,目的在於減少分支的個數,提高代碼的局部性。
  • l -freorder-functions:在編譯函數的時候重新安排基本的塊,目的在於減少分支的個數,提高代碼的局部性。這種優化的實施依賴特定的已存在的信息:.text.hot用於告知訪問頻率較高的函數,.text.unlikely用於告知基本不被執行的函數。
  • l -fstrict-aliasing:這種技術強制實行高級語言的嚴格變量規則。 對於c和c++程序來說, 它確保不在數據類型之間共享變量. 例如, 整數變量不和單精度浮點變量使用相同的內存位置。
  • l -funit-at-a-time:在代碼生成前,先分析整個的彙編語言代碼。這將使一些額外的優化得以執行,但是在編譯器間需要消耗大量的內存。(有資料介紹說:這使編譯器可以重新安排不消耗大量時間的代碼以便優化指令緩存。)
  • l -falign-functions:這個選項用於使函數對準內存中特定邊界的開始位置。 大多數處理器按照頁面讀取內存,並且確保全部函數代碼位於單一內存頁面內, 就不需要叫化代碼所需的頁面。
  • l -falign-jumps:對齊分支代碼到2的n次方邊界。在這種情況下,無需執行傀儡指令(dummy operations)
  • l -falign-loops:對齊循環到2的n次冪邊界。期望可以對循環執行多次,用以補償運行dummy operations所花費的時間。
  • l -falign-labels:對齊分支到2的n次冪邊界。這種選項容易使代碼速度變慢,原因是需要插入一些dummy operations當分支抵達usual flow of the code.
  • l -fcrossjumping:這是對跨越跳轉的轉換代碼處理, 以便組合分散在程序各處的相同代碼。 這樣可以減少代碼的長度, 但是也許不會對程序性能有直接影響。

-o3

比O2更進一步的進行優化。

  • l -finline-functions:內聯簡單的函數到被調用函數中。由編譯器啓發式的決定哪些函數足夠簡單可以做這種內聯優化。默認情況下,編譯器限制內聯的尺寸,3.4.6中限制爲600(具體含義不詳,指令條數或代碼size?)可以通過-finline-limit=n改變這個長度。這種優化技術不爲函數創建單獨的彙編語言代碼, 而是把函數代碼包含在調度程序的代碼中。 對於多次被調用的函數來說, 爲每次函數調用複製函數代碼。 雖然這樣對於減少代碼長度不利, 但是通過最充分的利用指令緩存代碼, 而不是在每次函數調用時進行分支操作, 可以提高性能。
  • l -fweb:構建用於保存變量的僞寄存器網絡。 僞寄存器包含數據, 就像他們是寄存器一樣, 但是可以使用各種其他優化技術進行優化, 比如cse和loop優化技術。這種優化會使得調試變得更加的不可能,因爲變量不再存放於原本的寄存器中。
  • l -frename-registers:在寄存器分配後,通過使用registers left over來避免預定代碼中的虛假依賴。這會使調試變得非常困難,因爲變量不再存放於原本的寄存器中了。
  • l -funswitch-loops:將無變化的條件分支移出循環,取而代之的將結果副本放入循環中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章