[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
以下に、レジスタとメモリへのアクセスを記述する、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)
が正しく使える文脈は
二つだけである。
代入における代入先(テストおよび比較命令において)として、
および 0 (値がゼロの const_int
、すなわち const0_rtx
である)
との比較を行なう比較演算においてである。
この手法を使う場合、(cc0)
が有効なのは次の二つの文脈だけである。
ソースオペランドが比較演算子である(テストと比較命令では)
代入の目的オペランドとして、もう一つは
(条件分岐の) if_then_else
の最初のオペランドとしてである。
コード 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.