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

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

このコミットは、Goコンパイラのレジスタ最適化(regopt)フェーズにおける型情報(gotype)の追跡方法に関する変更を扱っています。具体的には、型情報がTYPE命令によって処理されるようになったため、MOV命令に付随する型情報を維持する必要がなくなったことを示しています。これにより、コンパイラのコードが簡素化され、不要な型情報の追跡が削除されました。

コミット

commit aa3efb28f02924a451f2c519794cc473b15b7559
Author: Russ Cox <rsc@golang.org>
Date:   Mon Feb 25 16:11:34 2013 -0500

    cmd/gc: can stop tracking gotype in regopt
    
    Now that the type information is in TYPE instructions
    that are not rewritten by the optimization passes,
    we don't have to try to preserve the type information
    (no longer) attached to MOV instructions.
    
    R=ken2
    CC=golang-dev
    https://golang.org/cl/7402054

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

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

元コミット内容

cmd/gc: can stop tracking gotype in regopt

Now that the type information is in TYPE instructions
that are not rewritten by the optimization passes,
we don't have to try to preserve the type information
(no longer) attached to MOV instructions.

R=ken2
CC=golang-dev
https://golang.org/cl/7402054

変更の背景

この変更の背景には、Goコンパイラの内部における型情報の管理方法の進化があります。以前のGoコンパイラでは、MOV(移動)命令などの一部の命令に、その操作対象のデータの型情報(gotype)が付随していました。これは、コンパイラの最適化パス、特にレジスタ最適化(regopt)の段階で、型情報を保持し、正しく伝播させるために必要でした。

しかし、コンパイラの開発が進むにつれて、型情報をより堅牢かつ効率的に扱うための新しいメカニズムが導入されました。具体的には、型情報がTYPE命令という、最適化パスによって書き換えられない(つまり、その内容が不変である)専用の命令に集約されるようになりました。

この新しいアプローチにより、MOV命令が型情報を保持する必要がなくなりました。TYPE命令が型情報の「真の情報源」となり、最適化フェーズでMOV命令がどのように変更されても、型情報の整合性が保証されるようになったためです。結果として、regoptフェーズでMOV命令に付随するgotypeを追跡し、維持するための複雑なロジックが不要になりました。このコミットは、この冗長になったコードを削除し、コンパイラの保守性と効率性を向上させることを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGoコンパイラの内部構造と概念に関する知識が必要です。

  • Goコンパイラ (cmd/gc): Go言語の公式コンパイラです。ソースコードを機械語に変換する過程で、複数のフェーズ(字句解析、構文解析、型チェック、中間表現生成、最適化、コード生成など)を経ます。
  • 中間表現 (IR): コンパイラがソースコードを直接機械語に変換するのではなく、まず抽象的な中間形式に変換します。Goコンパイラも独自のIRを使用しており、最適化はこのIRに対して行われます。
  • 最適化パス: コンパイラが生成するコードの性能を向上させるために適用される一連の変換処理です。例えば、不要なコードの削除、レジスタ割り当て、ループ最適化などがあります。
  • レジスタ最適化 (regopt): コンパイラの最適化パスの一つで、プログラムの変数をCPUのレジスタに効率的に割り当てることを目的とします。レジスタはメモリよりもアクセスが高速なため、レジスタを最大限に活用することでプログラムの実行速度が向上します。このフェーズでは、命令の並べ替えや変換が行われることがあります。
  • gotype: Goコンパイラ内部で、Go言語の型システムにおける型情報を表すために使用される概念です。例えば、intstring、構造体、関数型など、あらゆるGoの型がこれに該当します。コンパイラは、型チェック、メモリレイアウトの決定、コード生成など、様々な段階でこの型情報を使用します。
  • MOV命令: 中間表現やアセンブリ言語において、ある場所(レジスタやメモリ)から別の場所へデータを移動させる命令です。コンパイラの最適化フェーズでは、これらのMOV命令が頻繁に生成、変更、削除されます。
  • TYPE命令: このコミットの文脈で言及されているTYPE命令は、Goコンパイラの内部で型情報を明示的に表現するために導入された新しい種類の中間表現命令であると推測されます。この命令は、最適化パスによってその内容が変更されない(不変である)という特性を持つため、型情報の信頼できる情報源として機能します。これにより、型情報がMOV命令のような他の命令に「付随」する必要がなくなりました。

技術的詳細

このコミットが示す技術的詳細は、Goコンパイラのバックエンド、特にレジスタ最適化フェーズにおける型情報の取り扱いに関する重要な変更点です。

Goコンパイラは、ソースコードを解析し、中間表現(IR)を生成します。このIRは、様々な最適化パスを経て、最終的にターゲットアーキテクチャの機械語に変換されます。レジスタ最適化(regopt)は、この最適化パスの一部であり、変数を効率的にレジスタに割り当てることで、生成されるコードのパフォーマンスを向上させます。

以前のGoコンパイラでは、MOV命令のようなデータ移動を伴う命令が、その操作対象のデータのgotype(Goの型情報)を保持していました。これは、regoptのような最適化パスが命令を変換したり、再配置したりする際に、型情報が失われたり、誤って伝播されたりしないようにするためでした。しかし、このアプローチにはいくつかの課題がありました。

  1. 複雑性: MOV命令が型情報を持つことで、regoptは命令の変換と同時に型情報の整合性も維持する必要がありました。これは、最適化ロジックを複雑にし、バグの温床となる可能性がありました。
  2. 冗長性: 型情報は、プログラムの他の部分(例えば、変数の定義や型チェックの段階)でも既に利用可能でした。MOV命令に型情報を重複して持たせることは、ある種の冗長性をもたらしていました。

このコミットの変更は、Goコンパイラが型情報をTYPE命令という新しい、より洗練された方法で管理するようになった結果です。TYPE命令は、最適化パスによってその内容が書き換えられないという特性を持っています。これは、型情報が一度TYPE命令として表現されると、その情報はコンパイラの後のフェーズで不変であることを意味します。

この新しい設計により、MOV命令はもはやgotypeを保持する必要がなくなりました。型情報はTYPE命令によって確実に表現され、最適化パスがMOV命令をどのように操作しても、型情報の正確性はTYPE命令によって保証されます。

結果として、regoptフェーズでは、MOV命令からgotypeを明示的に追跡し、維持するためのコードが不要になりました。これは、コンパイラのコードベースを簡素化し、レジスタ最適化のロジックをよりクリーンで理解しやすいものにするとともに、潜在的なバグのリスクを低減します。

具体的には、src/cmd/5g/reg.csrc/cmd/6g/reg.csrc/cmd/8g/reg.c(それぞれARM、x86-64、x86アーキテクチャ向けのレジスタ最適化コード)内のmkvar関数やaddmove関数から、v->gotype = a->gotype;のようなgotypeをコピーまたは設定する行が削除されています。また、src/cmd/gc/go.hからは、Var構造体からSym* gotype;フィールドが削除されています。これは、Var構造体がもはやgotypeを直接保持する必要がないことを示しています。

この変更は、Goコンパイラの内部設計におけるクリーンアップと効率化の一環であり、コンパイラの堅牢性と保守性を向上させるものです。

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

このコミットでは、主に以下のファイルからgotypeに関連するコードが削除されています。

  • src/cmd/5g/reg.c (ARMアーキテクチャ向け)
  • src/cmd/6g/reg.c (x86-64アーキテクチャ向け)
  • src/cmd/8g/reg.c (x86アーキテクチャ向け)
  • src/cmd/gc/go.h (Goコンパイラの共通ヘッダ)

具体的な変更箇所は以下の通りです。

src/cmd/5g/reg.c

--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -1012,7 +1012,6 @@ mkvar(Reg *r, Adr *a)\n \tv = var+i;\n \tv->offset = o;\n \tv->name = n;\n-//\tv->gotype = a->gotype;\n \tv->etype = et;\n \tv->width = w;\n \tv->addr = flag;\t\t// funny punning

mkvar関数内で、v->gotype = a->gotype; の行がコメントアウト(実質的に削除)されています。

src/cmd/6g/reg.c

--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -872,7 +872,6 @@ addmove(Reg *r, int bn, int rn, int f)\n \ta->offset = v->offset;\n \ta->etype = v->etype;\n \ta->type = v->name;\n-\ta->gotype = v->gotype;\n \ta->node = v->node;\n \ta->sym = v->node->sym;\n \n@@ -1056,7 +1055,6 @@ mkvar(Reg *r, Adr *a)\n \tv = var+i;\n \tv->offset = o;\n \tv->name = n;\n-\tv->gotype = a->gotype;\n \tv->etype = et;\n \tv->width = w;\n \tv->addr = flag;\t\t// funny punning

addmove関数内で a->gotype = v->gotype; の行が削除されています。 mkvar関数内で v->gotype = a->gotype; の行が削除されています。

src/cmd/8g/reg.c

--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -806,7 +806,6 @@ addmove(Reg *r, int bn, int rn, int f)\n \ta->offset = v->offset;\n \ta->etype = v->etype;\n \ta->type = v->name;\n-\ta->gotype = v->gotype;\n \ta->node = v->node;\n \ta->sym = v->node->sym;\n \n@@ -984,7 +983,6 @@ mkvar(Reg *r, Adr *a)\n \tv = var+i;\n \tv->offset = o;\n \tv->name = n;\n-\tv->gotype = a->gotype;\n \tv->etype = et;\n \tv->width = w;\n \tv->addr = flag;\t\t// funny punning

addmove関数内で a->gotype = v->gotype; の行が削除されています。 mkvar関数内で v->gotype = a->gotype; の行が削除されています。

src/cmd/gc/go.h

--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -695,7 +695,6 @@ typedef	struct	Var	Var;\n struct	Var\n {\n \tvlong	offset;\n-\tSym*	gotype;\n \tNode*	node;\n \tint	width;\n \tchar	name;

Var構造体から Sym* gotype; フィールドが削除されています。

コアとなるコードの解説

これらの変更は、Goコンパイラのレジスタ最適化フェーズにおいて、gotype(Goの型情報)の追跡が不要になったことを反映しています。

  • src/cmd/{5,6,8}g/reg.c からの gotype 関連行の削除: mkvar関数とaddmove関数は、レジスタ最適化の過程で変数やアドレスの情報を管理するために使用されます。以前は、これらの関数内でgotypeフィールドがVar構造体やAdr構造体間でコピーまたは設定されていました。これは、MOV命令が型情報を保持する必要があったためです。しかし、型情報がTYPE命令によって一元的に管理されるようになったため、これらのreg.cファイル内のgotypeのコピーや設定は冗長となり、削除されました。これにより、レジスタ最適化のロジックが簡素化され、型情報の伝播に関する懸念が軽減されます。

  • src/cmd/gc/go.h からの Var 構造体における gotype フィールドの削除: go.hはGoコンパイラの共通ヘッダファイルであり、Var構造体はコンパイラ内部で変数を表現するために使用されます。この構造体からSym* gotype;フィールドが削除されたことは、Var構造体がもはや型情報を直接保持する必要がないことを意味します。これは、型情報がTYPE命令という別のメカニズムによって確実に利用可能になったためです。この変更は、コンパイラのデータ構造をクリーンアップし、型情報の責任をTYPE命令に完全に移管するものです。

これらの変更は、Goコンパイラの内部設計が進化し、型情報の管理がより効率的かつ堅牢になったことを明確に示しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Goコンパイラの内部構造に関する詳細なドキュメントは公開されていないため、一般的なコンパイラの概念とGoのソースコードから推測)
  • 一般的なコンパイラ最適化に関する資料 (レジスタ割り当て、中間表現など)
  • Go言語のソースコード (特にsrc/cmd/gcディレクトリ内のファイル)
  • Go言語のGerrit Code Reviewシステム (CL 7402054の議論や関連する変更履歴)
  • Russ Cox氏のGoに関するブログ記事や講演 (Goコンパイラの設計思想や進化に関する情報)
  • Go言語のIssue Tracker (関連するバグ報告や機能要求)
  • Stack Overflowや技術ブログ (Goコンパイラの内部に関するコミュニティの議論)