[インデックス 14915] ファイルの概要
このコミットは、Go言語のビルドシステムにおいて、386アーキテクチャ向けのコンパイル時に使用されるCPU機能の検出および指定方法を改善するものです。具体的には、GO386
環境変数のデフォルト値および内部的なCPU機能検出ロジックを、より正確なsse
からsse2
へと変更しています。これにより、GoコンパイラがSSE2命令セットの利用可能性をより正確に判断し、それに基づいて最適化されたコードを生成できるようになります。
コミット
commit d795f07718f0011b035adad4a8fb5f5a33cb7ba1
Author: Russ Cox <rsc@golang.org>
Date: Fri Jan 18 15:10:36 2013 -0500
build: change GO386=sse to GO386=sse2
sse2 is a more precise description of the requirement,
and it matches what people will see in, for example
grep sse2 /proc/cpuinfo # linux
sysctl hw.optional.sse2 # os x
R=golang-dev, dsymonds, iant
CC=golang-dev
https://golang.org/cl/7057050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d795f07718f0011b035adad4a8fb5f5a33cb7ba1
元コミット内容
このコミットの目的は、GoのビルドプロセスにおけるGO386
環境変数の扱いを変更することです。以前はGO386=sse
としていたものをGO386=sse2
に変更しています。コミットメッセージによると、sse2
の方が要件をより正確に記述しており、Linuxの/proc/cpuinfo
やmacOSのsysctl hw.optional.sse2
といった一般的なシステムツールでユーザーが確認する情報と一致するため、この変更が行われました。これは、Goコンパイラが生成するコードの最適化レベルを、ターゲットCPUの実際の機能に合わせて調整するためのものです。
変更の背景
この変更の背景には、Go言語がサポートするx86アーキテクチャ(特に32ビット版の386)におけるCPUの命令セット拡張の進化があります。
- SSE (Streaming SIMD Extensions): IntelがPentium IIIプロセッサで導入したSIMD(Single Instruction, Multiple Data)命令セットです。浮動小数点演算やマルチメディア処理の高速化を目的としています。
- SSE2 (Streaming SIMD Extensions 2): IntelがPentium 4プロセッサで導入したSSEの拡張版です。SSE2は、SSEの浮動小数点演算機能に加えて、整数演算や倍精度浮動小数点演算にもSIMD機能を提供します。現代のほとんどのx86-64プロセッサはSSE2をサポートしており、32ビットモードでも利用可能です。
Goのビルドシステムは、ターゲットとなるCPUが特定の命令セットをサポートしているかどうかを検出し、それに応じてコンパイル時の最適化を適用します。以前はsse
という一般的な用語を使用していましたが、これはSSEとSSE2のどちらを指すのか曖昧でした。多くの現代のCPUはSSE2をサポートしており、GoコンパイラがSSE2命令を利用できる場合、より効率的なコードを生成できます。
このコミットは、以下の理由からsse
からsse2
への変更を行いました。
- 精度の向上:
sse2
は、Goコンパイラが期待するCPUの命令セット要件をより正確に表現しています。これにより、コンパイラはより適切な最適化を適用できます。 - ユーザーとの整合性: Linuxの
/proc/cpuinfo
やmacOSのsysctl hw.optional.sse2
といった一般的なシステムツールでユーザーがCPUの機能を確認する際に、sse2
という用語が広く使われています。この変更により、Goのビルド設定とシステム情報との間に一貫性が生まれ、ユーザーが自身の環境でGoをビルドする際の混乱が減少します。 - デフォルトの最適化:
GO386
が設定されていない場合、GoのビルドシステムはCPUの機能を自動検出します。この自動検出ロジックがcansse()
からcansse2()
に変わることで、より新しい命令セットであるSSE2がデフォルトで考慮されるようになり、結果としてより高性能なバイナリが生成される可能性が高まります。
前提知識の解説
このコミットを理解するためには、以下の概念を把握しておく必要があります。
1. Go言語のビルドシステムとクロスコンパイル
Go言語は、強力なクロスコンパイル機能を内蔵しています。これは、あるオペレーティングシステム(OS)やアーキテクチャ上で、別のOSやアーキテクチャ向けのバイナリを生成できる能力です。この機能は、GOOS
、GOARCH
、GOARM
、GO386
などの環境変数によって制御されます。
GOOS
: ターゲットとなるOS(例:linux
,windows
,darwin
)。GOARCH
: ターゲットとなるCPUアーキテクチャ(例:amd64
,386
,arm
,arm64
)。GO386
:GOARCH=386
の場合にのみ関連する環境変数で、32ビットx86アーキテクチャ向けの特定のCPU機能(命令セット拡張)を指定します。この変数は、コンパイラが生成するコードの最適化レベルに影響を与えます。
Goのビルドプロセスは、これらの環境変数を参照して、適切なコンパイラツールチェーンを選択し、ターゲット環境に合わせたバイナリを生成します。
2. x86アーキテクチャと命令セット拡張 (SSE, SSE2)
x86アーキテクチャは、IntelとAMDによって開発された命令セットアーキテクチャです。長年にわたり、性能向上と新機能の追加のために様々な命令セット拡張が導入されてきました。
-
SIMD (Single Instruction, Multiple Data): 一つの命令で複数のデータ要素に対して同じ操作を実行する並列処理の形式です。これにより、特にマルチメディア処理、科学技術計算、グラフィックス処理などで大幅な性能向上が期待できます。
-
SSE (Streaming SIMD Extensions):
- IntelがPentium IIIプロセッサで導入。
- 8つの128ビットXMMレジスタ(
XMM0
~XMM7
)と、新しいデータ型(単精度浮動小数点数)を導入。 - 主に単精度浮動小数点演算のSIMD処理を目的としています。
-
SSE2 (Streaming SIMD Extensions 2):
- IntelがPentium 4プロセッサで導入。
- SSEの機能を拡張し、倍精度浮動小数点数と整数データ型に対するSIMD演算をサポート。
- 現代のほとんどのx86-64プロセッサはSSE2をサポートしており、32ビットモードでも利用可能です。Windows XP SP2以降の32ビット版Windowsは、SSE2を必須要件としています。
Goコンパイラは、これらの命令セット拡張を利用して、より効率的なコード(例えば、浮動小数点演算やメモリ操作を高速化するコード)を生成できます。
3. CPUID命令
CPUID
命令は、x86アーキテクチャのプロセッサが提供する命令で、プロセッサの機能や情報をプログラムから問い合わせるために使用されます。オペレーティングシステムやアプリケーションは、この命令を使ってプロセッサがサポートする命令セット拡張(SSE, SSE2, AVXなど)やキャッシュ構成などの情報を取得し、それに基づいて最適なコードパスを選択したり、特定の機能を有効にしたりします。
Goのビルドシステムでは、cansse()
やcansse2()
のような関数が内部的にCPUID
命令を利用して、実行環境のCPUが特定の命令セットをサポートしているかを判断します。
技術的詳細
このコミットは、Goのビルドシステムにおける386アーキテクチャ向けのCPU機能検出ロジックと、それに関連するコンパイルオプションの扱いを変更しています。
1. GO386
環境変数のデフォルト値の変更
src/cmd/dist/build.c
のinit()
関数は、GO386
環境変数が設定されていない場合にデフォルト値を決定するロジックを含んでいます。
変更前:
if(cansse())
bwritestr(&b, "sse");
else
bwritestr(&b, "387");
変更後:
if(cansse2())
bwritestr(&b, "sse2");
else
bwritestr(&b, "387");
この変更により、GO386
が明示的に設定されていない場合、ビルドシステムはまずcansse2()
を呼び出してSSE2のサポートをチェックします。SSE2が利用可能であればGO386
はsse2
に設定され、そうでなければ従来の387
(x87 FPU命令セットのみを使用)に設定されます。これにより、現代のCPUではデフォルトでSSE2が利用されるようになり、より高性能なバイナリが生成される可能性が高まります。
2. cansse()
からcansse2()
への関数名の変更とロジックの統一
複数のファイル(src/cmd/dist/a.h
, src/cmd/dist/plan9.c
, src/cmd/dist/unix.c
, src/cmd/dist/windows.c
)で、cansse()
という関数名がcansse2()
に変更されています。これは単なるリネームではなく、その関数が実際にSSE2のサポートをチェックするようになったことを明確にするためのものです。
これらのファイルは、Goのビルドツールであるdist
コマンドの一部であり、異なるOS(Plan 9, Unix系, Windows)上でのCPU機能検出ロジックをカプセル化しています。cansse2()
関数は、内部的にCPUID
命令を使用して、プロセッサがSSE2命令セットをサポートしているかどうかを判断します。
例えば、src/cmd/dist/unix.c
やsrc/cmd/dist/windows.c
では、__cpuid
またはcpuid
関数を呼び出してCPU情報を取得し、特定のビット(SSE2のサポートを示すビット)がセットされているかを確認します。
3. src/cmd/gc/lex.c
におけるGO386
のパースロジックの変更
src/cmd/gc/lex.c
はGoコンパイラの字句解析器の一部であり、ビルド時に設定されるGO386
の値に基づいて、コンパイラがSSE命令を使用するかどうかを決定します。
変更前:
use_sse = strcmp(getgo386(), "sse") == 0;
変更後:
if(thechar == '8') { // '8' corresponds to GOARCH=386
p = getgo386();
if(strcmp(p, "387") == 0)
use_sse = 0;
else if(strcmp(p, "sse2") == 0)
use_sse = 1;
else
sysfatal("unsupported setting GO386=%s", p);
}
この変更により、コンパイラはGO386
の値として"sse"
ではなく"sse2"
を期待するようになります。
GO386="387"
の場合、use_sse
は0
となり、SSE/SSE2命令は使用されません。GO386="sse2"
の場合、use_sse
は1
となり、コンパイラはSSE2命令を利用した最適化を行います。- これら以外の値が設定された場合は、致命的なエラー(
sysfatal
)が発生し、サポートされていない設定であることをユーザーに通知します。
この変更は、コンパイラがGO386
の値に基づいて、生成するアセンブリコードにSSE2命令を含めるかどうかを制御するための重要な部分です。
影響
この変更は、主に32ビットx86(GOARCH=386
)向けのGoバイナリのビルドに影響を与えます。
- 性能向上: 現代のCPUでビルドする場合、デフォルトでSSE2が有効になるため、浮動小数点演算や一部のメモリ操作が高速化され、Goアプリケーションの実行性能が向上する可能性があります。
- 互換性: 非常に古いCPU(SSE2をサポートしないPentium III以前のプロセッサなど)でGoバイナリを実行しようとすると、
GO386=sse2
でビルドされたバイナリは実行できない可能性があります。しかし、そのような環境は現在では非常に稀であり、Goのターゲット環境としては通常考慮されません。 - ビルドの明確化:
GO386=sse2
というより正確な記述により、ビルド設定が何を意味するのかが明確になります。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードの変更点は以下の通りです。
-
src/cmd/dist/a.h
:bool cansse(void);
がbool cansse2(void);
に変更。dist
コマンドのヘッダーファイルで、CPU機能検出関数の宣言が更新されました。
-
src/cmd/dist/build.c
:init()
関数内で、GO386
が未設定の場合のデフォルト値決定ロジックが変更。if(cansse())
がif(cansse2())
に変更。bwritestr(&b, "sse");
がbwritestr(&b, "sse2");
に変更。- これにより、デフォルトでSSE2のサポートがチェックされ、
GO386
にsse2
が設定されるようになりました。
-
src/cmd/dist/plan9.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Plan 9向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/dist/unix.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Unix系OS向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/dist/windows.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Windows向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/gc/lex.c
:main()
関数内で、GO386
の値に基づいてuse_sse
フラグを設定するロジックが変更。use_sse = strcmp(getgo386(), "sse") == 0;
が削除。GOARCH=386
の場合(thechar == '8'
)、getgo386()
で取得した値が"387"
ならuse_sse = 0
、"sse2"
ならuse_sse = 1
に設定されるようになりました。- サポートされていない
GO386
の値が検出された場合にsysfatal
でエラーを出すロジックが追加されました。
コアとなるコードの解説
src/cmd/dist/a.h
このファイルは、Goのビルドツールであるdist
コマンドが使用する共通のヘッダーファイルです。cansse()
からcansse2()
への変更は、このヘッダーで宣言されているCPU機能検出関数の名前が、より正確なSSE2のチェックを反映するように更新されたことを示しています。
src/cmd/dist/build.c
このファイルは、Goのビルドプロセスを制御するdist
コマンドの主要な部分です。init()
関数は、ビルド環境の初期化を担当し、その中でGO386
環境変数のデフォルト値を設定します。
変更されたコードブロックは、GO386
がユーザーによって明示的に設定されていない場合に実行されます。
if(b.len == 0) { // GO386が設定されていない場合
if(cansse2()) // SSE2が利用可能かチェック
bwritestr(&b, "sse2"); // 利用可能なら "sse2" を設定
else
bwritestr(&b, "387"); // 利用不可なら "387" を設定
}
このロジックにより、現代のCPUでは自動的にGO386=sse2
が選択され、コンパイラがSSE2命令を利用した最適化を行うようになります。
src/cmd/dist/plan9.c
, src/cmd/dist/unix.c
, src/cmd/dist/windows.c
これらのファイルは、それぞれPlan 9、Unix系OS、Windowsといった異なるプラットフォームにおけるCPU機能検出の実装を含んでいます。cansse()
関数がcansse2()
にリネームされたのは、これらの関数が実際にSSE2のサポートをチェックするようになったことを明確にするためです。
例えば、src/cmd/dist/unix.c
やsrc/cmd/dist/windows.c
では、CPUID
命令(__cpuid
またはcpuid
関数を通じて)を使用してCPUの機能フラグを読み取り、SSE2のサポートを示すビット(通常はEDXレジスタのビット26)がセットされているかを確認します。
src/cmd/gc/lex.c
このファイルはGoコンパイラの字句解析器の一部であり、コンパイル時にGO386
の値に基づいてuse_sse
という内部フラグを設定します。このフラグは、コンパイラのバックエンドがSSE/SSE2命令を生成するかどうかを制御します。
変更されたコードブロックは、GOARCH
が386
(thechar == '8'
)の場合に実行されます。
if(thechar == '8') { // GOARCH=386の場合
p = getgo386(); // GO386の値を取得
if(strcmp(p, "387") == 0) // "387" ならSSEを使わない
use_sse = 0;
else if(strcmp(p, "sse2") == 0) // "sse2" ならSSEを使う
use_sse = 1;
else
sysfatal("unsupported setting GO386=%s", p); // それ以外はエラー
}
このロジックにより、コンパイラはGO386
の値が"sse2"
である場合にのみSSE2命令を生成するようになり、"sse"
という古い値はサポートされなくなりました。これにより、コンパイラの動作とビルドシステムの意図がより密接に連携するようになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goの環境変数に関するドキュメント: https://go.dev/doc/install/source#environment (このコミット時点では古い情報である可能性がありますが、概念は共通です)
- GoのIssueトラッカー (このコミットに関連する議論があるかもしれません): https://github.com/golang/go/issues
参考にした情報源リンク
- Streaming SIMD Extensions (SSE) - Wikipedia: https://ja.wikipedia.org/wiki/Streaming_SIMD_Extensions
- Streaming SIMD Extensions 2 (SSE2) - Wikipedia: https://ja.wikipedia.org/wiki/Streaming_SIMD_Extensions_2
- CPUID - Wikipedia: https://ja.wikipedia.org/wiki/CPUID
- Goのビルドシステムに関する一般的な情報 (Goのソースコードや関連するブログ記事、フォーラムの議論など)
grep sse2 /proc/cpuinfo
およびsysctl hw.optional.sse2
のコマンド出力例に関する情報 (一般的なLinux/macOSのドキュメントやフォーラム)```markdown
[インデックス 14915] ファイルの概要
このコミットは、Go言語のビルドシステムにおいて、386アーキテクチャ向けのコンパイル時に使用されるCPU機能の検出および指定方法を改善するものです。具体的には、GO386
環境変数のデフォルト値および内部的なCPU機能検出ロジックを、より正確なsse
からsse2
へと変更しています。これにより、GoコンパイラがSSE2命令セットの利用可能性をより正確に判断し、それに基づいて最適化されたコードを生成できるようになります。
コミット
commit d795f07718f0011b035adad4a8fb5f5a33cb7ba1
Author: Russ Cox <rsc@golang.org>
Date: Fri Jan 18 15:10:36 2013 -0500
build: change GO386=sse to GO386=sse2
sse2 is a more precise description of the requirement,
and it matches what people will see in, for example
grep sse2 /proc/cpuinfo # linux
sysctl hw.optional.sse2 # os x
R=golang-dev, dsymonds, iant
CC=golang-dev
https://golang.org/cl/7057050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d795f07718f0011b035adad4a8fb5f5a33cb7ba1
元コミット内容
このコミットの目的は、GoのビルドプロセスにおけるGO386
環境変数の扱いを変更することです。以前はGO386=sse
としていたものをGO386=sse2
に変更しています。コミットメッセージによると、sse2
の方が要件をより正確に記述しており、Linuxの/proc/cpuinfo
やmacOSのsysctl hw.optional.sse2
といった一般的なシステムツールでユーザーが確認する情報と一致するため、この変更が行われました。これは、Goコンパイラが生成するコードの最適化レベルを、ターゲットCPUの実際の機能に合わせて調整するためのものです。
変更の背景
この変更の背景には、Go言語がサポートするx86アーキテクチャ(特に32ビット版の386)におけるCPUの命令セット拡張の進化があります。
- SSE (Streaming SIMD Extensions): IntelがPentium IIIプロセッサで導入したSIMD(Single Instruction, Multiple Data)命令セットです。浮動小数点演算やマルチメディア処理の高速化を目的としています。
- SSE2 (Streaming SIMD Extensions 2): IntelがPentium 4プロセッサで導入したSSEの拡張版です。SSE2は、SSEの浮動小数点演算機能に加えて、整数演算や倍精度浮動小数点演算にもSIMD機能を提供します。現代のほとんどのx86-64プロセッサはSSE2をサポートしており、32ビットモードでも利用可能です。
Goのビルドシステムは、ターゲットとなるCPUが特定の命令セットをサポートしているかどうかを検出し、それに応じてコンパイル時の最適化を適用します。以前はsse
という一般的な用語を使用していましたが、これはSSEとSSE2のどちらを指すのか曖昧でした。多くの現代のCPUはSSE2をサポートしており、GoコンパイラがSSE2命令を利用できる場合、より効率的なコードを生成できます。
このコミットは、以下の理由からsse
からsse2
への変更を行いました。
- 精度の向上:
sse2
は、Goコンパイラが期待するCPUの命令セット要件をより正確に表現しています。これにより、コンパイラはより適切な最適化を適用できます。 - ユーザーとの整合性: Linuxの
/proc/cpuinfo
やmacOSのsysctl hw.optional.sse2
といった一般的なシステムツールでユーザーがCPUの機能を確認する際に、sse2
という用語が広く使われています。この変更により、Goのビルド設定とシステム情報との間に一貫性が生まれ、ユーザーが自身の環境でGoをビルドする際の混乱が減少します。 - デフォルトの最適化:
GO386
が設定されていない場合、GoのビルドシステムはCPUの機能を自動検出します。この自動検出ロジックがcansse()
からcansse2()
に変わることで、より新しい命令セットであるSSE2がデフォルトで考慮されるようになり、結果としてより高性能なバイナリが生成される可能性が高まります。
前提知識の解説
このコミットを理解するためには、以下の概念を把握しておく必要があります。
1. Go言語のビルドシステムとクロスコンパイル
Go言語は、強力なクロスコンパイル機能を内蔵しています。これは、あるオペレーティングシステム(OS)やアーキテクチャ上で、別のOSやアーキテクチャ向けのバイナリを生成できる能力です。この機能は、GOOS
、GOARCH
、GOARM
、GO386
などの環境変数によって制御されます。
GOOS
: ターゲットとなるOS(例:linux
,windows
,darwin
)。GOARCH
: ターゲットとなるCPUアーキテクチャ(例:amd64
,386
,arm
,arm64
)。GO386
:GOARCH=386
の場合にのみ関連する環境変数で、32ビットx86アーキテクチャ向けの特定のCPU機能(命令セット拡張)を指定します。この変数は、コンパイラが生成するコードの最適化レベルに影響を与えます。
Goのビルドプロセスは、これらの環境変数を参照して、適切なコンパイラツールチェーンを選択し、ターゲット環境に合わせたバイナリを生成します。
2. x86アーキテクチャと命令セット拡張 (SSE, SSE2)
x86アーキテクチャは、IntelとAMDによって開発された命令セットアーキテクチャです。長年にわたり、性能向上と新機能の追加のために様々な命令セット拡張が導入されてきました。
-
SIMD (Single Instruction, Multiple Data): 一つの命令で複数のデータ要素に対して同じ操作を実行する並列処理の形式です。これにより、特にマルチメディア処理、科学技術計算、グラフィックス処理などで大幅な性能向上が期待できます。
-
SSE (Streaming SIMD Extensions):
- IntelがPentium IIIプロセッサで導入。
- 8つの128ビットXMMレジスタ(
XMM0
~XMM7
)と、新しいデータ型(単精度浮動小数点数)を導入。 - 主に単精度浮動小数点演算のSIMD処理を目的としています。
-
SSE2 (Streaming SIMD Extensions 2):
- IntelがPentium 4プロセッサで導入。
- SSEの機能を拡張し、倍精度浮動小数点数と整数データ型に対するSIMD演算をサポート。
- 現代のほとんどのx86-64プロセッサはSSE2をサポートしており、32ビットモードでも利用可能です。Windows XP SP2以降の32ビット版Windowsは、SSE2を必須要件としています。
Goコンパイラは、これらの命令セット拡張を利用して、より効率的なコード(例えば、浮動小数点演算やメモリ操作を高速化するコード)を生成できます。
3. CPUID命令
CPUID
命令は、x86アーキテクチャのプロセッサが提供する命令で、プロセッサの機能や情報をプログラムから問い合わせるために使用されます。オペレーティングシステムやアプリケーションは、この命令を使ってプロセッサがサポートする命令セット拡張(SSE, SSE2, AVXなど)やキャッシュ構成などの情報を取得し、それに基づいて最適なコードパスを選択したり、特定の機能を有効にしたりします。
Goのビルドシステムでは、cansse()
やcansse2()
のような関数が内部的にCPUID
命令を利用して、実行環境のCPUが特定の命令セットをサポートしているかを判断します。
技術的詳細
このコミットは、Goのビルドシステムにおける386アーキテクチャ向けのCPU機能検出ロジックと、それに関連するコンパイルオプションの扱いを変更しています。
1. GO386
環境変数のデフォルト値の変更
src/cmd/dist/build.c
のinit()
関数は、GO386
環境変数が設定されていない場合にデフォルト値を決定するロジックを含んでいます。
変更前:
if(cansse())
bwritestr(&b, "sse");
else
bwritestr(&b, "387");
変更後:
if(cansse2())
bwritestr(&b, "sse2");
else
bwritestr(&b, "387");
この変更により、GO386
が明示的に設定されていない場合、ビルドシステムはまずcansse2()
を呼び出してSSE2のサポートをチェックします。SSE2が利用可能であればGO386
はsse2
に設定され、そうでなければ従来の387
(x87 FPU命令セットのみを使用)に設定されます。これにより、現代のCPUではデフォルトでSSE2が利用されるようになり、より高性能なバイナリが生成される可能性が高まります。
2. cansse()
からcansse2()
への関数名の変更とロジックの統一
複数のファイル(src/cmd/dist/a.h
, src/cmd/dist/plan9.c
, src/cmd/dist/unix.c
, src/cmd/dist/windows.c
)で、cansse()
という関数名がcansse2()
に変更されています。これは単なるリネームではなく、その関数が実際にSSE2のサポートをチェックするようになったことを明確にするためのものです。
これらのファイルは、Goのビルドツールであるdist
コマンドの一部であり、異なるOS(Plan 9, Unix系, Windows)上でのCPU機能検出ロジックをカプセル化しています。cansse2()
関数は、内部的にCPUID
命令を使用して、プロセッサがSSE2命令セットをサポートしているかどうかを判断します。
例えば、src/cmd/dist/unix.c
やsrc/cmd/dist/windows.c
では、__cpuid
またはcpuid
関数を呼び出してCPU情報を取得し、特定のビット(SSE2のサポートを示すビット)がセットされているかを確認します。
3. src/cmd/gc/lex.c
におけるGO386
のパースロジックの変更
src/cmd/gc/lex.c
はGoコンパイラの字句解析器の一部であり、ビルド時に設定されるGO386
の値に基づいて、コンパイラがSSE命令を使用するかどうかを決定します。
変更前:
use_sse = strcmp(getgo386(), "sse") == 0;
変更後:
if(thechar == '8') { // '8' corresponds to GOARCH=386
p = getgo386();
if(strcmp(p, "387") == 0)
use_sse = 0;
else if(strcmp(p, "sse2") == 0)
use_sse = 1;
else
sysfatal("unsupported setting GO386=%s", p);
}
この変更により、コンパイラはGO386
の値として"sse"
ではなく"sse2"
を期待するようになります。
GO386="387"
の場合、use_sse
は0
となり、SSE/SSE2命令は使用されません。GO386="sse2"
の場合、use_sse
は1
となり、コンパイラはSSE2命令を利用した最適化を行います。- これら以外の値が設定された場合は、致命的なエラー(
sysfatal
)が発生し、サポートされていない設定であることをユーザーに通知します。
この変更は、コンパイラがGO386
の値に基づいて、生成するアセンブリコードにSSE2命令を含めるかどうかを制御するための重要な部分です。
影響
この変更は、主に32ビットx86(GOARCH=386
)向けのGoバイナリのビルドに影響を与えます。
- 性能向上: 現代のCPUでビルドする場合、デフォルトでSSE2が有効になるため、浮動小数点演算や一部のメモリ操作が高速化され、Goアプリケーションの実行性能が向上する可能性があります。
- 互換性: 非常に古いCPU(SSE2をサポートしないPentium III以前のプロセッサなど)でGoバイナリを実行しようとすると、
GO386=sse2
でビルドされたバイナリは実行できない可能性があります。しかし、そのような環境は現在では非常に稀であり、Goのターゲット環境としては通常考慮されません。 - ビルドの明確化:
GO386=sse2
というより正確な記述により、ビルド設定が何を意味するのかが明確になります。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルとコードの変更点は以下の通りです。
-
src/cmd/dist/a.h
:bool cansse(void);
がbool cansse2(void);
に変更。dist
コマンドのヘッダーファイルで、CPU機能検出関数の宣言が更新されました。
-
src/cmd/dist/build.c
:init()
関数内で、GO386
が未設定の場合のデフォルト値決定ロジックが変更。if(cansse())
がif(cansse2())
に変更。bwritestr(&b, "sse");
がbwritestr(&b, "sse2");
に変更。- これにより、デフォルトでSSE2のサポートがチェックされ、
GO386
にsse2
が設定されるようになりました。
-
src/cmd/dist/plan9.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Plan 9向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/dist/unix.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Unix系OS向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/dist/windows.c
:bool cansse(void)
関数がbool cansse2(void)
にリネーム。- Windows向けのCPU機能検出ロジックの関数名が変更されました。
-
src/cmd/gc/lex.c
:main()
関数内で、GO386
の値に基づいてuse_sse
フラグを設定するロジックが変更。use_sse = strcmp(getgo386(), "sse") == 0;
が削除。GOARCH=386
の場合(thechar == '8'
)、getgo386()
で取得した値が"387"
ならuse_sse = 0
、"sse2"
ならuse_sse = 1
に設定されるようになりました。- サポートされていない
GO386
の値が検出された場合にsysfatal
でエラーを出すロジックが追加されました。
コアとなるコードの解説
src/cmd/dist/a.h
このファイルは、Goのビルドツールであるdist
コマンドが使用する共通のヘッダーファイルです。cansse()
からcansse2()
への変更は、このヘッダーで宣言されているCPU機能検出関数の名前が、より正確なSSE2のチェックを反映するように更新されたことを示しています。
src/cmd/dist/build.c
このファイルは、Goのビルドプロセスを制御するdist
コマンドの主要な部分です。init()
関数は、ビルド環境の初期化を担当し、その中でGO386
環境変数のデフォルト値を設定します。
変更されたコードブロックは、GO386
がユーザーによって明示的に設定されていない場合に実行されます。
if(b.len == 0) { // GO386が設定されていない場合
if(cansse2()) // SSE2が利用可能かチェック
bwritestr(&b, "sse2"); // 利用可能なら "sse2" を設定
else
bwritestr(&b, "387"); // 利用不可なら "387" を設定
}
このロジックにより、現代のCPUでは自動的にGO386=sse2
が選択され、コンパイラがSSE2命令を利用した最適化を行うようになります。
src/cmd/dist/plan9.c
, src/cmd/dist/unix.c
, src/cmd/dist/windows.c
これらのファイルは、それぞれPlan 9、Unix系OS、Windowsといった異なるプラットフォームにおけるCPU機能検出の実装を含んでいます。cansse()
関数がcansse2()
にリネームされたのは、これらの関数が実際にSSE2のサポートをチェックするようになったことを明確にするためです。
例えば、src/cmd/dist/unix.c
やsrc/cmd/dist/windows.c
では、CPUID
命令(__cpuid
またはcpuid
関数を通じて)を使用してCPUの機能フラグを読み取り、SSE2のサポートを示すビット(通常はEDXレジスタのビット26)がセットされているかを確認します。
src/cmd/gc/lex.c
このファイルはGoコンパイラの字句解析器の一部であり、コンパイル時にGO386
の値に基づいてuse_sse
という内部フラグを設定します。このフラグは、コンパイラのバックエンドがSSE/SSE2命令を生成するかどうかを制御します。
変更されたコードブロックは、GOARCH
が386
(thechar == '8'
)の場合に実行されます。
if(thechar == '8') { // GOARCH=386の場合
p = getgo386(); // GO386の値を取得
if(strcmp(p, "387") == 0) // "387" ならSSEを使わない
use_sse = 0;
else if(strcmp(p, "sse2") == 0) // "sse2" ならSSEを使う
use_sse = 1;
else
sysfatal("unsupported setting GO386=%s", p); // それ以外はエラー
}
このロジックにより、コンパイラはGO386
の値が"sse2"
である場合にのみSSE2命令を生成するようになり、"sse"
という古い値はサポートされなくなりました。これにより、コンパイラの動作とビルドシステムの意図がより密接に連携するようになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goの環境変数に関するドキュメント: https://go.dev/doc/install/source#environment (このコミット時点では古い情報である可能性がありますが、概念は共通です)
- GoのIssueトラッカー (このコミットに関連する議論があるかもしれません): https://github.com/golang/go/issues
参考にした情報源リンク
- Streaming SIMD Extensions (SSE) - Wikipedia: https://ja.wikipedia.org/wiki/Streaming_SIMD_Extensions
- Streaming SIMD Extensions 2 (SSE2) - Wikipedia: https://ja.wikipedia.org/wiki/Streaming_SIMD_Extensions_2
- CPUID - Wikipedia: https://ja.wikipedia.org/wiki/CPUID
- Goのビルドシステムに関する一般的な情報 (Goのソースコードや関連するブログ記事、フォーラムの議論など)
grep sse2 /proc/cpuinfo
およびsysctl hw.optional.sse2
のコマンド出力例に関する情報 (一般的なLinux/macOSのドキュメントやフォーラム)