Goのssa.htmlの変更点まとめ2018〜

[Go2 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/go2) 20日目の記事です。
空きを見つけたので代筆させていただきます。

(2020/9/11に、Go1.15までの変更点を追記しました。)

# はじめに

Goコンパイラの中間表現として採用されているSSA(Static Single Assignment)の小ネタです。

SSA(静的単一代入)については[Wikipedia](https://ja.wikipedia.org/wiki/%E9%9D%99%E7%9A%84%E5%8D%98%E4%B8%80%E4%BB%A3%E5%85%A5)が詳しいのでご覧ください。

GoコンパイラにはSSA形式が最適化パスを通してどのように変化してくのかをHTMLファイル(`ssa.html`)にダンプする機能があります。この記事では`ssa.html`が2018年にどのように進化していったかをコミットログから追っていきます。

# `ssa.html`の作り方

```
$ env GOSSAFUNC=main go build
```

コンパイル時に環境変数`GOSSAFUNC`に関数名をセットすることで、`ssa.html`を生成できます。

後述しますが、2017年は`GOSSAFUNC`には単に関数名を指定するだけでしたが、2018年の変更で複雑な指定もできるようになりました。

# 変更点

では、以降でどのような変更があったかを見ていきます。変更は

* 現在の最新安定版(`Go11.4`)までに入っているもの
* まだ`master`(`go1.12beta1`)にしか入っていないもの

に分けて見ていきます。

変更点は、`ssa.html`を生成している[`cmd/compile/internal/ssa/html.go`のコミットログ](https://github.com/golang/go/commits/master/src/cmd/compile/internal/ssa/html.go)から調べました。

今回解析対象としたコードは以下のサンプルの`ssa`関数です。[Wikipediaの例](https://ja.wikipedia.org/wiki/%E9%9D%99%E7%9A%84%E5%8D%98%E4%B8%80%E4%BB%A3%E5%85%A5#SSA_%E3%81%B8%E3%81%AE%E5%A4%89%E6%8F%9B)を拝借しました。

```golang
package main

import "fmt"

func ssa() {
        var w, x, y, z int

        x = 5
        x = x - 3
        if x < 3 {
                y = x * 2
                w = y
        } else {
                y = x - 3
        }
        w = x - y
        z = x + y

        fmt.Printf("%d, %d\n", w, z)
}

func main() {
        ssa()
}
```


## 1.9.2〜1.11.4の変更点

昨年末の最新版`Go1.9.2`と現在の最新版`Go1.11.4`で`ssa.html`がどのくらい違うのか比べて見ましょう。

* [Go1.9.2のssa.html](https://tooru.github.io/gossahtml/html/ssa.go1.9.2.html)
* [Go1.11.4のssa.html](https://tooru.github.io/gossahtml/html/ssa.go1.11.4.html)

大きく違うのはいくつかの最適化パスが折りたたまれていることでしょうか。

では、順に見ていきます。


### Jul 28, 2017 (1.10beta1-) Goコードの変数名が出力されるように

[[dev.debug] cmd/compile: better DWARF with optimizations on](https://github.com/golang/go/commit/4c54a047c6ea88dd77416a3b878f6935165f6129#diff-b2d90156dd033e6f5810ff415a54dbf6)

SSA形式の変数名だけでは元のコードのどの変数だったのかが分かりづらかったのですが、この変更によって対応する変数が表示されるようになりました。
この変更自体は、最適化によって失われていた変数の位置情報をコンパイラオプション`-dwarflocationlists`によってデバッグ情報として付与できるようにした、
というものです。

`-dwarflocationlists`オプションについては以下に少し書いてあります
https://tip.golang.org/doc/diagnostics.html#debugging

### Aug 18, 2017 (1.10beta1-) (リファクタリングなのでスキップ)

[cmd/compile: rename SSA Register.Name to Register.String](https://github.com/golang/go/commit/bf4d8d3d055c47c03d8e0e05e8d07fd94f793e53#diff-b2d90156dd033e6f5810ff415a54dbf6)

### Oct 12, 2017 (1.10beta1-) 変数に対応する行数が表示されるように

[cmd/compile: add line numbers to values & blocks in ssa.html](https://github.com/golang/go/commit/edcf2d0cd604062cdd3b28d7e679b8b271ddc2ec#diff-b2d90156dd033e6f5810ff415a54dbf6)

元のコードの行数がSSAの変数の横に括弧書きされるようになりました。


### Apr 5, 2018 (go1.11beta1-) `IsStmt`によって行数の表示が変わるように

[cmd/compile: add IsStmt breakpoint info to src.lico](https://github.com/golang/go/commit/619679a3971fad8ff4aa231d7942c95579ceff23#diff-8cd6c5dd336a16009909e578d8b6fcb3R394)

```
Includes changes to html output for GOSSAFUNC to indicate
not-default is-a-statement with bold and not-a-statement
with strikethrough.
```

https://github.com/golang/go/commit/619679a3971fad8ff4aa231d7942c95579ceff23#diff-8cd6c5dd336a16009909e578d8b6fcb3R394

この変更時点では`IsStmt`マークは使われていませんが、現在は例えば以下の演算で行番号がストライクアウトされます。
https://github.com/golang/go/blob/release-branch.go1.11/src/cmd/compile/internal/ssa/numberlines.go#L62


### Jun 14, 2018 (go1.11beta1-) 最適化の各フェーズの列を折り畳めるように

[cmd/compile: use expandable columns in ssa.html](https://github.com/golang/go/commit/5eb98b3c3016c7dd10d71ee15bb6fc5d3128bec9#diff-b2d90156dd033e6f5810ff415a54dbf6)

デフォルトでは以下の名前で始まるパスが最初から広がっており([html.go#L297](https://github.com/golang/go/commit/5eb98b3c3016c7dd10d71ee15bb6fc5d3128bec9#diff-b2d90156dd033e6f5810ff415a54dbf6R297))、それ以外は折りたたまれるようになりました。パス名の辺りをクリックすることで畳んだり広げたりできます。

* `"start"`
* `"deadcode"`
* `"opt"`
* `"lower"`
* `"late deadcode"`
* `"regalloc"`
* `"genssa"`

### Jun 16, 2018 (go1.11beta1-) 選択した時の色の種類が増えました

[cmd/compile: add more color choices to ssa.html](https://github.com/golang/go/commit/b459e0045404d30dc14ea82d3b735f12b43df7d4#diff-b2d90156dd033e6f5810ff415a54dbf6)

ブロックや各行を選択するたびに別の色でハイライトされますが、この色が5色ほど増えました。

## 1.12以降の変更点

まだ`master`ブランチにしか入ってませんが、かなり変更が入っていますので紹介しておきます。全て[@ysmolsky](https://github.com/ysmolsky)さんによるものです。

Go1.11.4と最新リリースのGo1.12beta1で`ssa.html`がどのくらい違うのか比べて見ましょう。

* [Go1.11.4のssa.html](https://tooru.github.io/gossahtml/html/ssa.go1.11.4.html)
* [Go1.12beta1のssa.html](https://tooru.github.io/gossahtml/html/ssa.go1.12beta1.html)

ソースコードやAST、そしてCFG(Control Flow Graph)が追加されています。

では、1つずつ見ていきます。

### Aug 23, 2018 Goの元のソースコードがssa.htmlに含まれるように

[cmd/compile: display Go code for a function in ssa.html](https://github.com/golang/go/commit/8c0425825ced4042eac0439161abe1f22a47d615#diff-b2d90156dd033e6f5810ff415a54dbf6)

今まではSSA形式に変換されてからの変遷でしたが、元のソースコードと対応づけて表示できるようになりました。

### Aug 23, 2018 ssa.htmlの出力パスが標準出力に表示されるように

[cmd/compile: clean the output of GOSSAFUNC](https://github.com/golang/go/commit/c35069d6428d29b12088731aab35cbff1e504a28#diff-b2d90156dd033e6f5810ff415a54dbf6)

この変更は、`GOSSAFUNC`をつけたときに標準出力に表示される大量のデバッグプリントを抑制するためのものです。従来のようにデバッグプリントが必要な時は`GOSSAFUNC=Foo+`のように関数名の後ろに`+`をつければよいです。`ssa.html`の内容に変化はありませんが、`html.go`の中では`ssa.html`の出力パスを表示するよう変更になりました。

### Aug 23, 2018 ソースコードにインライン展開後のソースが追加

[cmd/compile: add sources for inlined functions to ssa.html](https://github.com/golang/go/commit/9e2a04d5ebe450defe3435d827ef07ca3c0eae3f#diff-b2d90156dd033e6f5810ff415a54dbf6)

https://github.com/golang/go/issues/25904

インライン展開された関数がソースコードの列に追加されるようになりました。

### Aug 25, 2018 ソースコードとSSAの間にASTの列が追加

[cmd/compile: display AST IR in ssa.html](https://github.com/golang/go/commit/4cc027fb55956c001ce486f48538835581bc5197#diff-b2d90156dd033e6f5810ff415a54dbf6)

https://github.com/golang/go/issues/26662

ソースコードとSSAの間にAST(Abstract Syntax Tree)の列が入りました。ソースコード⇔AST⇔SSA間も対応づけてハイライトされます。

### Sep 19, 2018 [bug fix] 

[cmd/compile/internal/ssa: fix `a == a` to `a == b`](https://github.com/golang/go/commit/9850ad045fced1346a049df4baec7d4b7ab0db8c#diff-b2d90156dd033e6f5810ff415a54dbf6)

Goのソースコードの列の関数の順序の計算が間違ってました。

### Oct 17, 2018 タブ幅を狭く

[cmd/compile: make tabs narrow in src column of ssa.html](https://github.com/golang/go/commit/c8b2ac68906a154c470a845172f133aceae7c5c7#diff-b2d90156dd033e6f5810ff415a54dbf6)

Goのソースコードのインデントのタブ幅を狭くしました。

### Oct 25, 2018 ヘッダの高さを控えめに

[cmd/compile: reduce the size of header in ssa.html](https://github.com/golang/go/commit/c8b2ac68906a154c470a845172f133aceae7c5c7#diff-b2d90156dd033e6f5810ff415a54dbf6)

関数名とヘルプで上部領域が埋まってたので調整したようです。
毎日見ていると、この高さが気になるのでしょう。

### Nov 21, 2018 各フェーズのCFGを表示できるように

[cmd/compile: add control flow graphs to ssa.html](https://github.com/golang/go/commit/3068fcfa0d6535d081a6fe3fb3dc8dd30bff370f#diff-b2d90156dd033e6f5810ff415a54dbf6)

大きめの機能が入りました。各フェーズにCFG(Control Flow Graph)を表示できるようになりました。コミットログにも書かれていますが、関数名の後ろに次の指定をすることでCFGが生成されます。

```
:*            - dump CFG for every phase
:lower        - just the lower phase
:lower-layout - lower through layout
:w,x-y        - phases w and x through y
```

サンプルはこちらでも確認できます。

https://github.com/golang/go/issues/28177

実行には、graphviz(`dot`コマンド)が必要です。SVG出力したものが`ssa.html`に埋め込まれています。SSAの各ブロックを選択するとそれ対応してCFGのノードがハイライトされます。反対にノードを選択すると対応するブロックが選択されます。

細かい話ですが、先ほど紹介した「Aug 23, 2018 ssa.htmlの出力パスが標準出力に表示されるように」で末尾に「+」を追加するとデバッグプリントが表示されるのは、この形式になっても有効です。

```
# 全フェーズでCFGを生成、デバッグプリントも表示
$ env GOSSAFUNC=ssa:*+ go build main.go
```


### Nov 22, 2018 ↑の手直し

[cmd/compile: fix TestFormats by using valid formats](https://github.com/golang/go/commit/8c5c2b71f4124eb5e72cde327d740a8dbdd4eeb8#diff-b2d90156dd033e6f5810ff415a54dbf6)

### Nov 24, 2018 ブロックが畳めるように

[cmd/compile: make ssa blocks collapsable in ssa.html](https://github.com/golang/go/commit/1ac84999b93876bb06887e483ae45b27e03d7423#diff-b2d90156dd033e6f5810ff415a54dbf6)

小さいですが各ブロックの右上に`-`ボタンが追加されました。押すとブロックを畳めます。

# まとめ

2018年に導入された`ssa.html`への変更点をまとめました。主に次の変更点がありました。

* 元のソースコードとの対応づけ強化
* CFG表示
* 最適化パスやブロックの折りたたみ
* 色数増加

go1.12がリリースされた際にはお試しください。

それでは良いお年を。

# 追記

2019年以降の変更点も気が向いた時に調べてまとめていきます。

## 2019年以降変更点

Go1.13/1.14では大きな変更点はありません。

### Feb 27, 2019 (go1.13beta1)

[all: fix typos as reported by 'misspell'](https://github.com/golang/go/commit/d090429ea9af7cc2958fd95460196b02212c2b62)
コメントのタイポの修正です。

### Oct 2, 2019 (go1.14beta1)

[cmd/compile: allow multiple SSA block control values](https://github.com/golang/go/commit/9c2e7e8bed3368fd2b3903b47d686b5a900ebe04)

block control value を複数指定できるようになりました。IBM S/390等のアーキテクチャでは、compare(比較)とbranch(分岐)を一度に行う命令があり、その対応のためにcontrol value (分岐に使われる値) を2つに拡張しました。

このコミットの後、次のようなコミットがされています。
[cmd/compile: add SSA rules for s390x compare-and-branch instructions](https://github.com/golang/go/commit/6ec4c71eef730d56169255515fea3490c8a32650)

ssa.htmlとしての変更点としてはあまりありませんが、S/390アーキテクチャ向けにビルドすると複数のcontrol valueが使われていることが分かります。

- [ssa.html / Go1.13 GOOS=linux GOARCH=s390x](https://tooru.github.io/gossahtml/html/ssa.go1.13-s390x.html) lower phase のLTにはv7とv8の比較結果であるv9を指定している
- [ssa.html / Go1.14 GOOS=linux GOARCH=s390x](https://tooru.github.io/gossahtml/html/ssa.go1.14-s390x.html) lower phase のCGRJには2つcontrol value(v7とv8)を指定している


## 2020年以降変更点

Go1.15では、ダークモード(黒背景)、フェーズ結合が導入されました。

### Mar 1, 2020 (go1.15beta1)

[cmd/compile: add a dark mode to ssa html generation which can be toggled](https://github.com/golang/go/commit/1e9665da8fd8e2e095eb0e99a3b83118f600dc0b)
ダークモード切替機能を追加しました。

https://github.com/golang/go/issues/34325
を受けての対応です。白い背景だと夜見るのが辛いそうです。それに対して、Rob Pikeが[コメント](https://github.com/golang/go/issues/34325#issuecomment-532018866)してました。

### Mar 11, 2020 (go1.15beta1)

[cmd/compile: improve CFG size in ssa.html](https://github.com/golang/go/commit/c6fef1fb52e9660ce2226a19508fdaacf71e46a9)

CFGのサイズを改良しました。Go1.14は左に寄ってましたが、Go1.15から左右に余白ができました。

### Mar 28, 2020 (go1.15beta1)

[cmd/compile: add dark mode functionality to CFGs in the ssa.html output](https://github.com/golang/go/commit/9131f08a23bd5923d135df15da30b322748ffa12)
CFGにもダークモード適用されて欲しいよねと。

### Apr 1, 2020 (go1.15beta1)

[cmd/compile: combine ssa.html columns with identical contents](https://github.com/golang/go/commit/afc480bab447c0fefe26a69e4221d93673021e98)
phaseが大量にあるのでどれが効いているのか分かり辛かったのですが、phaseに変化のない場合は列が結合される様になりました。

### Apr 6, 2020 (go1.15beta1)

[cmd/compile: refactor around HTMLWriter removing logger in favor of Func](https://github.com/golang/go/commit/6736b2fdb22a8b83c4e29d7f7d3f11080a8af328)
リファクタリングです。

### Apr 6, 2020 (go1.15beta1)

[cmd/compile: restore missing columns in ssa.html](https://github.com/golang/go/commit/763bd58b19a3aea9760cb8c8326dabf78653db68)
最後のカラム(phase)だけ結合できていなかったので直しました。

### Apr 6, 2020 (go1.15beta1)

[cmd/compile: print block auxint value in HTML output](https://github.com/golang/go/commit/a4451e11437c2375c7451d90aac5419903629b16)
https://github.com/golang/go/issues/38250

[cmd/compile: allow multiple SSA block control values](https://github.com/golang/go/commit/9c2e7e8bed3368fd2b3903b47d686b5a900ebe04)で対応した、control valueに即値が指定された場合、表示される様になりました。

### Apr 24, 2020 (go1.15beta1)

[cmd/compile: fix misalignment in sources column of generated ssa.html](https://github.com/golang/go/commit/d0ea533c54092e034ab474691df56f8da05ed0d5)
一番左の列のsourceの行番号の位置がコードとずれていたので直しました。

# ssa.htmlの変遷

各バージョンでの変更点をまとめます。各バージョンのリンクはそのバージョンのssa.htmlのサンプルです。

|Go Version|主な変更点|
|:--|:--|
|[Go1.9.2](https://tooru.github.io/gossahtml/html/ssa.go1.9.2.html)|-|
|[Go1.11.4](https://tooru.github.io/gossahtml/html/ssa.go1.11.4.html)|変数名表示、Phase折り畳み、色数増加|
|[Go1.12beta1](https://tooru.github.io/gossahtml/html/ssa.go1.12beta1.html)|Goのソース(インライン展開含む)、AST列追加、CFG(Control Flw Graph)追加|
|Go1.13|変更なし|
|[Go1.14](https://tooru.github.io/gossahtml/html/ssa.go1.14.html)|compare-and-branch対応|
|[Go1.15](https://tooru.github.io/gossahtml/html/ssa.go1.15.html)|ダークモード(黒背景)導入、変化のないPhase(列)は結合|


# 変更履歴

|日付|変更点|
|:---------|:--|
|2018/12/20|初版、Go1.12までの変更点をまとめ|
|2020/09/11|Go1.15までの変更点を追記|