[WebKit] JavaScriptCore解析--高階篇(一) SSA (static single assignment)
在編譯器優化領域,資料結構的選擇會直接影響程式優化的有效性。SSA是一種編譯器使用的中間語言(intermediate language), 作為編譯優化的基礎(也是DFG JIT的基礎),它和Control Dependence Graph一起被用來表示程式的資料流和控制流。
大家都知道編譯器是這樣工作的:解析、優化,最後生成程式碼。中間會使用到一箇中間語言的進行過度,好的中間語言一定要
1. 簡單,這樣優化工作就可以變得簡單。
2. 很好的表達能力,這樣就可以很容易從原始碼中生成出來。
3. 實效性(utilitarian), 它的結構可以讓你做到很多的優化。
SSA簡介
如何為迴圈生成有效的機器程式碼是編譯優化領域中一個關鍵的問題。要處理很多的控制流操作,都被集中到了一階的控制流問題, 也就是一個直線型的程式碼(Straight-line code)。SSA中的變數是不會變化的,他們只會被指定一次。向一個變數賦個新值,都會導致一個新的繫結。
比如下面的函式:
function clamp (x, lower, upper) {
if (x < lower)
x = lower;
else if (x > upper)
x = upper;
return x;
}
SSA的轉換結果為:
entry:
x0, lower0, upper0 = args;
goto b0;
b0:
t0 = x0 < lower0;
goto t0 ? b1 : b2;
b1:
x1 = lower0;
goto exit;
b2:
t1 = x0 > upper0;
goto t1 ? b3 : exit;
b3:
x2 = upper0;
goto exit;
exit:
x4 = phi(x0, x1, x2);
return x4;
SSA把過程區分出若干個基本塊(basic blocks),每塊在結尾或有條件,也或者無條件地轉向其它分支。臨時變數也有自己的命名,以便進行後期優化。
phi函式(phi functions)
SSA還有一個有趣的"phi" 函式,它被放置在控制流交匯點(control-flow joins). 上面的例子裡,x可能來自引數,也可能在兩個條件語句中被賦值,這時就有phi函式來表示它。第一個基本塊(basic blocks)都可以認為是一個函式,而phi函式就是帶有一個引數的基本塊。
就像這樣:
上面的phi函式表示在一個分支的交匯點後,後續對V的呼叫,就變為對V3的呼叫。這樣做就可以方便地引入進一步的優化,比如Copy Propagation。
為了正確放置phi函式,你需要建立一個dominator tree. 如果所有的控制路徑必須經過第一個,才能到達第二個,我們稱這個基本塊支配(dominate)另一個。比如入口的基本塊就支配整個函式。上面的例子裡,b0也支配其它塊。而b1沒有跳轉到exit, 所以它就沒有支配exit, 因為exit可能會從路徑到達。
這是個比較生僻的內容,主要來自學習和翻譯以下兩篇資料:
因為能力有限,一定會有理解錯誤的地方,歡迎指正。
系列索引: