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

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

このコミットは、Goコンパイラのcmd/6g(64-bit x86アーキテクチャ向けコンパイラ)におけるレジスタ割り当てロジックの変更に関するものです。具体的には、src/cmd/6g/reg.cファイルが修正されています。

コミット

cmd/6g: allow use of R14, R15 now

We stopped reserving them in 2009 or so.

R=ken
CC=golang-dev
https://golang.org/cl/6215061

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

https://github.com/golang/go/commit/8f8640a057f813e0238b6d3a77643ac07b52f56b

元コミット内容

cmd/6g: allow use of R14, R15 now

このコミットは、Goコンパイラのcmd/6gにおいて、x86-64アーキテクチャのレジスタR14およびR15の使用を許可するように変更するものです。コミットメッセージには「2009年頃からそれらを予約するのをやめた」とあり、以前は特定の目的のために予約されていたこれらのレジスタが、もはや予約の必要がないため、コンパイラが自由に利用できるようにするという意図が示されています。

変更の背景

Go言語の初期のコンパイラであるcmd/6gは、64-bit x86 (amd64) アーキテクチャをターゲットとしていました。Goの呼び出し規約は、特にGo 1.17でレジスタベースの呼び出し規約が導入されるまで、主にスタックベースでした。スタックベースのモデルでは、関数引数や戻り値はスタックを介して渡され、レジスタは主に一時的な計算やスクラッチ領域として使用されました。

x86-64アーキテクチャには、R8からR15までの拡張レジスタセットが含まれており、R14とR15も汎用64ビットレジスタです。Goのコンパイラは、これらのレジスタの一部を特定の内部目的のために予約したり、使用を制限したりすることがありました。コミットメッセージにある「2009年頃からそれらを予約するのをやめた」という記述は、Goコンパイラの開発過程で、R14とR15に対する特定の予約や制限が不要になったことを示唆しています。

この変更の背景には、コンパイラのレジスタ割り当ての効率化と、利用可能なハードウェアリソース(レジスタ)を最大限に活用するという目的があります。以前の予約が不要になったことで、コンパイラはより多くのレジスタを自由に利用できるようになり、生成されるコードのパフォーマンス向上に寄与する可能性があります。

前提知識の解説

Goコンパイラ (cmd/6g)

cmd/6gは、Go言語の初期のコンパイラツールチェーンの一部であり、64-bit x86 (amd64) アーキテクチャ向けのGoプログラムをコンパイルするために使用されていました。Goのコンパイラは、独自のバックエンドとレジスタ割り当てアルゴリズム(線形スキャンレジスタ割り当てのバリアント)を使用しており、高速なコンパイル時間を実現しています。

レジスタ割り当て

レジスタ割り当ては、コンパイラの重要な最適化フェーズの一つです。プログラムの実行中に頻繁にアクセスされる変数を、CPUの高速なレジスタに割り当てることで、メモリへのアクセスを減らし、プログラムの実行速度を向上させます。コンパイラは、仮想レジスタ(無限にあると仮定される)を、ターゲットアーキテクチャの限られた物理レジスタにマッピングします。

x86-64アーキテクチャのレジスタ (R14, R15)

x86-64(AMD64)アーキテクチャは、Intel 64とも呼ばれ、64ビットの汎用レジスタを提供します。R14とR15は、R8からR15までの拡張レジスタセットの一部であり、汎用レジスタとして利用可能です。Goの初期のスタックベースの呼び出し規約では、R15はスタックフレームを指す特別な役割を持つことがありましたが、R14には特定の固定された意味はありませんでした。これらのレジスタは、コンパイラが一時的な計算のために使用できるスクラッチレジスタとして機能します。

D_R13, D_R15, exregoffset, BtoR

これらはGoコンパイラの内部で使用される定数や関数です。

  • D_R13, D_R15: これらは、Goコンパイラがレジスタを識別するために使用する内部的な定数であると考えられます。D_AXから始まる一連の定数の一部で、特定のレジスタに対応するオフセットやインデックスを示します。
  • exregoffset: reg.cファイル内のregopt関数で使用される変数で、"external registers offset"(外部レジスタのオフセット)を意味すると考えられます。これは、コンパイラのレジスタ割り当てアルゴリズムが、どのレジスタまでを自由に割り当て可能と見なすかの境界を定義するために使用されます。この値より大きいレジスタは、何らかの理由で予約されているか、コンパイラが直接割り当てないレジスタとして扱われる可能性があります。
  • BtoR: reg.cファイル内の関数で、"Bit to Register"(ビットからレジスタへ)を意味すると考えられます。この関数は、レジスタのビットマスク表現(どのレジスタが使用可能かを示すビット列)を受け取り、対応するレジスタ番号(または内部的なレジスタ識別子)を返す役割を担います。レジスタ割り当ての際に、利用可能なレジスタの集合を効率的に扱うために使用されます。

技術的詳細

このコミットの技術的な核心は、Goコンパイラのレジスタ割り当てロジックが、R14とR15レジスタを汎用レジスタとして利用できるように変更された点にあります。

  1. exregoffsetの変更:

    • 変更前: exregoffset = D_R13;
    • 変更後: exregoffset = D_R15; この変更は、コンパイラのレジスタ割り当てアルゴリズムが、D_R13(R13レジスタに対応する内部定数)までではなく、D_R15(R15レジスタに対応する内部定数)までを自由に割り当て可能なレジスタとして扱うようになったことを意味します。これにより、以前は「外部」または予約済みと見なされていたR14とR15が、コンパイラのレジスタ割り当ての対象に含まれるようになります。
  2. BtoR関数のビットマスクの変更:

    • 変更前: b &= 0x3fffL; // no R14 or R15
    • 変更後: b &= 0xffffL; BtoR関数は、レジスタのビットマスクを処理し、レジスタ番号に変換します。
    • 0x3fffLは16進数で、バイナリでは0011 1111 1111 1111です。このマスクは、R14とR15に対応するビット(通常、レジスタ番号が大きいほどビット位置も高くなる)をゼロにすることで、これらのレジスタが選択されないようにしていました。コメントにも「no R14 or R15」と明記されています。
    • 0xffffLは16進数で、バイナリでは1111 1111 1111 1111です。このマスクは、すべての下位ビットを保持するため、R14とR15に対応するビットも含まれるようになります。これにより、BtoR関数がレジスタのビットマスクを処理する際に、R14とR15が有効なレジスタとして認識されるようになります。

これらの変更は、GoコンパイラがR14とR15を、他の汎用レジスタと同様に、コード生成時のレジスタ割り当ての候補として考慮するようになったことを明確に示しています。これにより、コンパイラはより多くのレジスタを利用して、より効率的なコードを生成できる可能性が高まります。

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

src/cmd/6g/reg.cファイルにおいて、以下の2箇所が変更されています。

--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -164,7 +164,7 @@ regopt(Prog *firstp)
 
  if(first) {
  	fmtinstall('Q', Qconv);
- 	exregoffset = D_R13;	// R14,R15 are external
+ 	exregoffset = D_R15;
  	first = 0;
  }
 
@@ -1577,7 +1577,7 @@ RtoB(int r)
 int
 BtoR(int32 b)
 {
- 	b &= 0x3fffL;		// no R14 or R15
+ 	b &= 0xffffL;
  	if(b == 0)
  		return 0;
  	return bitno(b) + D_AX;

コアとなるコードの解説

  1. regopt関数内のexregoffsetの変更:

    • regopt関数は、Goコンパイラのレジスタ最適化パスの一部であると考えられます。
    • exregoffset = D_R13; から exregoffset = D_R15; への変更は、コンパイラがレジスタ割り当てを行う際に、R14とR15を「外部」または予約済みレジスタのリストから除外し、通常の汎用レジスタとして扱えるようにする設定変更です。これにより、コンパイラはこれらのレジスタを自由に利用できるようになります。
  2. BtoR関数内のビットマスクの変更:

    • BtoR関数は、レジスタのビットマスク表現をレジスタ番号に変換するユーティリティ関数です。
    • b &= 0x3fffL; から b &= 0xffffL; への変更は、R14とR15に対応するビットが、レジスタ選択の際にマスクによって除外されないようにするためのものです。
      • 0x3fffLは、R14とR15に対応するビットを強制的に0にするマスクでした。これは、これらのレジスタが使用されないことを保証していました。
      • 0xffffLは、すべてのビットを保持するマスクであり、R14とR15に対応するビットも有効なものとして扱われるようになります。
    • この変更により、BtoR関数は、R14とR15がビットマスクで指定された場合に、それらを有効なレジスタとして正しく認識し、対応するレジスタ番号を返すことができるようになります。

これらの変更は相互に補完し合い、GoコンパイラがR14とR15レジスタをレジスタ割り当ての対象として含めるための、内部的なロジックの調整を行っています。

関連リンク

参考にした情報源リンク