Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 13110] ファイルの概要

このコミットは、Go言語のツールチェインにおけるアセンブラ (cmd/6a) とリンカ (cmd/6l) に、BSWAPL (Byte Swap Long) および BSWAPQ (Byte Swap Quad) という新しい命令のサポートを追加するものです。これにより、32ビットおよび64ビットのバイト順序を反転させるCPU命令をGoのアセンブリコードから直接利用できるようになります。

コミット

commit ed480128a6da8e65119738bf792f3fbe4af2e16f
Author: Russ Cox <rsc@golang.org>
Date:   Tue May 22 00:12:58 2012 -0400

    cmd/6a, cmd/6l: add BSWAPL, BSWAPQ
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/6209087

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/ed480128a6da8e65119738bf792f3fbe4af2e16f

元コミット内容

cmd/6a, cmd/6l: add BSWAPL, BSWAPQ

このコミットは、Go言語の64ビットアーキテクチャ向けアセンブラ (cmd/6a) とリンカ (cmd/6l) に、BSWAPL および BSWAPQ 命令のサポートを追加します。

変更の背景

この変更の背景には、Go言語が様々なアーキテクチャで効率的に動作するための最適化があります。BSWAP (Byte Swap) 命令は、プロセッサがレジスタ内のバイト順序を反転させるための命令です。これは、異なるエンディアン(バイト順序)を持つシステム間でデータをやり取りする際や、ネットワークプロトコルなどでバイト順序の変換が必要な場合に非常に有用です。

特に、Intel/AMDのx86-64アーキテクチャ(Goのツールチェインでは通常6で始まるコマンドがこれに対応します)には、BSWAP命令が用意されており、これを利用することでソフトウェアによるバイトスワップ処理よりもはるかに高速に処理を実行できます。Goの標準ライブラリやユーザーコードがこのような低レベルの最適化を必要とする場合、アセンブラとリンカがこれらの命令を認識し、正しく処理できる必要があります。

このコミットは、Goのツールチェインがハードウェアの機能を最大限に活用し、パフォーマンスを向上させるための継続的な取り組みの一環として行われました。

前提知識の解説

このコミットを理解するためには、以下の概念について基本的な知識が必要です。

  • アセンブリ言語とアセンブラ:
    • アセンブリ言語: コンピュータのCPUが直接実行できる機械語に非常に近い低レベルのプログラミング言語です。人間が読めるニーモニック(例: MOV, ADD, BSWAP)とオペランドで構成されます。
    • アセンブラ: アセンブリ言語で書かれたソースコードを、CPUが直接実行できる機械語(バイナリコード)に変換するプログラムです。Go言語のツールチェインでは、cmd/6aがx86-64アーキテクチャ向けのアセンブラに相当します。
  • リンカ:
    • リンカ: アセンブラによって生成された複数のオブジェクトファイル(機械語に変換されたコード)やライブラリを結合し、実行可能なプログラムを生成するプログラムです。Go言語のツールチェインでは、cmd/6lがx86-64アーキテクチャ向けのリンカに相当します。リンカは、命令のオペコード(機械語表現)を解決し、最終的な実行ファイルに配置する役割も担います。
  • バイトスワップ (Byte Swap):
    • バイトスワップとは、マルチバイトデータ(例: 32ビット整数、64ビット整数)のバイト順序を反転させる操作です。
    • エンディアン: コンピュータのメモリ上でマルチバイトデータをどのように格納するかを示す方式です。
      • リトルエンディアン: 最下位バイトが最も小さいアドレスに格納されます(例: Intel x86/x64アーキテクチャ)。
      • ビッグエンディアン: 最上位バイトが最も小さいアドレスに格納されます(例: ネットワークバイトオーダー、一部のRISCプロセッサ)。
    • 異なるエンディアンのシステム間でデータを交換する場合、バイトスワップが必要になります。
  • BSWAP 命令:
    • Intel/AMDのx86-64アーキテクチャに存在するCPU命令で、レジスタ内のバイト順序を効率的に反転させます。
    • BSWAPL: 32ビット(Long Word)のバイト順序を反転させます。
    • BSWAPQ: 64ビット(Quad Word)のバイト順序を反転させます。
    • これらの命令は、ソフトウェアでバイトスワップを行うよりもはるかに高速です。
  • Go言語のツールチェイン:
    • Go言語は、独自のコンパイラ、アセンブラ、リンカを含むツールチェインを持っています。これにより、クロスコンパイルが容易になり、特定のアーキテクチャに最適化されたバイナリを生成できます。
    • cmd/6a: x86-64アセンブラ
    • cmd/6l: x86-64リンカ
    • lex.c: アセンブラの字句解析部分。アセンブリ命令のニーモニックを認識し、内部的なトークンに変換します。
    • 6.out.h: リンカが使用する命令の列挙型(enum)定義。各アセンブリ命令に対応する内部的な定数を定義します。
    • optab.c: リンカの命令テーブル。各命令のオペコード(機械語表現)やオペランドの形式、命令の長さなどの情報が定義されています。

技術的詳細

このコミットは、BSWAPLBSWAPQ命令をGoのx86-64アセンブラとリンカに統合するために、以下の3つのファイルに修正を加えています。

  1. src/cmd/6a/lex.c:
    • このファイルは、アセンブラの字句解析器の一部であり、アセンブリ命令のニーモニック(例: MOV, ADD)を認識し、それに対応する内部的な定数(トークン)に変換する役割を担っています。
    • BSWAPLBSWAPQという新しいニーモニックが、それぞれABSWAPLABSWAPQという内部定数にマッピングされるように追加されました。LTYPE1は、これらの命令が特定のオペランドタイプを持つことを示します。
  2. src/cmd/6l/6.out.h:
    • このヘッダファイルは、リンカが使用する命令の列挙型(enum)を定義しています。アセンブラが生成した中間コードで、各命令はここで定義された定数として表現されます。
    • ABSWAPLABSWAPQが、既存の命令リストの末尾近くに追加されました。これにより、リンカがこれらの新しい命令を内部的に識別できるようになります。
  3. src/cmd/6l/optab.c:
    • このファイルは、リンカの命令テーブル(optab)を定義しており、各アセンブリ命令に対応する機械語のオペコード、オペランドの形式、命令の長さなどの詳細情報が含まれています。リンカは、このテーブルを参照して、アセンブリ命令を実際の機械語に変換します。
    • 新しいybswapというオペランドタイプ定義が追加されました。これはBSWAP命令がレジスタオペランドを一つ取ることを示します。
    • optab配列に、ABSWAPLABSWAPQのエントリが追加されました。
      • ABSWAPL: Pxはプレフィックスなし、0x0f,0xc8BSWAP命令のオペコードです。BSWAPLは32ビットレジスタに対して動作します。
      • ABSWAPQ: PwはREX.Wプレフィックス(64ビットオペランドを示す)を意味し、0x0f,0xc8は同様にBSWAP命令のオペコードです。BSWAPQは64ビットレジスタに対して動作します。
    • これにより、リンカはBSWAPLBSWAPQ命令を正しく機械語に変換できるようになります。

これらの変更により、Goのアセンブリコード内でBSWAPLBSWAPQ命令を使用できるようになり、Goプログラムがバイトスワップ操作を必要とする場合に、CPUのネイティブ命令を活用してパフォーマンスを向上させることが可能になります。

コアとなるコードの変更箇所

src/cmd/6a/lex.c

--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -340,6 +340,8 @@ struct
 	"BSRL",		LTYPE3,	ABSRL,
 	"BSRQ",		LTYPE3,	ABSRQ,
 	"BSRW",		LTYPE3,	ABSRW,
+	"BSWAPL",	LTYPE1,	ABSWAPL,
+	"BSWAPQ",	LTYPE1,	ABSWAPQ,
 	"BTCL",		LTYPE3,	ABTCL,
 	"BTCQ",		LTYPE3,	ABTCQ,
 	"BTCW",		LTYPE3,	ABTCW,

src/cmd/6l/6.out.h

--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -743,6 +743,8 @@ enum
 	APREFETCHNTA,
 	
 	AMOVQL,
+	ABSWAPL,
+	ABSWAPQ,
 
 	ALAST
 };

src/cmd/6l/optab.c

--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -302,6 +302,11 @@ uchar	ypopl[] =
 	Ynone,	Ym,	Zo_m,	2,
 	0
 };
+uchar	ybswap[] =
+{
+	Ynone,	Yrl,	Z_rp,	2,
+	0,
+};
 uchar	yscond[] =
 {
 	Ynone,	Ymb,	Zo_m,	2,
@@ -641,6 +646,8 @@ Optab optab[] =
 	{ ABSRL,	yml_rl,	Pm, 0xbd },
 	{ ABSRQ,	yml_rl,	Pw, 0x0f,0xbd },
 	{ ABSRW,	yml_rl,	Pq, 0xbd },
+	{ ABSWAPL,	ybswap,	Px, 0x0f,0xc8 },
+	{ ABSWAPQ,	ybswap,	Pw, 0x0f,0xc8 },
 	{ ABTCL,	ybtl,	Pm, 0xba,(07),0xbb },
 	{ ABTCQ,	ybtl,	Pw, 0x0f,0xba,(07),0x0f,0xbb },
 	{ ABTCW,	ybtl,	Pq, 0xba,(07),0xbb },

コアとなるコードの解説

src/cmd/6a/lex.c の変更

  • "BSWAPL", LTYPE1, ABSWAPL,
  • "BSWAPQ", LTYPE1, ABSWAPQ,

これらの行は、アセンブラの字句解析器に新しい命令ニーモニックを登録しています。

  • "BSWAPL""BSWAPQ" は、アセンブリコードで記述される命令の名前です。
  • LTYPE1 は、これらの命令が1つのオペランド(通常はレジスタ)を取ることを示すタイプです。
  • ABSWAPLABSWAPQ は、アセンブラがこれらのニーモニックを内部的に識別するために使用する定数(トークン)です。

これにより、Goのアセンブリソースファイル内でBSWAPLBSWAPQという命令が記述された際に、アセンブラがそれを正しく認識できるようになります。

src/cmd/6l/6.out.h の変更

  • ABSWAPL,
  • ABSWAPQ,

これらの行は、リンカが使用する命令の列挙型enumに、ABSWAPLABSWAPQという新しい定数を追加しています。アセンブラが生成する中間表現では、これらの定数が実際の命令を表すために使用されます。リンカはこの定数を見て、対応する機械語オペコードを生成します。

src/cmd/6l/optab.c の変更

  • uchar ybswap[] = { Ynone, Yrl, Z_rp, 2, 0, };
    • これは、BSWAP命令のオペランドの形式を定義する新しい配列です。
    • Ynone: 最初のオペランドはなし(命令自体がレジスタを暗黙的に操作するため)。
    • Yrl: 2番目のオペランドはレジスタ(r/mフィールドで指定されるレジスタ)。
    • Z_rp: オペコードの形式に関連する情報。
    • 2: 命令のバイト長(オペコードのバイト数)。
    • 0: 終端。
  • { ABSWAPL, ybswap, Px, 0x0f,0xc8 },
  • { ABSWAPQ, ybswap, Pw, 0x0f,0xc8 },

これらの行は、リンカの命令テーブルoptabBSWAPLBSWAPQ命令のエントリを追加しています。

  • ABSWAPLABSWAPQ: 6.out.hで定義された命令の内部定数です。
  • ybswap: 上で定義されたオペランド形式の配列を参照しています。
  • Px: プレフィックスなし。
  • Pw: REX.Wプレフィックス。これは64ビットオペランドを示すために使用されます。BSWAPQは64ビットレジスタを操作するため、このプレフィックスが必要です。
  • 0x0f,0xc8: これらはBSWAP命令の実際の機械語オペコードです。0x0fは2バイトオペコードのプレフィックスで、0xc8BSWAP命令のメインオペコードです。

これらの変更により、リンカはABSWAPLABSWAPQという内部定数を受け取った際に、対応する正しい機械語オペコード(0x0f 0xc8、64ビットの場合はREX.Wプレフィックス付き)を生成できるようになります。

関連リンク

参考にした情報源リンク

  • 上記のGitHubコミットページ
  • Go言語のソースコード(src/cmd/6a/lex.c, src/cmd/6l/6.out.h, src/cmd/6l/optab.c
  • Intel 64 and IA-32 Architectures Software Developer's Manuals (特にVol. 2A: Instruction Set Reference, A-L)
  • アセンブリ言語、リンカ、エンディアンに関する一般的なコンピュータサイエンスの知識。
  • Go言語のツールチェインに関する一般的な知識。
  • Go CL 6209087: https://golang.org/cl/6209087 (コミットメッセージに記載されているChange Listへのリンク)