編譯器與程式碼產生

靜態單一指派形式(static single assignment,SSA)

/ SSA /

想像你做筆記時永遠不准劃掉重寫一個值——如果某個量改變了,你必須給它一個新名字。所以不是「x = 5 …… 後來 x = 9」,而是寫「x1 = 5 …… x2 = 9」。看似迂腐,但它讓一件事變得極簡單:你看到的任何名字都恰好在一個地方被設定。靜態單一指派形式(SSA)就是一種精確遵守這條規則的 IR。

在 SSA 中,每個變數恰好被指派一次,是「靜態」上的一次——也就是整個函式中只有一個指令定義某個名字。當原始程式重新指派一個變數時,編譯器就改名:x 在每次新指派時變成 x1、x2、x3。「靜態」很重要:迴圈內的一個定義即使執行很多次,仍只有一個文字上的定義點。這讓每次對某值的使用都有明確的、唯一的來源。唯一的麻煩是流程控制:當兩條不同路徑各自定義了一個版本的 x、然後匯流時,哪個版本在範圍內?SSA 用一個特殊的 phi 節點來回答,依走過的路徑挑出正確的傳入版本。

它重要在於:單一指派形式讓資料流分析大幅簡化。要問「是什麼產生了這個值?」編譯器只需跟著一條連結,而不必搜尋所有先前的指派;這讓常數傳播、死碼消除、共同子運算式消除更乾淨也更快。SSA 是 LLVM 與大多數現代最佳化器的骨幹 IR。一個提醒:SSA 是內部形式,不是任何原始語言的特性——它由編譯器建構,並在暫存器配置前被拆解(離開 SSA),因為真實暫存器確實會被重新指派。

// 原本: // SSA 形式(每次指派都改名): x = 1; x1 = 1 x = x + 4; x2 = x1 + 4 y = x * 2; y1 = x2 * 2

每個名字只定義一次。任何使用(如 x2)都精確指回一個定義——沒有歧義。

SSA 是編譯器內部形式,不是原始語言的規則:編譯器建立它、在其中最佳化,然後在暫存器配置前離開它(de-SSA),因為實體暫存器在執行期確實會被重新指派。

又称
SSASSA form靜態單賦值形式