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

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

このコミットは、Go言語のARMアーキテクチャ向けコンパイラ(cmd/5c)、Goコンパイラ(cmd/5g)、およびリンカ(cmd/5l)において、新しい命令であるMOVBSMOVHSを導入するものです。これらの命令は、それぞれ既存のMOVB(バイト移動)とMOVH(ハーフワード移動)の複製として定義され、符号拡張(sign-extension)を伴うデータ移動を行います。コミットメッセージには「コード生成に変更はない」と明記されており、これは既存のコードがこれらの新しい命令を直接生成するわけではないことを示唆しています。

コミット

commit 3670337097dbdc6461af7a3ac38fd2dc784dfecd
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Thu Aug 8 23:28:53 2013 +0200

    cmd/5c, cmd/5g, cmd/5l: introduce MOVBS and MOVHS instructions.
    
    MOVBS and MOVHS are defined as duplicates of MOVB and MOVH,
    and perform sign-extension moving.
    No change is made to code generation.
    
    Update #1837
    
    R=rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/12682043

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

https://github.com/golang/go/commit/3670337097dbdc6461af7a3ac38fd2dc784dfecd

元コミット内容

cmd/5c, cmd/5g, cmd/5l: introduce MOVBS and MOVHS instructions.

MOVBS and MOVHS are defined as duplicates of MOVB and MOVH, and perform sign-extension moving. No change is made to code generation.

Update #1837

変更の背景

この変更の背景には、Go言語のコンパイラとリンカがARMアーキテクチャの命令セットをより正確に、かつ効率的に扱うための改善があります。特に、符号付きのバイト(8ビット)やハーフワード(16ビット)の値を、より大きなレジスタ(通常は32ビット)にロードする際に、正しい符号拡張を行う必要がありました。

既存のMOVB(Move Byte)やMOVH(Move Halfword)命令は、通常、メモリからレジスタへデータを移動する際に、ゼロ拡張(zero-extension)または特定のアーキテクチャのデフォルトの動作を行います。しかし、C言語のような言語では、char型やshort型のような符号付きの小さい整数型をより大きな整数型にキャストする際に、値の符号を保持したまま拡張する「符号拡張」が求められます。

コミットメッセージにあるUpdate #1837は、この変更がGoのIssue 1837に関連していることを示しています。Issue 1837は「cmd/5c: signed char/short loads are not sign-extended」というタイトルで、ARMアーキテクチャにおいて符号付きのcharshort型のロードが正しく符号拡張されていないというバグを報告しています。このバグは、C言語のコードをGoのツールチェーンでコンパイルする際に、予期せぬ値の変更を引き起こす可能性がありました。

このコミットは、既存のMOVBMOVH命令の動作を変更するのではなく、符号拡張を明示的に行うための新しい命令MOVBS(Move Byte Signed)とMOVHS(Move Halfword Signed)を導入することで、この問題を解決しようとしています。これにより、コンパイラは必要に応じてこれらの新しい命令を選択できるようになり、正しい符号拡張が保証されます。

前提知識の解説

1. ARMアーキテクチャとGo言語のツールチェーン

  • ARMアーキテクチャ: ARM(Advanced RISC Machine)は、モバイルデバイスや組み込みシステムで広く使用されているRISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。Go言語は、ARMを含む多くのアーキテクチャをサポートしており、それぞれのアーキテクチャ向けに専用のコンパイラとリンカを持っています。
  • Go言語のツールチェーン: Go言語のコンパイラは、ソースコードを機械語に変換します。このコミットで言及されているcmd/5cはC言語のコンパイラ(Goのツールチェーンの一部としてCgoなどで使用される)、cmd/5gはGo言語のコンパイラ、cmd/5lはリンカです。5というプレフィックスは、Goの初期のバージョンでARMv5アーキテクチャを指す慣例でした。

2. 符号拡張(Sign Extension)とゼロ拡張(Zero Extension)

  • 符号拡張: 符号拡張とは、より小さいビット幅の符号付き数値を、より大きいビット幅のレジスタやメモリ領域にコピーする際に、元の数値の符号(最上位ビット)を保持したまま上位ビットを埋める操作です。例えば、8ビットの符号付き数値0b10000000(-128)を32ビットレジスタに符号拡張すると、0b11111111111111111111111110000000となります。最上位ビットが1(負の数)であるため、上位ビットはすべて1で埋められます。これにより、数値の算術的な値が保持されます。
  • ゼロ拡張: ゼロ拡張とは、より小さいビット幅の数値を、より大きいビット幅のレジスタやメモリ領域にコピーする際に、上位ビットをすべて0で埋める操作です。例えば、8ビットの符号なし数値0b10000000(128)を32ビットレジスタにゼロ拡張すると、0b00000000000000000000000010000000となります。これは符号なし数値やアドレスの移動によく使われます。

3. アセンブリ命令

  • MOVB (Move Byte): バイト(8ビット)データを移動する命令。
  • MOVH (Move Halfword): ハーフワード(16ビット)データを移動する命令。
  • これらの命令が、デフォルトでゼロ拡張を行うか、あるいはアーキテクチャ依存の動作をする場合、符号付きの小さい整数を扱う際に問題が生じることがあります。

技術的詳細

このコミットは、Go言語のARMアーキテクチャ向けコンパイラとリンカの内部実装に深く関わる変更です。

1. 新しい命令の定義

MOVBSMOVHSという新しい命令が、既存のMOVBMOVHの「複製」として定義されています。これは、命令の基本的な動作(バイトまたはハーフワードの移動)は同じですが、符号拡張という特定のセマンティクスを持つことを意味します。

src/cmd/5l/5.out.hファイルでは、これらの新しい命令が列挙型asに追加されています。これは、リンカが認識する命令のリストにこれらが含まれることを示します。

enum    as
    AMODU,

    AMOVB,
    AMOVBS, // 新しく追加
    AMOVBU,
    AMOVH,
    AMOVHS, // 新しく追加
    AMOVHU,
    AMOVW,
    AMOVM,

2. コンパイラ(cmd/5c, cmd/5g)の変更

src/cmd/5c/peep.csrc/cmd/5g/peep.cは、それぞれCコンパイラとGoコンパイラのピーフホール最適化(peephole optimization)に関連するファイルです。ピーフホール最適化は、生成されたアセンブリコードの小さなシーケンスをより効率的なシーケンスに置き換えることで、コードの品質を向上させます。これらのファイルでは、AMOVBSAMOVHSが既存のAMOVBAMOVHと同様に扱われるように、命令のパターンマッチングや処理ロジックが更新されています。

src/cmd/5c/txt.cは、Cコンパイラのコード生成部分です。このファイルでは、C言語のchar型やshort型を扱う際に、デフォルトでAMOVBSAMOVHSを使用するように変更されています。これは、C言語のセマンティクス(符号付き型の符号拡張)に合わせるための重要な変更です。

例えば、gmove関数内で、TCHAR(Cのchar型)を移動する際にAMOVBではなくAMOVBSが選択されるようになっています。

// src/cmd/5c/txt.c
case TCHAR:
-           a = AMOVB;
+           a = AMOVBS;
            break;
// ...
case TSHORT:
-           a = AMOVH;
+           a = AMOVHS;
            break;

しかし、コミットメッセージには「No change is made to code generation.」とあります。これは一見矛盾しているように見えますが、文脈を考慮すると、既存のMOVBMOVH命令を生成するロジック自体には変更がなく、C言語の型システムに基づいて、より適切な符号拡張命令(MOVBS/MOVHS)が選択されるようになった、という意味だと解釈できます。つまり、コンパイラが生成する命令の種類が増えただけで、命令生成の基本的なアルゴリズムや構造は変わっていない、ということです。

3. リンカ(cmd/5l)の変更

src/cmd/5l/asm.cは、リンカのアセンブリコード処理部分です。ここでは、AMOVBSAMOVHSAMOVBAMOVHと同様に、ARM命令のエンコーディングやデコーディングのロジックに追加されています。これにより、リンカはこれらの新しい命令を正しく解釈し、実行可能なバイナリに含めることができるようになります。

src/cmd/5l/optab.cは、リンカの命令テーブルを定義するファイルです。このテーブルには、各命令のオペランドの型、命令の長さ、およびその他の属性が記述されています。MOVBSMOVHSがこのテーブルに追加され、それぞれのオペランドの組み合わせが定義されています。これにより、リンカはこれらの新しい命令を正しく処理するための情報を持ちます。

例えば、optab配列にAMOVBSAMOVHSのエントリが追加されています。

// src/cmd/5l/optab.c
    { AMOVB,        C_REG,  C_NONE, C_REG,          14, 8, 0 },
    { AMOVBS,       C_REG,  C_NONE, C_REG,          14, 8, 0 }, // 新しく追加
    { AMOVBU,       C_REG,  C_NONE, C_REG,          58, 4, 0 },
    { AMOVH,        C_REG,  C_NONE, C_REG,          14, 8, 0 },
    { AMOVHS,       C_REG,  C_NONE, C_REG,          14, 8, 0 }, // 新しく追加

src/cmd/5l/span.cは、リンカの命令スパン(命令の長さの計算)に関連するファイルです。新しい命令が追加されたことで、リンカが命令の長さを正しく計算できるように、このファイルも更新されています。

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

このコミットのコアとなる変更は、主に以下のファイルに集中しています。

  1. src/cmd/5c/txt.c: Cコンパイラがcharshort型を扱う際に、符号拡張を伴うMOVBSMOVHS命令を生成するように変更された点。これにより、C言語のセマンティクスに合致するコードが生成されるようになります。
  2. src/cmd/5l/5.out.h: 新しい命令AMOVBSAMOVHSが命令の列挙型に追加された点。これは、リンカがこれらの命令を認識するための基盤となります。
  3. src/cmd/5l/optab.c: リンカの命令テーブルにMOVBSMOVHSのオペランド定義が追加された点。これにより、リンカはこれらの命令を正しく処理するための詳細な情報を持ちます。
  4. src/cmd/5l/asm.c: リンカがMOVBSMOVHS命令をARMの機械語にエンコード/デコードするロジックが追加・修正された点。

コアとなるコードの解説

src/cmd/5c/txt.c の変更

このファイルでは、gmove関数がGoのCコンパイラにおける主要なコード生成ルーチンの一つであり、異なる型の間のデータ移動を処理します。変更前は、char型(TCHAR)やshort型(TSHORT)の値をレジスタにロードする際に、それぞれAMOVBAMOVH命令を使用していました。これらの命令は、ARMアーキテクチャによってはゼロ拡張を行うか、あるいは符号拡張が保証されない場合があります。

変更後、TCHARに対してはAMOVBS(Move Byte Signed)、TSHORTに対してはAMOVHS(Move Halfword Signed)が明示的に使用されるようになりました。これにより、C言語の標準で定義されている符号付き整数型のセマンティクス、すなわち、より大きな型に変換される際に符号が保持されるという動作が、生成されるアセンブリコードレベルで保証されます。

--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -594,13 +594,13 @@ gmove(Node *f, Node *t)
 		case TDOUBLE:
 			a = AMOVD;
 			break;
 		case TCHAR:
-			a = AMOVB;
+			a = AMOVBS; // 変更点: AMOVB から AMOVBS へ
 			break;
 		case TUCHAR:
 			a = AMOVBU;
 			break;
 		case TSHORT:
-			a = AMOVH;
+			a = AMOVHS; // 変更点: AMOVH から AMOVHS へ
 			break;
 		case TUSHORT:
 			a = AMOVHU;

この変更は、C言語のコードをGoのツールチェーンでコンパイルする際の正確性を向上させる上で非常に重要です。特に、異なるプラットフォーム間での移植性や、C言語とGo言語のコードが混在するCgoのようなシナリオにおいて、予期せぬバグを防ぐのに役立ちます。

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

このファイルは、Goのリンカがサポートする命令とそのオペランドの組み合わせを定義する「命令テーブル」を含んでいます。新しい命令AMOVBSAMOVHSが導入されたため、リンカがこれらの命令を正しく認識し、処理できるように、このテーブルに新しいエントリが追加されました。

各エントリは、命令の種類(as)、ソースオペランドの型(C_REG, C_NONE, C_SAUTOなど)、デスティネーションオペランドの型、命令の長さ、およびその他のフラグを定義します。これにより、リンカはアセンブリコードを解析し、対応する機械語命令を生成する際に、これらの新しい命令を適切に扱うことができます。

--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -95,8 +95,10 @@ Optab	optab[] =
 	{ ACMP,		C_LCON,	C_REG,	C_NONE,		13, 8, 0,	LFROM },
 
 	{ AMOVB,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
+	{ AMOVBS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 }, // 新しいエントリ
 	{ AMOVBU,	C_REG,	C_NONE,	C_REG,		58, 4, 0 },
 	{ AMOVH,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
+	{ AMOVHS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 }, // 新しいエントリ
 	{ AMOVHU,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },

この変更は、リンカが新しい命令を正しく処理するための「レシピ」を提供し、Goのツールチェーン全体でこれらの命令がサポートされるようにするために不可欠です。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特にsrc/cmd/5c, src/cmd/5g, src/cmd/5lディレクトリ内のファイル)
  • ARMアーキテクチャのリファレンスマニュアル (一般的なアセンブリ命令と符号拡張の概念について)
  • Go言語のIssueトラッカー (Issue 1837の詳細について)
  • Go言語のコードレビューシステム (CL 12682043の詳細について)

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

このコミットは、Go言語のARMアーキテクチャ向けコンパイラ(cmd/5c)、Goコンパイラ(cmd/5g)、およびリンカ(cmd/5l)において、新しい命令であるMOVBSMOVHSを導入するものです。これらの命令は、それぞれ既存のMOVB(バイト移動)とMOVH(ハーフワード移動)の複製として定義され、符号拡張(sign-extension)を伴うデータ移動を行います。コミットメッセージには「コード生成に変更はない」と明記されており、これは既存のコードがこれらの新しい命令を直接生成するわけではないことを示唆しています。

コミット

commit 3670337097dbdc6461af7a3ac38fd2dc784dfecd
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Thu Aug 8 23:28:53 2013 +0200

    cmd/5c, cmd/5g, cmd/5l: introduce MOVBS and MOVHS instructions.
    
    MOVBS and MOVHS are defined as duplicates of MOVB and MOVH,
    and perform sign-extension moving.
    No change is made to code generation.
    
    Update #1837
    
    R=rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/12682043

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

https://github.com/golang/go/commit/3670337097dbdc6461af7a3ac38fd2dc784dfecd

元コミット内容

cmd/5c, cmd/5g, cmd/5l: introduce MOVBS and MOVHS instructions.

MOVBS and MOVHS are defined as duplicates of MOVB and MOVH, and perform sign-extension moving. No change is made to code generation.

Update #1837

変更の背景

この変更の背景には、Go言語のコンパイラとリンカがARMアーキテクチャの命令セットをより正確に、かつ効率的に扱うための改善があります。特に、符号付きのバイト(8ビット)やハーフワード(16ビット)の値を、より大きなレジスタ(通常は32ビット)にロードする際に、正しい符号拡張を行う必要がありました。

既存のMOVB(Move Byte)やMOVH(Move Halfword)命令は、通常、メモリからレジスタへデータを移動する際に、ゼロ拡張(zero-extension)または特定のアーキテクチャのデフォルトの動作を行います。しかし、C言語のような言語では、char型やshort型のような符号付きの小さい整数型をより大きな整数型にキャストする際に、値の符号を保持したまま拡張する「符号拡張」が求められます。

コミットメッセージにあるUpdate #1837は、この変更がGoのIssue 1837に関連していることを示しています。Issue 1837は「cmd/5c: signed char/short loads are not sign-extended」というタイトルで、ARMアーキテクチャにおいて符号付きのcharshort型のロードが正しく符号拡張されていないというバグを報告しています。このバグは、C言語のコードをGoのツールチェーンでコンパイルする際に、予期せぬ値の変更を引き起こす可能性がありました。

このコミットは、既存のMOVBMOVH命令の動作を変更するのではなく、符号拡張を明示的に行うための新しい命令MOVBS(Move Byte Signed)とMOVHS(Move Halfword Signed)を導入することで、この問題を解決しようとしています。これにより、コンパイラは必要に応じてこれらの新しい命令を選択できるようになり、正しい符号拡張が保証されます。

前提知識の解説

1. ARMアーキテクチャとGo言語のツールチェーン

  • ARMアーキテクチャ: ARM(Advanced RISC Machine)は、モバイルデバイスや組み込みシステムで広く使用されているRISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。Go言語は、ARMを含む多くのアーキテクチャをサポートしており、それぞれのアーキテクチャ向けに専用のコンパイラとリンカを持っています。
  • Go言語のツールチェーン: Go言語のコンパイラは、ソースコードを機械語に変換します。このコミットで言及されているcmd/5cはC言語のコンパイラ(Goのツールチェーンの一部としてCgoなどで使用される)、cmd/5gはGo言語のコンパイラ、cmd/5lはリンカです。5というプレフィックスは、Goの初期のバージョンでARMv5アーキテクチャを指す慣例でした。

2. 符号拡張(Sign Extension)とゼロ拡張(Zero Extension)

  • 符号拡張: 符号拡張とは、より小さいビット幅の符号付き数値を、より大きいビット幅のレジスタやメモリ領域にコピーする際に、元の数値の符号(最上位ビット)を保持したまま上位ビットを埋める操作です。例えば、8ビットの符号付き数値0b10000000(-128)を32ビットレジスタに符号拡張すると、0b11111111111111111111111110000000となります。最上位ビットが1(負の数)であるため、上位ビットはすべて1で埋められます。これにより、数値の算術的な値が保持されます。
  • ゼロ拡張: ゼロ拡張とは、より小さいビット幅の数値を、より大きいビット幅のレジスタやメモリ領域にコピーする際に、上位ビットをすべて0で埋める操作です。例えば、8ビットの符号なし数値0b10000000(128)を32ビットレジスタにゼロ拡張すると、0b00000000000000000000000010000000となります。これは符号なし数値やアドレスの移動によく使われます。

3. ARMアセンブリにおけるデータ移動命令

ARMアセンブリにおいて、バイトやハーフワードのデータをメモリからレジスタにロードし、拡張する際には、以下のような専用の命令が使用されます。

  • LDRB (Load Register Byte): メモリから1バイトをロードし、レジスタの残りのビットをゼロ拡張します。
  • LDRH (Load Register Halfword): メモリから1ハーフワードをロードし、レジスタの残りのビットをゼロ拡張します。
  • LDRSB (Load Register Signed Byte): メモリから1バイトをロードし、レジスタの残りのビットを符号拡張します。
  • LDRSH (Load Register Signed Halfword): メモリから1ハーフワードをロードし、レジスタの残りのビットを符号拡張します。

また、レジスタ内の値を符号拡張する命令も存在します。

  • SXTB (Sign Extend Byte): レジスタ内のバイト値を32ビットに符号拡張します。
  • SXTH (Sign Extend Halfword): レジスタ内のハーフワード値を32ビットに符号拡張します。

このコミットで導入されるMOVBSMOVHSは、Goのツールチェーン内部でこれらのARM命令に対応する抽象的な命令として定義され、コンパイラがC言語のセマンティクスに沿った正しい符号拡張を行うために利用されます。

技術的詳細

このコミットは、Go言語のARMアーキテクチャ向けコンパイラとリンカの内部実装に深く関わる変更です。

1. 新しい命令の定義

MOVBSMOVHSという新しい命令が、既存のMOVBMOVHの「複製」として定義されています。これは、命令の基本的な動作(バイトまたはハーフワードの移動)は同じですが、符号拡張という特定のセマンティクスを持つことを意味します。

src/cmd/5l/5.out.hファイルでは、これらの新しい命令が列挙型asに追加されています。これは、リンカが認識する命令のリストにこれらが含まれることを示します。

enum    as
    AMODU,

    AMOVB,
    AMOVBS, // 新しく追加
    AMOVBU,
    AMOVH,
    AMOVHS, // 新しく追加
    AMOVHU,
    AMOVW,
    AMOVM,

2. コンパイラ(cmd/5c, cmd/5g)の変更

src/cmd/5c/peep.csrc/cmd/5g/peep.cは、それぞれCコンパイラとGoコンパイラのピーフホール最適化(peephole optimization)に関連するファイルです。ピーフホール最適化は、生成されたアセンブリコードの小さなシーケンスをより効率的なシーケンスに置き換えることで、コードの品質を向上させます。これらのファイルでは、AMOVBSAMOVHSが既存のAMOVBAMOVHと同様に扱われるように、命令のパターンマッチングや処理ロジックが更新されています。

src/cmd/5c/txt.cは、Cコンパイラのコード生成部分です。このファイルでは、C言語のchar型やshort型を扱う際に、デフォルトでAMOVBSAMOVHSを使用するように変更されています。これは、C言語のセマンティクス(符号付き型の符号拡張)に合わせるための重要な変更です。

例えば、gmove関数内で、TCHAR(Cのchar型)を移動する際にAMOVBではなくAMOVBSが選択されるようになっています。

// src/cmd/5c/txt.c
case TCHAR:
-           a = AMOVB;
+           a = AMOVBS;
            break;
// ...
case TSHORT:
-           a = AMOVH;
+           a = AMOVHS;
            break;

しかし、コミットメッセージには「No change is made to code generation.」とあります。これは一見矛盾しているように見えますが、文脈を考慮すると、既存のMOVBMOVH命令を生成するロジック自体には変更がなく、C言語の型システムに基づいて、より適切な符号拡張命令(MOVBS/MOVHS)が選択されるようになった、という意味だと解釈できます。つまり、コンパイラが生成する命令の種類が増えただけで、命令生成の基本的なアルゴリズムや構造は変わっていない、ということです。

3. リンカ(cmd/5l)の変更

src/cmd/5l/asm.cは、リンカのアセンブリコード処理部分です。ここでは、AMOVBSAMOVHSAMOVBAMOVHと同様に、ARM命令のエンコーディングやデコーディングのロジックに追加されています。これにより、リンカはこれらの新しい命令を正しく解釈し、実行可能なバイナリに含めることができるようになります。

src/cmd/5l/optab.cは、リンカの命令テーブルを定義するファイルです。このテーブルには、各命令のオペランドの型、命令の長さ、およびその他の属性が記述されています。MOVBSMOVHSがこのテーブルに追加され、それぞれのオペランドの組み合わせが定義されています。これにより、リンカはこれらの新しい命令を正しく処理するための情報を持ちます。

例えば、optab配列にAMOVBSAMOVHSのエントリが追加されています。

// src/cmd/5l/optab.c
    { AMOVB,        C_REG,  C_NONE, C_REG,          14, 8, 0 },
    { AMOVBS,       C_REG,  C_NONE, C_REG,          14, 8, 0 }, // 新しく追加
    { AMOVBU,       C_REG,  C_NONE, C_REG,          58, 4, 0 },
    { AMOVH,        C_REG,  C_NONE, C_REG,          14, 8, 0 },
    { AMOVHS,       C_REG,  C_NONE, C_REG,          14, 8, 0 }, // 新しく追加

src/cmd/5l/span.cは、リンカの命令スパン(命令の長さの計算)に関連するファイルです。新しい命令が追加されたことで、リンカが命令の長さを正しく計算できるように、このファイルも更新されています。

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

このコミットのコアとなる変更は、主に以下のファイルに集中しています。

  1. src/cmd/5c/txt.c: Cコンパイラがcharshort型を扱う際に、符号拡張を伴うMOVBSMOVHS命令を生成するように変更された点。これにより、C言語のセマンティクスに合致するコードが生成されるようになります。
  2. src/cmd/5l/5.out.h: 新しい命令AMOVBSAMOVHSが命令の列挙型に追加された点。これは、リンカがこれらの命令を認識するための基盤となります。
  3. src/cmd/5l/optab.c: リンカの命令テーブルにMOVBSMOVHSのオペランド定義が追加された点。これにより、リンカはこれらの命令を正しく処理するための詳細な情報を持ちます。
  4. src/cmd/5l/asm.c: リンカがMOVBSMOVHS命令をARMの機械語にエンコード/デコードするロジックが追加・修正された点。

コアとなるコードの解説

src/cmd/5c/txt.c の変更

このファイルでは、gmove関数がGoのCコンパイラにおける主要なコード生成ルーチンの一つであり、異なる型の間のデータ移動を処理します。変更前は、char型(TCHAR)やshort型(TSHORT)の値をレジスタにロードする際に、それぞれAMOVBAMOVH命令を使用していました。これらの命令は、ARMアーキテクチャによってはゼロ拡張を行うか、あるいは符号拡張が保証されない場合があります。

変更後、TCHARに対してはAMOVBS(Move Byte Signed)、TSHORTに対してはAMOVHS(Move Halfword Signed)が明示的に使用されるようになりました。これにより、C言語の標準で定義されている符号付き整数型のセマンティクス、すなわち、より大きな型に変換される際に符号が保持されるという動作が、生成されるアセンブリコードレベルで保証されます。

--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -594,13 +594,13 @@ gmove(Node *f, Node *t)
 		case TDOUBLE:
 			a = AMOVD;
 			break;
 		case TCHAR:
-			a = AMOVB;
+			a = AMOVBS; // 変更点: AMOVB から AMOVBS へ
 			break;
 		case TUCHAR:
 			a = AMOVBU;
 			break;
 		case TSHORT:
-			a = AMOVH;
+			a = AMOVHS; // 変更点: AMOVH から AMOVHS へ
 			break;
 		case TUSHORT:
 			a = AMOVHU;

この変更は、C言語のコードをGoのツールチェーンでコンパイルする際の正確性を向上させる上で非常に重要です。特に、異なるプラットフォーム間での移植性や、C言語とGo言語のコードが混在するCgoのようなシナリオにおいて、予期せぬバグを防ぐのに役立ちます。

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

このファイルは、Goのリンカがサポートする命令とそのオペランドの組み合わせを定義する「命令テーブル」を含んでいます。新しい命令AMOVBSAMOVHSが導入されたため、リンカがこれらの命令を正しく認識し、処理できるように、このテーブルに新しいエントリが追加されました。

各エントリは、命令の種類(as)、ソースオペランドの型(C_REG, C_NONE, C_SAUTOなど)、デスティネーションオペランドの型、命令の長さ、およびその他のフラグを定義します。これにより、リンカはアセンブリコードを解析し、対応する機械語命令を生成する際に、これらの新しい命令を適切に扱うことができます。

--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -95,8 +95,10 @@ Optab	optab[] =
 	{ ACMP,		C_LCON,	C_REG,	C_NONE,		13, 8, 0,	LFROM },
 
 	{ AMOVB,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
+	{ AMOVBS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 }, // 新しいエントリ
 	{ AMOVBU,	C_REG,	C_NONE,	C_REG,		58, 4, 0 },
 	{ AMOVH,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
+	{ AMOVHS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 }, // 新しいエントリ
 	{ AMOVHU,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },

この変更は、リンカが新しい命令を正しく処理するための「レシピ」を提供し、Goのツールチェーン全体でこれらの命令がサポートされるようにするために不可欠です。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特にsrc/cmd/5c, src/cmd/5g, src/cmd/5lディレクトリ内のファイル)
  • ARMアーキテクチャのリファレンスマニュアル (一般的なアセンブリ命令と符号拡張の概念について)
  • Go言語のIssueトラッカー (Issue 1837の詳細について)
  • Go言語のコードレビューシステム (CL 12682043の詳細について)
  • Stack Overflow: ARM assembly LDRB vs LDRSB
  • ARM Developer Documentation: LDRSB, LDRSH