[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.7 レジスタとメモリ

以下に、レジスタとメモリへのアクセスを記述する、RTL 式のタイプを示す。

(reg:m n)

小さな整数 n (FIRST_PSEUDO_REGISTER より小さい)に対して、 マシンのレジスタ番号 n、すなわちハードレジスタの 参照であることを意味する。n が大きな値の場合は、 一時的な値か 仮想レジスタを表す。 GCC の戦略としては、まず、このような仮想レジスタが無限個あると仮定して コード生成を行ない、後で、ハードレジスタかメモリ参照への置き換えを行なう。

m は、この参照のマシンモードである。 モードの指定が必要なのは、一般に複数のモードで各レジスタを参照する ことが可能だからである。 例えば、レジスタを一つ取ってみると、そこには全語を入れることができるが、 それを半語やバイトとして参照する命令や、色々な精度の浮動小数点数として 参照する命令もありうるのである。

レジスタをアクセスするモードが一つしかないマシンの場合でも、 モードは常に指定しなければならない。

FIRST_PSEUDO_REGISTER というシンボルはマシン記述により 定義される。というのは、あるマシンのハードレジスタの数は そのマシンの不変の特徴だからである。ただ、マシンのレジスタが全て 汎用レジスタである必要はない。 データの格納に使える全てのマシンレジスタは、ハードレジスタ番号が 与えられる。たとえ、それらのレジスタが特定の命令でしか使えなかったり、 特定の型のデータしか保持できなくても。

ハードレジスタは一つの関数の中でも色々なモードでアクセスされる。 しかし、疑似レジスタにはそれぞれ自然なモードが与えられており、 そのモードでしかアクセスされない。 疑似レジスタを自然なモード以外のモードでアクセスするのを記述する 必要があるときは、subreg 式が使われる。

1ワードより多くのデータを指定するマシンモードを持つ reg 式は、 実際には幾つかの連続するレジスタを表す事がある。 そのレジスタ番号が、ある一個のハードウェアレジスタを指定するだけでなく、 実際には、その指定されたレジスタから始まる、幾つかの連続した ハードウェアレジスタ群を表している。

関数 RTL コードで使われている疑似レジスタ番号はそれぞれ、 一意的な reg 式で表現される。

FIRST_VIRTUAL_REGISTER から LAST_VIRTUAL_REGISTER までの 範囲の疑似レジスタ番号のうちいくつかは、 RTL 生成過程にしか現れず、最適化過程の前に削除される。 こういう疑似レジスタ番号は、それを含む関数についての RTL 生成が 完了するまでは決定できないスタックフレーム中の位置を表す。 以下の仮想レジスタ番号が定義されている。

VIRTUAL_INCOMING_ARGS_REGNUM

スタック渡しされた入力引数の先頭のワードを指し示す。 通常、これらの引数は呼びだし側によって置かれるが、 呼び出された側が、以前にレジスタで渡された引数の幾つかを プッシュすることもありうる。

RTL が完了した時点で、この仮想レジスタは、 ARG_POINTER_REGNUM で 指定されるレジスタと FIRST_PARM_OFFSET の値の和に置き換えられる。

VIRTUAL_STACK_VARS_REGNUM

FRAME_GROWS_DOWNWARD が定義されていれば、このマクロは スタック上の先頭の変数のすぐ上を指す。 FRAME_GROWS_DOWNWARD が定義されていない場合は、 スタック上の先頭の変数そのものを指す。

VIRTUAL_STACK_VARS_REGNUM は、FRAME_POINTER_REGNUM で 指定されるレジスタと STARTING_FRAME_OFFSET の値の和で置き換えられる。

VIRTUAL_STACK_DYNAMIC_REGNUM

これは、必要とするメモリ量の分だけスタックポインタの調整が行なわれた直後の、 スタック上に動的に確保されたメモリの位置を指す。

この仮想レジスタは、STACK_POINTER_REGNUM で指定されるレジスタと STACK_DYNAMIC_OFFSET の値の和に置き換えられる。

VIRTUAL_OUTGOING_ARGS_REGNUM

スタックが前もってプッシュされたときに、出力引数が書き込まれるべき スタック上の位置を指す。 (push insn を使ってプッシュされる引数は常に STACK_POINTER_REGNUM を 使うべきである。)

この仮想レジスタは、STACK_POINTER_REGNUM で指定されるレジスタと STACK_POINTER_OFFSET の値の和に置き換えられる。

(subreg:m reg wordnum)

subreg 式は、マシンに取って自然なモード以外のモードにある レジスタ、あるいは実際には複数のレジスタを参照する複数ワードの reg のうちの一つのレジスタを参照するのに使われる。

疑似レジスタにはそれぞれ自然なモードがある。 その自然なモードとは異なるモードでの操作が必要な場合、例えば、 一個のバイトを保持している疑似レジスタに対してフルワードの移動命令を 行なう場合は、その疑似レジスタは subreg の中に収まって いなければならない。この例の場合は、wordnum は 0 である。

m は普通は少なくとも reg のモードの幅しかなく、 その場合、reg のビットのうち m に入っているものだけを 考えれば良い。

場合によっては、m は reg のモードよりも広い。 そういう subreg 式は、病的と呼ばれることがある。 このような式は、より広いモードのオブジェクトを参照したいが、 付加的なビットがどういう値を持っているかは気にしないという場合に 使われる。 再ロードパスは、病的な参照はハードレジスタに対してのみ作られることを 保証する。

subreg の別の使い方は、複数のレジスタからなる値から個々のレジスタを 取り出すことである。DImode や TImode の様なマシンモードは、 一語より長い値、つまり通常二つ以上のレジスタを必要とする値である可能性が ある。こういうレジスタの一つを参照するには、subreg をモード SImode で使い、wordnum でどのレジスタかを指定する。

病的でない subreg に格納すると、subreg と同じワードに 属するビットに予期できない結果を生ずる。 この手抜きにより、そういう命令に対して効率の良いコードを生成するのが 用意になる。 subreg の外側の全ビットを保存する命令を表現するには、 subreg を strict_low_part で囲めば良い。

コンパイル時のパラメータである WORDS_BIG_ENDIAN が 1 に設定 されていれば、ワード番号 0 が最上位部であることを指示する。 1 でなければ、ワード番号 0 は最下位部を指示する。

ターゲットによっては、FLOAT_WORDS_BIG_ENDIAN と WORDS_BIG_ENDIAN が一致しないものが 2、3ある。 だが、GCC のほとんどの部分は、浮動小数点値を、整数値と同じエンディアン であるとして取り扱っている。これがうまく働くのは、単に、それらを 整数値の集まりとして扱っているからである。‘real.c’ と 実行時ライブラリだけが、FLOAT_WORDS_BIG_ENDIAN に注意している。

結合パスと再ロードパスの間で、第一引数が reg ではなく mem になっている、病的な subreg が発生する可能性がある。 また、再ロードパスの後では、mem を含む病的な subreg が 発生する可能性があり、通常、mem が疑似レジスタを置き換えたスタック スロットである場合に起きる。

DFmode の値を subreg を使って SFmode で参照するのは 正しくないことに注意。 マシンによっては、DFmode の値の上位部分が 単精度浮動小数点数値と同じフォーマットでない場合がある。

また、一個のハードレジスタにある複数ワードの値のうちの一ワードを アクセスすることは、その値が大きさから期待されるよりも少ないレジスタで 保持できるときは、正しくない。 例えば、32ビットマシンでは、浮動小数点レジスタは一個の DFmode の 値全体を保持できる。レジスタ 10 がそのようなレジスタなら、 (subreg:SI (reg:DF 10) 1) は正しくない。なぜなら、 そのような参照を一個のマシンレジスタに変換する方法がないからである。 再ロードパスは、subreg 式がこのような形式になるのを抑止する。

subreg 式の先頭のオペランドは SUBREG_REG マクロで、 第二オペランドは SUBREG_WORD マクロで参照する。

(scratch:m)

一個の命令の実行に必要とされ、それ以降は使われないスクラッチレジスタを 表す。 局所レジスタ確保か再ロードパスのどちらかにより、reg に変換される。

scratch は、普通は clobber 演算中に存在する (see section 副作用式)。

(cc0)

条件コードレジスタを参照する。オペランドは無く、マシンモードも持たない。 使い方は以下の二通りがある。

コード cc0 の式オブジェクトはただ一つだけ存在する。 変数 cc0_rtx の値である。 コード cc0 の式を作りだそうとすると必ず cc0_rtx が 返ってくる。

命令が暗黙のうちに条件コードを設定する可能性がある。 多くのマシンでは、ほぼ全ての命令が計算したり、格納した値に基づいて 条件コードを設定する。こういう動作を RTL に明示的に記録する必要は ない。というのは、マシン記述に、その命令が条件コードを設定することを 認識するための指示が含まれているからである(マクロ NOTICE_UPDATE_CC を使う)。See section 条件コードステータス。 条件コードを設定することだけを目的とする命令、そして 条件コードを使用する命令だけが、(cc0) を書く必要がある。

マシンによっては、条件コードレジスタにレジスタ番号が与えられ、 reg が (cc0) の代わりに使われる。 条件コードを書き換える命令がほんの一部の命令に限られるなら、 このアプローチが望ましい。 また別のマシンでは、条件コードを汎用レジスタに格納する。 その場合は疑似レジスタを使うべきである。

Sparc や RS/6000 のようなマシンでは、二種類の算術演算命令のセットがある。 一つのセットは条件コードを設定し、もう一つは設定しない。 このような場合を扱う最も良い方法は、通常は、条件コードを設定しない 命令を生成し、算術演算の実行と条件コードレジスタ(この場合は (cc0) ではない)の設定の両方を行なうパターンを作ることである。 例としては、‘sparc.md’ で ‘addcc’ や ‘andcc’ を 探してみて欲しい。

(pc)

プログラムカウンタを表す。 オペランドは取らず、マシンモードも持たなくて良い。 (pc) が使えるのは、分岐命令の特定の文脈においてだけである。

コードが pc である式オブジェクトはただ一つである。 変数 pc_rtx の値である。 コードが pc の式を作ろうとすると返ってくるのは pc_rtx になる。

分岐を行なわない命令は全て、プログラムカウンタをインクリメントすることに より暗黙のうちに変更する。しかし、このことを RTL に記述する必要はない。

(mem:m addr)

この RTX は、式 addr で表されるアドレスの主記憶への参照を 表す。m はメモリの、アクセスされる単位の大きさを表す。

(addressof:m reg)

この RTX はレジスタ reg のアドレスを要求することを表す。 モードは常に Pmode である。 CSE のフェーズの後で関数内に addressof 式がどんなものであれ 残っていれば、reg は強制的にスタックに置かれ、addressof 式は、 そのスタックスロットのアドレスを表す plus 式で置き換えられる。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html 1.78.