[インデックス 11099] ファイルの概要
このコミットは、Go言語のコンパイラ gc
において、関数のインライン化をデフォルトで有効にする変更を導入しています。これにより、Goプログラムの実行性能が特別なコンパイラオプションなしに向上することが期待されます。また、インライン化の挙動を制御するためのデバッグフラグの扱いが調整され、関連するテストファイルも更新されています。
コミット
commit 4a6b07f2356644e0aa58925799771d79ec0541a0
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 10 20:08:53 2012 -0800
gc: enable inlining by default
R=lvd, r
CC=golang-dev
https://golang.org/cl/5531058
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4a6b07f2356644e0aa58925799771d79ec0541a0
元コミット内容
Goコンパイラ (gc
): インライン化をデフォルトで有効にする。
レビュー担当者: lvd, r CC: golang-devメーリングリスト 関連する変更リスト: https://golang.org/cl/5531058
変更の背景
Go言語のコンパイラ gc
におけるインライン化は、プログラムの実行性能を向上させるための重要な最適化手法です。関数呼び出しのオーバーヘッドを削減し、より広範な最適化(例えば、レジスタ割り当ての改善やデッドコード削除)を可能にします。
このコミットが行われた2012年当時、Go言語はまだ比較的新しい言語であり、コンパイラの最適化機能は継続的に改善されていました。インライン化は、その効果と安定性が十分に評価された段階に達し、デフォルトで有効にすることで、ユーザーが特別な設定なしにGoプログラムの性能向上を享受できるようにすることを目的としています。これにより、開発者は明示的にインライン化を有効にする必要がなくなり、より高速な実行ファイルが生成されるようになります。
また、この変更は、コンパイラの内部デバッグフラグ debug['l']
の挙動を調整し、コマンドラインオプション -l
がインライン化を無効にするように再定義しています。これは、デフォルトでインライン化が有効になる新しい挙動と整合性を保ちつつ、必要に応じて開発者がインライン化を無効にできる手段を提供するためです。
前提知識の解説
- インライン化 (Inlining): コンパイラ最適化の一種で、呼び出される関数のコードを、その関数を呼び出す側のコードに直接埋め込む手法です。これにより、関数呼び出しに伴うスタックフレームの作成・破棄、引数の渡し方などのオーバーヘッドが削減されます。また、呼び出し元と呼び出し先のコードが一体となることで、コンパイラがより広範な最適化(例: 定数伝播、デッドコード削除)を適用できるようになります。ただし、コードサイズが増加する可能性があり、過度なインライン化はキャッシュミスを増やすなど、かえって性能を悪化させる場合もあります。
- Goコンパイラ (gc): Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担います。
gc
は、Go言語の設計思想に合わせて、高速なコンパイルと効率的な実行コードの生成を目指しています。 - コンパイラデバッグフラグ (
debug['l']
): コンパイラには、開発やデバッグのために様々な内部フラグが用意されています。これらは通常、コマンドライン引数(例:-gcflags='-m'
)を通じて制御されます。debug['l']
は、Goコンパイラgc
の内部でインライン化の挙動を制御するために使用されるフラグです。このフラグの値によって、インライン化が有効になるか、無効になるか、あるいは追加のデバッグ情報が出力されるかが決まります。debug['l'] == 0
: インライン化が無効。debug['l'] == 1
: インライン化が有効。debug['l'] > 1
: インライン化が有効で、さらに詳細なデバッグ情報が出力される。
lex.c
: Goコンパイラgc
のソースコードの一部で、字句解析(lexical analysis)やコマンドライン引数の処理など、コンパイラの初期段階の処理を担当するファイルです。
技術的詳細
このコミットの主要な変更は、src/cmd/gc/lex.c
内の main
関数にインライン化のデフォルト挙動を制御するロジックを追加した点です。
変更前のコンパイラでは、インライン化はデフォルトで無効になっていたか、特定のフラグを明示的に指定しないと有効になりませんでした。このコミットでは、debug['l']
という内部フラグの値を調整することで、このデフォルト挙動を変更しています。
追加されたコードは以下のロジックを実装しています。
// enable inlining. for now:
// default: inlining on. (debug['l'] == 1)
// -l: inlining off (debug['l'] == 0)
// -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
if(debug['l'] <= 1)
debug['l'] = 1 - debug['l'];
このコードブロックは、debug['l']
の現在の値に基づいて、インライン化の最終的な状態を決定します。
- デフォルトの場合: コマンドラインで
-l
オプションが指定されない場合、debug['l']
は初期値(通常は0)を持ちます。このときdebug['l'] <= 1
は真となり、debug['l'] = 1 - debug['l']
が実行されます。もし初期値が0であればdebug['l']
は1になり、インライン化が有効になります。 -l
オプションが指定された場合: コマンドラインで-l
オプションが指定されると、コンパイラはdebug['l']
を0に設定します。このときもdebug['l'] <= 1
は真となり、debug['l'] = 1 - debug['l']
が実行されます。debug['l']
は1 - 0 = 1
となります。しかし、コメントには-l: inlining off (debug['l'] == 0)
と書かれており、これはこのコードブロックの後にdebug['l']
が0になるように調整されるか、あるいはこのコードブロックが実行される前に-l
オプションがdebug['l']
を0に設定し、その後の処理でdebug['l']
が1になるが、最終的にインライン化がオフになるような別のロジックが存在することを示唆しています。- 追記: 実際のGoコンパイラの挙動として、
-l
フラグはdebug['l']
を0に設定し、インライン化を無効にします。このコミットのコードは、-l
が指定されていない場合にdebug['l']
を1に設定してインライン化を有効にするためのものです。もし-l
が指定されてdebug['l']
が0になった場合、1 - debug['l']
は1になりますが、これはインライン化を無効にするための最終的なチェックがこのコードブロックの後に存在するか、あるいはこのコードブロックが-l
が指定されていない場合のデフォルト挙動を設定するためのものであることを示しています。コメントの「debug['l'] == 0
」は、-l
が指定された結果としてインライン化がオフになる状態を指していると解釈するのが自然です。
- 追記: 実際のGoコンパイラの挙動として、
-ll
または-lll
オプションが指定された場合: これらのオプションはdebug['l']
を1より大きい値(例: 2や3)に設定します。この場合、debug['l'] <= 1
は偽となり、上記のif
文のブロックは実行されません。結果としてdebug['l']
は1より大きい値のままとなり、インライン化が有効になり、さらに詳細なデバッグ情報が出力されます。
要するに、この変更は、-l
オプションが指定されない限り、インライン化がデフォルトで有効になるように debug['l']
の値を調整するものです。
また、test/escape2.go
の変更は、この新しいデフォルト挙動に対応するためのものです。このテストは、エスケープ解析(escape analysis)に関連するもので、インライン化の有無によって挙動が変わる可能性があります。そのため、テストコマンドに -l
オプションを追加することで、このテストが常にインライン化が無効な状態で実行されるようにし、テストの安定性と再現性を確保しています。
コアとなるコードの変更箇所
src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -234,6 +234,13 @@ main(int argc, char *argv[])
print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
exit(0);
} ARGEND
+
+ // enable inlining. for now:
+ // default: inlining on. (debug['l'] == 1)
+ // -l: inlining off (debug['l'] == 0)
+ // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
+ if(debug['l'] <= 1)
+ debug['l'] = 1 - debug['l'];
if(argc < 1)
usage();
test/escape2.go
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1,4 +1,4 @@
-// errchk -0 $G -m $D/$F.go
+// errchk -0 $G -m -l $D/$F.go
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
コアとなるコードの解説
src/cmd/gc/lex.c
の変更
main
関数内に、インライン化の挙動を制御する新しいコードブロックが追加されました。
// enable inlining. for now:
// default: inlining on. (debug['l'] == 1)
// -l: inlining off (debug['l'] == 0)
// -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
if(debug['l'] <= 1)
debug['l'] = 1 - debug['l'];
このコードは、debug['l']
の値が0または1の場合に、その値を反転させることで、インライン化のデフォルト挙動を「オン」に設定します。
- もし
debug['l']
が初期値の0であれば、1 - 0 = 1
となり、インライン化が有効になります。 - もしコマンドラインオプション
-l
が指定され、debug['l']
が0に設定された場合、この行が実行されるとdebug['l']
は1になります。しかし、これはコメントにある「-l: inlining off (debug['l'] == 0)
」と矛盾するように見えます。これは、このコードブロックが実行された後、またはこのコードブロックの前に、-l
オプションが最終的にインライン化を無効にするための別のロジックが存在するか、あるいはこのコードブロックが-l
が指定されていない場合のデフォルト挙動を設定するためのものであることを示唆しています。Goコンパイラの実際の挙動では、-l
はインライン化を無効にします。このコードは、-l
が指定されない場合にインライン化を有効にするためのものです。 -ll
や-lll
のようにdebug['l']
が1より大きい値に設定されている場合は、if
文の条件が偽となり、このブロックは実行されません。これにより、詳細なデバッグ情報を含むインライン化が有効な状態が維持されます。
この変更により、Goコンパイラはデフォルトでインライン化を実行し、特別なフラグを指定しない限り、より最適化されたコードを生成するようになります。
test/escape2.go
の変更
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1,4 +1,4 @@
-// errchk -0 $G -m $D/$F.go
+// errchk -0 $G -m -l $D/$F.go
この変更は、テストスクリプトのコンパイルコマンドに -l
オプションを追加しています。
- 変更前:
// errchk -0 $G -m $D/$F.go
- 変更後:
// errchk -0 $G -m -l $D/$F.go
errchk
はGoのテストフレームワークの一部で、コンパイル時のエラーチェックを行うためのものです。$G
はGoコンパイラへのパス、$D/$F.go
はテスト対象のソースファイルを示します。
追加された -l
オプションは、Goコンパイラに対してインライン化を無効にするよう指示します。このテストはエスケープ解析の挙動を検証しているため、インライン化の有無によってテスト結果が不安定になることを避けるために、明示的にインライン化を無効にしています。これにより、コンパイラのデフォルトのインライン化設定に関わらず、テストが常に同じ条件下で実行されることが保証されます。
関連リンク
- Go Gerrit Change-Id: https://golang.org/cl/5531058
参考にした情報源リンク
- Go言語のコンパイラ最適化に関する一般的な知識
- Goコンパイラの内部フラグに関する一般的な情報