Go2 Advent Calendar 2018 20日目の記事です。
空きを見つけたので代筆させていただきます。
(2020/9/11に、Go1.15までの変更点を追記しました。)
はじめに
Goコンパイラの中間表現として採用されているSSA(Static Single Assignment)の小ネタです。
SSA(静的単一代入)についてはWikipediaが詳しいのでご覧ください。
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
のコミットログから調べました。
今回解析対象としたコードは以下のサンプルのssa
関数です。Wikipediaの例を拝借しました。
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
がどのくらい違うのか比べて見ましょう。
大きく違うのはいくつかの最適化パスが折りたたまれていることでしょうか。
では、順に見ていきます。
Jul 28, 2017 (1.10beta1-) Goコードの変数名が出力されるように
[dev.debug] cmd/compile: better DWARF with optimizations on
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
Oct 12, 2017 (1.10beta1-) 変数に対応する行数が表示されるように
cmd/compile: add line numbers to values & blocks in ssa.html
元のコードの行数がSSAの変数の横に括弧書きされるようになりました。
Apr 5, 2018 (go1.11beta1-) IsStmt
によって行数の表示が変わるように
cmd/compile: add IsStmt breakpoint info to src.lico
Includes changes to html output for GOSSAFUNC to indicate
not-default is-a-statement with bold and not-a-statement
with strikethrough.
この変更時点では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
デフォルトでは以下の名前で始まるパスが最初から広がっており(html.go#L297)、それ以外は折りたたまれるようになりました。パス名の辺りをクリックすることで畳んだり広げたりできます。
"start"
"deadcode"
"opt"
"lower"
"late deadcode"
"regalloc"
"genssa"
Jun 16, 2018 (go1.11beta1-) 選択した時の色の種類が増えました
cmd/compile: add more color choices to ssa.html
ブロックや各行を選択するたびに別の色でハイライトされますが、この色が5色ほど増えました。
1.12以降の変更点
まだmaster
ブランチにしか入ってませんが、かなり変更が入っていますので紹介しておきます。全て@ysmolskyさんによるものです。
Go1.11.4と最新リリースのGo1.12beta1でssa.html
がどのくらい違うのか比べて見ましょう。
ソースコードやAST、そしてCFG(Control Flow Graph)が追加されています。
では、1つずつ見ていきます。
Aug 23, 2018 Goの元のソースコードがssa.htmlに含まれるように
cmd/compile: display Go code for a function in ssa.html
今まではSSA形式に変換されてからの変遷でしたが、元のソースコードと対応づけて表示できるようになりました。
Aug 23, 2018 ssa.htmlの出力パスが標準出力に表示されるように
cmd/compile: clean the output of GOSSAFUNC
この変更は、GOSSAFUNC
をつけたときに標準出力に表示される大量のデバッグプリントを抑制するためのものです。従来のようにデバッグプリントが必要な時はGOSSAFUNC=Foo+
のように関数名の後ろに+
をつければよいです。ssa.html
の内容に変化はありませんが、html.go
の中ではssa.html
の出力パスを表示するよう変更になりました。
Aug 23, 2018 ソースコードにインライン展開後のソースが追加
cmd/compile: add sources for inlined functions to ssa.html
インライン展開された関数がソースコードの列に追加されるようになりました。
Aug 25, 2018 ソースコードとSSAの間にASTの列が追加
cmd/compile: display AST IR in ssa.html
ソースコードとSSAの間にAST(Abstract Syntax Tree)の列が入りました。ソースコード⇔AST⇔SSA間も対応づけてハイライトされます。
Sep 19, 2018 [bug fix]
cmd/compile/internal/ssa: fix a == a
to a == b
Goのソースコードの列の関数の順序の計算が間違ってました。
Oct 17, 2018 タブ幅を狭く
cmd/compile: make tabs narrow in src column of ssa.html
Goのソースコードのインデントのタブ幅を狭くしました。
Oct 25, 2018 ヘッダの高さを控えめに
cmd/compile: reduce the size of header in ssa.html
関数名とヘルプで上部領域が埋まってたので調整したようです。
毎日見ていると、この高さが気になるのでしょう。
Nov 21, 2018 各フェーズのCFGを表示できるように
cmd/compile: add control flow graphs to ssa.html
大きめの機能が入りました。各フェーズに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
サンプルはこちらでも確認できます。
実行には、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
Nov 24, 2018 ブロックが畳めるように
cmd/compile: make ssa blocks collapsable in ssa.html
小さいですが各ブロックの右上に-
ボタンが追加されました。押すとブロックを畳めます。
まとめ
2018年に導入されたssa.html
への変更点をまとめました。主に次の変更点がありました。
- 元のソースコードとの対応づけ強化
- CFG表示
- 最適化パスやブロックの折りたたみ
- 色数増加
go1.12がリリースされた際にはお試しください。
それでは良いお年を。
追記
2019年以降の変更点も気が向いた時に調べてまとめていきます。
2019年以降変更点
Go1.13/1.14では大きな変更点はありません。
Feb 27, 2019 (go1.13beta1)
all: fix typos as reported by 'misspell'
コメントのタイポの修正です。
Oct 2, 2019 (go1.14beta1)
cmd/compile: allow multiple SSA block control values
block control value を複数指定できるようになりました。IBM S/390等のアーキテクチャでは、compare(比較)とbranch(分岐)を一度に行う命令があり、その対応のためにcontrol value (分岐に使われる値) を2つに拡張しました。
このコミットの後、次のようなコミットがされています。
cmd/compile: add SSA rules for s390x compare-and-branch instructions
ssa.htmlとしての変更点としてはあまりありませんが、S/390アーキテクチャ向けにビルドすると複数のcontrol valueが使われていることが分かります。
- ssa.html / Go1.13 GOOS=linux GOARCH=s390x lower phase のLTにはv7とv8の比較結果であるv9を指定している
- ssa.html / Go1.14 GOOS=linux GOARCH=s390x 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/issues/34325
を受けての対応です。白い背景だと夜見るのが辛いそうです。それに対して、Rob Pikeがコメントしてました。
Mar 11, 2020 (go1.15beta1)
cmd/compile: improve CFG size in ssa.html
CFGのサイズを改良しました。Go1.14は左に寄ってましたが、Go1.15から左右に余白ができました。
Mar 28, 2020 (go1.15beta1)
cmd/compile: add dark mode functionality to CFGs in the ssa.html output
CFGにもダークモード適用されて欲しいよねと。
Apr 1, 2020 (go1.15beta1)
cmd/compile: combine ssa.html columns with identical contents
phaseが大量にあるのでどれが効いているのか分かり辛かったのですが、phaseに変化のない場合は列が結合される様になりました。
Apr 6, 2020 (go1.15beta1)
cmd/compile: refactor around HTMLWriter removing logger in favor of Func
リファクタリングです。
Apr 6, 2020 (go1.15beta1)
cmd/compile: restore missing columns in ssa.html
最後のカラム(phase)だけ結合できていなかったので直しました。
Apr 6, 2020 (go1.15beta1)
cmd/compile: print block auxint value in HTML output
https://github.com/golang/go/issues/38250
cmd/compile: allow multiple SSA block control valuesで対応した、control valueに即値が指定された場合、表示される様になりました。
Apr 24, 2020 (go1.15beta1)
cmd/compile: fix misalignment in sources column of generated ssa.html
一番左の列のsourceの行番号の位置がコードとずれていたので直しました。
ssa.htmlの変遷
各バージョンでの変更点をまとめます。各バージョンのリンクはそのバージョンのssa.htmlのサンプルです。
Go Version | 主な変更点 |
---|---|
Go1.9.2 | - |
Go1.11.4 | 変数名表示、Phase折り畳み、色数増加 |
Go1.12beta1 | Goのソース(インライン展開含む)、AST列追加、CFG(Control Flw Graph)追加 |
Go1.13 | 変更なし |
Go1.14 | compare-and-branch対応 |
Go1.15 | ダークモード(黒背景)導入、変化のないPhase(列)は結合 |
変更履歴
日付 | 変更点 |
---|---|
2018/12/20 | 初版、Go1.12までの変更点をまとめ |
2020/09/11 | Go1.15までの変更点を追記 |