[インデックス 10222] ファイルの概要
コミット
- コミットハッシュ:
1738dc0e71b0a0356f5f88737c8b10d92b619063
- 作者: Russ Cox rsc@golang.org
- コミット日時: 2011年11月3日 木曜日 11:32:37 -0400
- 変更ファイル:
src/cmd/8a/lex.c
(1ファイル変更) - 変更概要: 2行追加、2行削除
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1738dc0e71b0a0356f5f88737c8b10d92b619063
元コミット内容
8a: fix IMULL grammar
R=ken2
CC=golang-dev
https://golang.org/cl/5298091
変更の背景
このコミットは、Go言語のツールチェーンの一部である8a
アセンブラにおけるIMULL
命令の文法(grammar)の誤りを修正することを目的としています。8a
は、Plan 9アセンブラの構文を採用したGo言語のx86アーキテクチャ向けアセンブラです。
IMULL
は、x86アーキテクチャにおける符号付き整数乗算命令です。アセンブラが特定の命令を正しく解釈し、機械語に変換するためには、その命令の引数(オペランド)の型や数、並び順など、厳密な文法規則に従って記述されている必要があります。
このコミットが行われた2011年当時、Go言語はまだ比較的新しい言語であり、そのツールチェーンも活発に開発・改善が行われていました。アセンブラのような低レベルのツールにおける文法上のバグは、コンパイルエラーや不正なコード生成につながるため、早期の修正が求められます。
具体的には、IMULL
およびIMULW
命令が、アセンブラの字句解析器(lexer)または構文解析器(parser)において、誤った型として認識されていた可能性があります。この誤認識が、特定のコードパターンでコンパイルエラーを引き起こしたり、意図しない動作を招いたりする原因となっていたと考えられます。
前提知識の解説
Go言語のツールチェーンと8a
アセンブラ
Go言語は、コンパイラ、リンカ、アセンブラなどを含む独自のツールチェーンを持っています。8a
は、Go言語のツールチェーンに含まれるアセンブラの一つで、x86(32ビット)アーキテクチャ向けのコードを生成します。Go言語の標準ライブラリやランタイムの一部は、パフォーマンスが要求される箇所や、特定のハードウェア機能にアクセスするためにアセンブリ言語で記述されており、これらのアセンブリコードをコンパイルするために8a
のようなアセンブラが使用されます。
アセンブラ (Assembler)
アセンブラは、人間が記述したアセンブリ言語のソースコードを、コンピュータが直接実行できる機械語(バイナリコード)に変換するプログラムです。アセンブリ言語は、CPUの命令セットに1対1で対応する低レベル言語であり、ハードウェアを直接制御したり、非常に高速な処理を実現したりする際に用いられます。
x86アーキテクチャ
x86は、Intelが開発したマイクロプロセッサの命令セットアーキテクチャのファミリーです。PCやサーバーなど、今日の多くのコンピュータで使用されています。x86アーキテクチャには、32ビット版(IA-32)と64ビット版(x64またはAMD64)があります。8a
アセンブラは主に32ビットのx86命令を扱います。
IMULL
命令
IMULL
は、x86アーキテクチャにおける符号付き整数乗算命令です。
IMUL
は "Integer Multiply" の略です。- 最後の
L
は "Long" を意味し、32ビットオペランドに対する操作を示します(W
は "Word" で16ビット、B
は "Byte" で8ビット)。IMULL
命令は、通常、1つ、2つ、または3つのオペランドを取ることができます。 IMULL src
:EAX
レジスタの内容とsrc
オペランドの内容を乗算し、結果をEDX:EAX
(64ビット)に格納します。IMULL src, dest
:dest
オペランドの内容とsrc
オペランドの内容を乗算し、結果をdest
に格納します。IMULL multiplier, src, dest
:src
オペランドの内容とmultiplier
オペランドの内容を乗算し、結果をdest
に格納します。 このコミットでは、IMULL
の「文法」が問題とされているため、アセンブラがこれらのオペランドの組み合わせや型を正しく認識できていなかったことが示唆されます。
文法 (Grammar)
プログラミング言語やアセンブリ言語における文法とは、その言語で有効なプログラムを構成するための規則の集合です。字句解析(lexical analysis)と構文解析(syntactic analysis)の2つの主要な段階があります。
- 字句解析: ソースコードをトークン(意味を持つ最小単位、例: 予約語、識別子、演算子)のストリームに分解します。
- 構文解析: トークンのストリームが言語の文法規則に従っているかを確認し、通常は抽象構文木(AST)を構築します。
このコミットの変更箇所が
lex.c
であることから、字句解析の段階でIMULL
命令に関連するトークンの型定義に問題があった可能性が高いです。
lex.c
lex.c
というファイル名は、一般的に字句解析器(lexer)の実装を含むC言語のソースファイルであることを示唆しています。字句解析器は、ソースコードを読み込み、個々の単語や記号(トークン)に分解する役割を担います。例えば、IMULL
という文字列を「IMULL命令」というトークンとして認識し、そのトークンに適切な型(例: LTYPEI
やLTYPE2
のような内部的な型識別子)を割り当てます。この型が後続の構文解析で利用され、命令の正しい解釈とコード生成に繋がります。
技術的詳細
このコミットの技術的な核心は、src/cmd/8a/lex.c
ファイル内のIMULL
とIMULW
命令の定義において、関連付けられている型がLTYPE2
からLTYPEI
に変更された点です。
src/cmd/8a/lex.c
は、8a
アセンブラの字句解析器の一部であり、アセンブリ命令の文字列を内部的なトークン型にマッピングするテーブルを含んでいます。このテーブルは、アセンブラがソースコードを読み込む際に、各命令がどのような種類(例:オペランドをいくつ取るか、どのような型のオペランドを期待するか)であるかを識別するために使用されます。
元のコードでは、IMULL
とIMULW
はLTYPE2
として定義されていました。
"IMULL", LTYPE2, AIMULL,
"IMULW", LTYPE2, AIMULW,
修正後のコードでは、これらがLTYPEI
に変更されています。
"IMULL", LTYPEI, AIMULL,
"IMULW", LTYPEI, AIMULW,
ここで、LTYPE2
とLTYPEI
が具体的に何を意味するのかを理解することが重要です。Go言語のツールチェーンのソースコードを調査すると、これらのLTYPE
定数は、アセンブラの内部で命令のオペランドの数や種類を分類するために使用されることがわかります。
LTYPE2
: 一般的に、2つのオペランドを取る命令(例:ADDL $1, AX
のようにソースとデスティネーションを持つ命令)に関連付けられる型である可能性が高いです。LTYPEI
:IMUL
命令(符号付き乗算)に特化した型、または特定の種類のオペランド(例: 即値やレジスタ)を扱う命令に特化した型である可能性が高いです。IMUL
命令は、オペランドの数や種類が他の一般的な二項演算命令とは異なる振る舞いをすることがあります(例: 暗黙的にEAX
レジスタを使用する形式など)。
この変更は、IMULL
およびIMULW
命令が、アセンブラの字句解析器によって誤って「2つの一般的なオペランドを持つ命令」として扱われていたのを、「IMUL
命令特有のオペランド規則を持つ命令」として正しく認識させるための修正であると推測されます。これにより、IMULL
命令が持つ多様なオペランド形式(1オペランド、2オペランド、3オペランド形式など)や、特定のレジスタを暗黙的に使用する挙動が、アセンブラによって正確に解析され、適切な機械語が生成されるようになります。
この修正により、IMULL
命令を含むアセンブリコードが、以前は文法エラーとして扱われたり、誤った機械語にコンパイルされたりしていたケースが解消され、Go言語のコンパイラが生成するアセンブリコードや、手書きのアセンブリコードの信頼性が向上しました。
コアとなるコードの変更箇所
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index ca2e2c138d..403669404e 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -313,8 +313,8 @@ struct
"IDIVL", LTYPE2, AIDIVL,
"IDIVW", LTYPE2, AIDIVW,
"IMULB", LTYPE2, AIMULB,
- "IMULL", LTYPE2, AIMULL,
- "IMULW", LTYPE2, AIMULW,
+ "IMULL", LTYPEI, AIMULL,
+ "IMULW", LTYPEI, AIMULW,
"INB", LTYPE0, AINB,
"INL", LTYPE0, AINL,
"INW", LTYPE0, AINW,
コアとなるコードの解説
上記のコードスニペットは、src/cmd/8a/lex.c
ファイル内の命令定義テーブルの一部を示しています。このテーブルは、アセンブリ命令のニーモニック(例: "IMULL")と、それに対応する内部的な型(例: LTYPE2
, LTYPEI
)および命令コード(例: AIMULL
)をマッピングしています。
IMULB
(8ビット符号付き乗算)は引き続きLTYPE2
のままです。これは、IMULB
が他のIMUL
命令とは異なるオペランド規則を持つか、あるいはこのコミットの時点ではIMULB
には文法上の問題がなかったことを示唆しています。IMULL
(32ビット符号付き乗算)とIMULW
(16ビット符号付き乗算)の型がLTYPE2
からLTYPEI
に変更されました。
この変更は、IMULL
とIMULW
命令の字句解析および構文解析の挙動を修正するために行われました。LTYPE2
は一般的な2オペランド命令の型を指すのに対し、LTYPEI
はIMUL
命令特有の複雑なオペランド規則や、暗黙的なレジスタの使用(例: EAX
レジスタ)を正しく処理するための特別な型であると考えられます。
この修正により、8a
アセンブラはIMULL
およびIMULW
命令を、その本来のx86アーキテクチャのセマンティクスに従って正確に解釈できるようになり、アセンブリコードのコンパイル時の文法エラーが解消され、より堅牢なコード生成が可能になりました。
関連リンク
- Go言語のコードレビューシステム (Gerrit) での変更: https://golang.org/cl/5298091
- GitHub上のコミットページ: https://github.com/golang/go/commit/1738dc0e71b0a0356f5f88737c8b10d92b619063
参考にした情報源リンク
- Go言語のソースコード(特に
src/cmd/8a/
ディレクトリ内の関連ファイル) - x86命令セットリファレンス(IMUL命令に関する情報)
- アセンブラの設計と実装に関する一般的な知識
- 字句解析と構文解析に関する情報
- Plan 9アセンブラの構文に関する情報 (具体的なURLは、当時のGo言語のドキュメントやIntelの公式ドキュメントを参照しました。)