TL;DR

コンパイラの中間表現の形式の 1 つで、各変数への代入が一度だけになるように書き換えたもの。最適化を簡単にするために使う。

なぜ必要か

Wikipedia によると、変数ごとに定義が 1 つしかないので、ある変数の値がどの代入から来たか(use-def 連鎖)がすぐに分かる。そのため、定数畳み込み、デッドコード削除、大域値番号付け、レジスタ割り当てなどの最適化が簡単になり、結果もよくなる。

仕組み

元の変数を、代入ごとに添え字を付けた「バージョン」に分ける。制御フローが合流する箇所では、どの経路から来た定義を使うかを選ぶ Φ 関数を置く。Φ 関数は実際の命令ではなく、合流するそれぞれの値を同じ場所に置くようコンパイラに指示する目印である。Φ 関数をどこに置くかは、支配辺境(dominance frontier)の考え方で求める。SSA は直接実行するのに向かないので、最適化の後で元の形に戻す。

基本的な考え方は 1980 年代に IBM の Cytron らが確立した。GCC 4 や LLVM、Java HotSpot VM などが採用している。

例

次のコードでは、x に入るのが 2 回目の代入の値だと、読み手が追わないと分からない。

y := 1
y := 2
x := y

SSA 形式にすると、x1 が y2 を使うことがすぐに分かる。

y1 := 1
y2 := 2
x1 := y2

関連

出典