🐰
Go言語のfor文が動く仕組みをアセンブリレベルで見てみよう
for文がCPU上でどのように実行されているか、想像したことはあるでしょうか?
実際にコンパイルさせてみて出力結果を読んでみましょう。
なんの変哲もないfor文
package main
func main() {
for i := 1; i <= 10; i++ {
print(i)
}
}
コンパイルしてアセンブリに変換
上のコードをアセンブリに変換してみましょう。
出力結果が読みやすくなるように、最適化とインライン化をoffにします。(-N -l オプション)
$ go tool compile -S -N -l min.go
出力されたアセンブリコード ( //のコメントは筆者 )
00029 (min.go:6) MOVQ $1, "".i+8(SP) // i = 1
00038 (min.go:6) JMP 40 // goto 40番地
00040 (min.go:6) CMPQ "".i+8(SP), $10 // compare i <=> 10
00046 (min.go:6) JLE 50 // goto 50番地 if less than or equal to
00048 (min.go:6) JMP 91 // goto 91番地(for loopの出口へ)
00050 (min.go:7) PCDATA $1, $0
00050 (min.go:7) CALL runtime.printlock(SB)
00055 (min.go:7) MOVQ "".i+8(SP), AX // $AX = i
00060 (min.go:7) MOVQ AX, (SP) // args[0] = $AX
00064 (min.go:7) CALL runtime.printint(SB) // printint()
00069 (min.go:7) CALL runtime.printunlock(SB)
00074 (min.go:7) JMP 76 // goto 76番地
00076 (min.go:6) MOVQ "".i+8(SP), AX // $AX = i
00081 (min.go:6) INCQ AX // $AX++
00084 (min.go:6) MOVQ AX, "".i+8(SP) // i = $AX
00089 (min.go:6) JMP 40 // goto 40番地
解説
Go言語でも goto文を使えば 上のアセンブリに近いコードを書くことができます。
package main
func main() {
{
var i int
i = 1
goto CONDITON
CONDITON:
is_le := (i <= 10)
if is_le {
goto BLOCK_START
}
goto EXIT_LOOP
BLOCK_START:
println(i)
goto POST_STMT
POST_STMT:
i++
goto CONDITON
EXIT_LOOP:
}
}
実行する → https://play.golang.org/p/SSPxmu-pfg1
実際に Goコンパイラを作るときも、このような構造を経てからアセンブリに変換すると for文をうまくコンパイルすることができます。
Discussion