llvm 一個簡單函式的優化
阿新 • • 發佈:2022-04-13
LLVM優化一個簡單函式
一個優化的、領先的編譯器通常被組織為:
early common subexpression elimination
接下來是“早期公共子表示式消除”(CSE)。CSE嘗試消除人們編寫的程式碼和部分優化的程式碼中出現的冗餘子計算。“早期CSE”是快速的,一種查詢平凡冗餘計算的簡單CSE。SSA形式後,每個SSA的
值是不會被更改的,僅被賦值一次。所以相同的表示式的指令是可以合併的。如下圖的%10,%17。可以用10%代替所有的%17.
指令合併 :instruction combiner
主要執行一組多種多樣的“窺孔優化”,它們(通常)將一組由資料流連線的指令重寫為更高效的形式。InstCombine將不改變函式的控制流。 在本例中沒有優化的空間。
舉例 a = b +1 ; a = a - 1; ==> a = b;
這裡不是從%1減去1來計算%4,我們決定加上-1。這是一個規範化而不是優化。當有多種方式表示一個計算時,LLVM嘗試規範化到一個形式(通常任意選擇),這個形式是LLVM-PASS與後端期望看到的。由InstCombine進行的第二個改變是將計算%7與%11的兩個符號擴充套件操作規範化為零擴充套件(zext)。在編譯器可以證明sext的運算元是非負時,這是一個安全的或轉換。這裡就是這個情形,因為迴圈歸納變數從零開始,在到達n之前停止(如果n是負的,迴圈永遠不會執行)。最後的改變是向產生%10的指令新增“nuw”(沒有無符號迴繞)標記。我們可以看到這是安全,通過觀察到(1)歸納變數總是遞增的,(2)如果一個變數從零開始且遞增,在到達僅次於UINT_MAX的無符號迴繞邊界前,穿過僅次於INT_MAX的有符號迴繞邊界,它將變成未定義的。這個標記可用於證明後續優化的合理性。
再一次simplifyCFG,刪除了兩個無用的塊。
翻轉迴圈
initializer
if (condition)
goto BODY
else
goto EXIT
BODY:
body
modifier
if (condition)
goto BODY
else
goto EXIT
EXIT:
因為現在,與原始迴圈相比,翻轉迴圈後少一個分支。,但旋轉迴圈還提供了其他優化機會。如果我們可以證明第一個條件始終為真,從而始終執行迴圈,我們可以重用迴圈中定義的值,而無需迴圈退出節點中的 phi
global value numbering 全域性值編號,重用全域性變數。左邊迴圈裡的兩個load對應a[i]與a[i+1]。這裡GVN斷定載入a[i]是不必要的,因為來自一次迴圈迭代的a[i+1]可以轉發到下一次迭代作為a[i]。這個簡單的技巧將這個函式load指令減半。LLVM與GCC都是最近得到這個轉換的
https://blog.regehr.org/archives/1603
- 一個將原始碼翻譯為一箇中間表示(IR)的前端。
- 一個目標無關的優化流水線:一系列,它們持續重寫IR,以消除低效性以及不能容易翻譯為機器碼的形式。有時稱之為“中端(middle end)”。
- 一個目標相關的後端,生成彙編程式碼或機器碼。
- 刪除沒有前驅的基本塊。
- 如果僅有一個前驅且該前驅僅有一個後繼,將基本塊與且前驅合併。
- 消除只有一個前驅的基本塊的PHI節點。
- 消除僅包含無條件分支的基本塊。
- 將invoke指令改為呼叫nounwind函式。
- 把形如“if (x) if (y)”的情形改為“if (x&y)”