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

16.7 RTL生成用標準パターン名

以下に、RTL 生成パスで意味を持つ命令パターン名の一覧を示す。 ある命令パターンに以下の名前の一つを与えると、RTL 生成パスは、 ある一定の仕事を達成するためにそのパターンを使って良いという ことがわかる。

movm

ここで m は、二文字からなるマシンモード名を小文字で表したもの である。この命令パターンは、指定されたマシンモードのデータを オペランド 1 からオペランド 0 に移動する。 例えば、‘movsi’ は全ワードのデータを移動する。

オペランド 0 が、モードが m より広いレジスタの、モード msubreg であるなら、この命令の効果はモード m に対応する レジスタの一部に指定された値を格納することである。 レジスタの他の部分に対する効果は未定義である。

このクラスのパターンは色々な点で特殊である。 まず第一に、これらの名前はそれぞれ定義されなくてはならない。 なぜなら、データをある場所から他の場所にコピーする方法が 他にはないからである。

第二に、これらのパターンは RTL 生成パスだけで使われるのではない。 再ロードパスにおいても、値をスタックスロットから一時レジスタにコピーする move insn を生成する可能性がある。 その時、オペランドの一つはハードレジスタであり、他の一つは、 レジスタに再ロードされる必要となる可能性があるオペランドである。

このため、このようなオペランドの対が与えられたとき、 このパターンは再ロードを必要とせず、一時レジスタ–オペランド以外のレジスタを 必要としない RTL を生成しなければならない。 例えば、define_expand でそのパターンをサポートするなら、 その場合、define_expandforce_reg や 新しい疑似レジスタを生成するような他の関数は呼び出してはならない

RISCマシンのサブワードモードについても、その機種で メモリからサブワードモードを取り出すのに複数の命令と一時レジスタが 必要なら、この要求は存在する。 この要求を満たすにはどうすれば良いかは ‘spur.md’ を参照のこと。

再ロードの最中、無効なアドレスのメモリ参照がオペランドとして渡される 可能性がある。そういうアドレスは、再ロードパスの後の方で有効なアドレスに 置き換えられる。この場合、そのままでは、そのアドレスに対してはそれを 使うという以外には何も行なわれない。 もしそれがコピーされたとすると、有効なアドレスには置き換えられない。 そういうアドレスを有効なアドレスに変えようとする試みは全く行なわれず、 (change_address のような)そういう処理をする関数も呼ばれない。 general_operand をそのようなアドレスに適用すると失敗することに 注意。

グローバル変数 reload_in_progress(これは必要なら明示的に宣言 しなければならない)を使って、そのような特別な取扱いが必要かどうかを 決定することができる。

再ロードされるオペランドの種類は、マシン記述のその他の部分に依存するが、 RISC 機種では普通はハードレジスタを割り当てることの出来なかった 疑似レジスタに限られる。一方、それ以外の機種では明示的なメモリ参照は 再ロードされる可能性がある。

あるオブジェクトをメモリへ、あるいはメモリから移動するのに、 スクラッチレジスタが必要な場合は、生死解析に先だって gen_reg_rtx を使って割り当てることができる。

再ロード後にスクラッチレジスタが必要になる場合が あるなら、SECONDARY_INPUT_RELOAD_CLASS を定義しなければならない。 また、それらを検出するためにおそらく SECONDARY_OUTPUT_RELOAD_CLASS も定義しなければならない。それから、それらに対する取扱いのために、 ‘reload_inm’ パターンか ‘reload_outm’ パターンを 定義しなければならない。See section レジスタクラス

グローバル変数 no_new_pseudos を使って、新しい疑似レジスタを 作るのが危険かどうかを決定することができる。 この変数がゼロでないときは、gen_reg_rtx を使って新しい疑似レジスタを 割り当てるのは危険である。

movem’ についての制約は、任意のハードレジスタから別の任意の ハードレジスタへの移動を許さなければならない。 ただし、HARD_REGNO_MODE_OK がどちらのレジスタもモード m であることを許し、これらのレジスタのクラスに REGISTER_MOVE_COST を適用した場合に 2 という値が返ってくるという前提がある。

固定小数点値を保持できる任意のレジスタについて、値を出し入れできる 浮動小数点 ‘movm’ 命令をサポートするのは必須である。 なぜなら共用体や構造体(モードは SImodeDImode)は そのようなレジスタに入れることができ、浮動小数点メンバが存在する 可能性があるからである。

また、浮動小数点レジスタから値を出し入れする固定小数点 ‘movm’ 命令も必要である。ただ、残念なことに著者はどうしてそうしたのだったかを 忘れてしまっており、現在でもその通りであるかどうかがわからない。 HARD_REGNO_MODE_OK が浮動小数点レジスタに固定小数点値を 入れるのを拒絶するなら、固定小数点 ‘movm’ 命令の制約は 浮動小数点レジスタに再ロードするのを避けるように定義しなければならない。

reload_inm
reload_outm

movm’ と同様だが、オペランド 0 とオペランド 1 の間で 移動を行なうのにスクラッチレジスタが必要な場合に使われる。 オペランド 2 がそのスクラッチレジスタを記述する。 see section レジスタクラス のマクロ SECONDARY_RELOAD_CLASS の 議論を参照のこと。

movstrictm

movm’ と同様だが、オペランド 0 が、その自然なモードが もっと広いようなレジスタのモード msubreg であるなら、 ‘movstrictm’ 命令は、モード m に属する部分を除いて、 そのレジスタをなんら変更しないことが保証される。

load_multiple

幾つかの連続したメモリ位置から幾つかの連続したレジスタにロードする。 オペランド 0 は連続するレジスタの先頭のレジスタであり、 オペランド 1 は、メモリ位置の先頭であり、オペランド 2 は、 連続するレジスタ数を指定する定数である。

これを定義するのは、ターゲットマシンが実際にこのような命令を持っている 場合に限る。メモリから連続するレジスタへロードするのに最も効率が 良い方法が、一個一個ロードすることであれば、このマクロは定義しては いけない。

マシンによっては、どの連続するレジスタがメモリに格納可能であるか について制限がある。例えば、先頭や末尾のレジスタ番号が特定の ものでなくてはいけないとか、有効なレジスタ数の範囲内でのみ 可能である、などである。 このような制限がある場合は、define_expand(see section コード生成のための RTL 列の定義) を使って、制限が満たされない場合はそのパターンが失敗するようにする。

生成される insn は一個の parallel として書き、その要素は 一個のレジスタを適切なメモリ位置に設定する set とする (また、use あるいは clobber の要素も必要である)。 match_parallel (see section RTL テンプレート)を使って、その insn を 認識する。 この insn パターンの使い方の例としては、‘a29k.md’ と ‘rs6000.md’ を参照のこと。

store_multiple

load_multiple’ と同様だが、複数の連続したレジスタを 連続したメモリ位置に格納する。 オペランド 0 が連続したメモリ位置の先頭で、オペランド 1 が先頭のレジスタ、 オペランド 2 がある定数で、連続するレジスタの数を表す。

addm3

オペランド 2 と 1 を加算し、結果をオペランド 0 に格納する。 オペランドは全てモードが m でなければならない。 2オペランドのマシンでも使用可能である。 その場合は、オペランド 1 とオペランド 0 が同じ位置にあるという制約を 課せば良い。

subm3’, ‘mulm3
divm3’, ‘udivm3’, ‘modm3’, ‘umodm3
sminm3’, ‘smaxm3’, ‘uminm3’, ‘umaxm3
andm3’, ‘iorm3’, ‘xorm3

他の算術演算についても同様である。

mulhisi3

オペランド 1 と 2 を乗算する。どちらもモードは HImode である。 SImode の乗算の結果をオペランド 0 に格納する。

mulqihi3’, ‘mulsidi3

他の幅の、乗算の結果がオペランドの幅よりも大きくなる命令についても 同様である。

umulqihi3’, ‘umulhisi3’, ‘umulsidi3

符号なしの乗算を行なう、乗算の結果がオペランドの幅よりも大きくなる命令に ついても同様である。

mulm3_highpart

オペランド 1 と 2 の符号付き乗算を行なう。モードは m である。 積の上位半分をオペランド 0 に格納する。 積の下位半分は捨てられる。

umulm3_highpart

mulm3_highpart’ と、乗算が符号なしで行なわれる点を 除いて、同じである。

divmodm4

商と剰余の両方を生成する符号付き除算である。 オペランド1 をオペランド 2 で割り、商がオペランド 0 に、 剰余がオペランド 3 に格納される。

商と剰余の両方を生成する命令がある機種では、‘divmodm4’ の パターンを定義し、‘divm3’ と ‘modm3’ の パターンは定義しないようにすること。 これにより、商と剰余の両方を計算するという比較的良くある場合に 最適化が可能になる。

単に商か剰余のどちらかを生成する命令が存在し、両方を生成する命令よりも 効率が良い場合は、‘divmodm4’ の出力ルーチンを、 find_reg_note を呼び出して、商か剰余についての REG_UNUSED ノートを見つけ、適切な命令を生成するように書く。

udivmodm4

divmodm4’ と、除算が符号なしで行なわれる点を除いて、 同じである。

ashlm3

オペランド 1 を、オペランド 2 で指定されたビット数だけ左に 算術シフトし、結果をオペランド 0 に格納する。 ここで、mは、オペランド 0 とオペランド 1 のモードである。 オペランド 2 のモードは、命令パターンにより指定され、コンパイラは 命令を生成する前にオペランドをそのモードに変換する。

ashrm3’, ‘lshrm3’, ‘rotlm3’, ‘rotrm3

その他のシフトとローテート命令群。ashlm3 と同様である。

negm2

オペランド 1 の符号を反転し、その結果をオペランド 0 に格納する。

absm2

オペランド 1 の絶対値をオペランド 0 に格納する。

sqrtm2

オペランド 1 の平方根をオペランド 0 に格納する。

C の組み込み関数 sqrt は、常に C 言語のデータ型 double に対応するモードを使用する。

ffsm2

オペランド 0 に、1 と、オペランド 1 のビットが 1 のうち最下位のものの インデックスを足したものを格納する。 オペランド 1 がゼロなら、ゼロを格納する。 m はオペランド 0 のモードである。オペランド 1 のモードは命令 パターンにより指定され、コンパイラが命令を生成する前にオペランド 1 を そのモードに変換する。

C の組み込み関数 ffs は、C のデータ型 int に 対応するモードを常に使う。

one_cmplm2

オペランド 1 のビット毎の補数をオペランド 0 に格納する。

cmpm

オペランド 0 とオペランド 1 を比較し、条件コードを設定する。 RTL パターンは以下のようにする必要がある。

 
(set (cc0) (compare (match_operand:m 0 …)
                    (match_operand:m 1 …)))
tstm

オペランド 0 とゼロを比較し、条件コードを設定する。 RTL パターンは以下のようにする必要がある。

 
(set (cc0) (match_operand:m 0 …))

(cc0) を使わない機種では、‘tstm’ パターンを 定義すべきでない。定義すると、どの set 演算が比較なのか はっきりしなくなってしまうために最適化パスが混乱する。 代わりに、‘cmpm’ パターンを使うべきである。

movstrm

ブロック移動命令である。移動先と移動元の文字列のアドレスが最初の 二つのオペランドであり、どちらも Pmode モードである。

移動すべきバイト数を三番目のオペランドで、モード m で指定する。 普通は、m として word_mode を指定する。 しかし、有効な長さの範囲が全ワードで表せる範囲より狭いことが 分かっているなら、より良いコードを生成することができるという 場合には、効率良く扱える値の範囲に対応するモード(例えば、 0–127の範囲の値の場合なら QImode とする。負の数に見えるものは 避けることに注意)のパターンと word_mode のパターンの両方を提供すべきである。

四番目のオペランドは、移動元と移動先で共通の既知のアライメントを const_int rtx の形で表したものである。 つまり、コンパイラが移動元も移動先もワード境界にアライメントされている ことを知っているなら、このオペランドには 4 という値が与えられる。

複数の movstrm パターンを記述するのは、 より小さなモードに対するそれらのパターンについて、第一、第二、第四オペランド についての制限がより少ない場合にのみ、有益である。 movstrm のモード m は、ブロック中の個々の移動された データ単位のモードには、なんら制限を与えないことに注意。

このパターンは、移動元と移動先の文字列が重なっている可能性は、 特に考えなくて良い。

clrstrm

ブロックのクリア命令である。対象文字列のアドレスが第一オペランドであり、 モード Pmode である。クリアすべきバイト数が第二オペランドであり、 モード m である。モードの選択についての議論は、‘movstrm’ を 参照のこと。

三番目のオペランドは、目的先の既知のアラインメントを const_int RTX の 形で表したものである。つまり、コンパイラが目的先がワード整合されている ことを知っているなら、このオペランドの値を 4 とする。

複数の clrstrm の使い方は、movstrm と 同じである。

cmpstrm

ブロック同士の比較命令で、オペランドは5つある。 オペランド 0 には出力が置かれ、モードは m である。 その他の4つのオペランドは、‘movstrm’ のオペランドと同様である。 指定された二つのメモリブロックがバイト毎に辞書順で比較される。 この命令の結果、オペランド 0 に格納された値の符号が、比較結果になる。

strlenm

文字列の長さを計算する。オペランドは三つある。 オペランド 0 は結果(モードは m)を格納する。 オペランド 1 は、文字列の先頭の文字を参照する mem である。 オペランド 2 は、検索すべき文字(通常はゼロ)である。 オペランド 3 は、文字列の開始位置の既知のアラインメントを記述する 定数である。

floatmn2

符号付き整数オペランド 1(固定小数点モード m として有効) を 浮動小数点モード n に変換し、オペランド 0 (モード n)に格納する。

floatunsmn2

符号なし整数オペランド 1(固定小数点モード m として有効) を 浮動小数点モード n に変換し、オペランド 0 (モード n)に格納する。

fixmn2

オペランド 1(浮動小数点モード m として有効)を符号付き数として 固定小数点モード n に変換し、オペランド 0(モード n) に 格納する。この命令の結果は、オペランド 1 の値が整数の場合にのみ 定義される。

fixunsmn2

オペランド 1(浮動小数点モード m として有効)を符号なし数として 固定小数点モード n に変換し、オペランド 0(モード n) に 格納する。この命令の結果は、オペランド 1 の値が整数の場合にのみ 定義される。

ftruncm2

オペランド 1(浮動小数点モード m として有効) を 整数値に変換する。ただし、依然として浮動小数点モード m で表現される。 結果は、オペランド 0(浮動小数点モード m として有効)に格納される。

fix_truncmn2

fixmn2’ と同様だが、モードが m の 任意の浮動小数点値について、その値を整数に変換することにより、 動作する。

fixuns_truncmn2

fixunsmn2’ と同様だが、モードが m の 任意の浮動小数点値について、その値を整数に変換することにより、 動作する。

truncmn2

(モード m で有効な)オペランド1をモード n に切り詰め、 結果を(モードが nの)オペランド 0 に格納する。 両方のモードが固定小数点モードか、両方のモードが浮動小数点モードで なければならない。

extendmn2

(モード m で有効な)オペランド1をモード n に符号拡張し、 結果を(モードが nの)オペランド 0 に格納する。 両方のモードが固定小数点モードか、両方のモードが浮動小数点モードで なければならない。

zero_extendmn2

(モード m で有効な)オペランド1をモード n にゼロ拡張し、 結果を(モードが nの)オペランド 0 に格納する。 どちらのモードも固定小数点モードでなければならない。

extv

オペランド 1(レジスタかメモリオペランド)からビットフィールドを 抽出する。オペランド2 でビット幅を指定し、オペランド3で開始ビットを 指定する。結果をオペランド 0 に格納する。 オペランド 0 は、word_mode モードでなければならない。 オペランド 1 は、byte_modeword_mode である。 word_mode はレジスタにしか許されないことが多い。 オペランド 2 と 3 は、word_mode として有効でなくてはならない。

RTL 生成パスは、オペランド 2 とオペランド 3 が定数の場合しか この命令を生成しない。

ビットフィールドの値は、オペランド 0 に格納される前に 全語の整数に符号拡張される。

extzv

extv’ との違いは、ビットフィールドの値がゼロ拡張される点である。

insv

オペランド 3(word_mode として有効でなくてはならない)を オペランド 0 のビットフィールドに格納する。 オペランド 1 でビット幅を指定し、オペランド 2 で開始ビットを指定する。 オペランド 0 は、byte_modeword_mode である。 word_mode はレジスタにしか許されないことが多い。 オペランド 1 と 2 は、word_mode として有効でなくてはならない。

RTL 生成パスは、オペランド 1 とオペランド 2 が定数の場合しか この命令を生成しない。

movmodecc

条件付きで、オペランド 2 またはオペランド 3 を、オペランド 1 に入っている 比較にしたがって、オペランド 0 に移動する。 比較が真ならオペランド 2 がオペランド 0 に移動され、 偽ならオペランド 3 が移動される。

比較されるオペランドのモードは、移動されるオペランドのモードと 同じである必要はない。例えば sparc64 のような機種には、 浮動小数点の条件コードに基づいて整数を条件付きで移動したり、 その逆を行なう命令がある。

条件付き移動命令を持たない機種では、このパターンは定義しないこと。

scond

条件コードにしたがって、ゼロか非ゼロをオペランドに格納する。 条件 cond が真なら格納される値は非ゼロである。 cond は、比較演算式コードの名前で、例えば、eqltleu 等がある。

match_operand 式を書くときにオペランドが持たなければならない モードを指定する。コンパイラはどのモードを使ったかを見て、 自動的にそのモードのオペランドを提供する。

条件が真の場合に格納される値は、下位ビットが 1 か、あるいは負で なければならない。 そうなっていないと、その命令は適切でないので、マシン記述から取り除く べきである。マクロ STORE_FLAG_VALUE (see section 種々雑多なパラメータ) を定義することで 正確にはどの値がストアされるかということを GCC に対して指示する必要がある。 全ての ‘scond’ パターンに対して使用可能な指示が見つからない 場合は、これらの演算をマシン記述から取り除くべきである。

これらの演算は失敗する可能性があるが、失敗して良いのは比較的 珍しいケースだけである。整数の比較を含む良くあるケースで 失敗することがあるなら、そういうパターンは取り除くのが良い。

そういう演算が取り除かれると、GNU CC は、定数 1 をターゲットに コピーし、そのターゲットにゼロを代入している付近に分岐する。 このコードが、‘scond’ パターンで使われる潜在的な 命令に、結果を SImode の 1 か ゼロに変換するのに必要な命令が 続けたものより、効率が良いのなら、マシン記述から ‘scond’ という 演算を取り除くべきである。

bcond

条件分岐命令。オペランド 0 は、ジャンプ先のラベルを参照する label_ref である。条件コードが条件 cond に一致した場合に ジャンプする。

機種によっては、個々で想定した、比較命令の後には条件分岐命令が 続くというモデルに従わないものもある。その場合、‘cmpm’ (と ‘tstm’) パターンでは、オペランドを単に格納しておき、 条件分岐演算を表す define_expand (see section コード生成のための RTL 列の定義) で必要とされる全ての insn を生成すべきである。‘bcond’ パターンを展開する全ての呼び出しの直前には、‘cmpm’ パターンか ‘tstm’ パターンを展開する呼び出しが置かれる。

条件コード値を表すのに疑似レジスタを使っていたり、 比較に使われるモードがテストされる条件に依存する機種でも、やはり 上記の方法を使うべきである。 See section ジャンプ命令のパターンを定義する.

上の議論は、‘movmodecc’ と ‘scond’ のパターンにも 当てはまる。

call

値を返さないサブルーチン命令呼びだしである。 オペランド 0 は呼び出すべき関数であり、オペランド 1 は const_int としてスタックに積まれた引数のバイト数である。 オペランド 2 はオペランドとして使われるレジスタの数である。

ほとんどのマシンでは、オペランド 2 は実際には RTL パターンには格納されない。 この情報をアセンブラコードに置く必要のある、いくつかの RISC 機種の ために提供されている。オペランド 1 の代わりに RTL に置くことができる。

オペランド 0 は、アドレスがその関数のアドレスである mem RTX で あるべきである。だが、このアドレスは、ターゲット機種上での 正当なメモリアドレスになっていなくても、symbol_ref になりうる ことに注意して欲しい。また、call 命令の正しい引数でない場合も、 この演算用のパターンは、アドレスをレジスタに置き、そのレジスタを call 命令で使うような define_expand (see section コード生成のための RTL 列の定義) になっている必要がある。

call_value

値を返すサブルーチン呼び出し命令である。 オペランド 0 は、値が返されるハードレジスタである。 さらにオペランドが三つあり、それらは ‘call’ 命令の三つのオペランド と同じである(オペランド番号は一ずつ増えている)。

BLKmode のオブジェクトを返すサブルーチンは ‘call’ insn を 使う。

call_pop’, ‘call_value_pop

call’ や ‘call_value’ と同様だが、 定義されていて、かつ、RETURN_POPS_ARGS がゼロでない場合に 使われる点が異なる。 これらのパターンは、関数呼び出しとフレームポインタに対してなされた 調整を表す set の両方を含む parallel を生成すべきである。

RETURN_POPS_ARGS がゼロでない値になりうる機種では、 これらのパターンを使うと、望まれている場合には、 フレームポインタを消去可能な関数の数が増えることになる。

untyped_call

任意の型の値を返すサブルーチン呼びだし命令である。 オペランド 0 が呼び出すべき関数、オペランド 1 が関数を呼び出した結果を 格納すべきメモリ位置、オペランド 2 が parallel 式である。 この parallel 式の各要素は、関数の戻り値を結果のブロックへ セーブすることを示す set 式である。

この命令パターンは、任意個数の引数のサブルーチンを呼び出したり、 戻り値をセーブするのに特別な命令を必要とするマシンで、__builtin_apply を動作させるために定義する必要がある。 この命令パターンは、戻り値を保持できるレジスタが複数ある(すなわち、 FUNCTION_VALUE_REGNO_P が二個以上のレジスタに対して 真である)マシンで必要とされる。

return

サブルーチンから戻る命令である。この命令パターン名は、 一個の命令だけで、関数から戻る処理の全てを行なえる場合にのみ 定義するべきである。

movm’ パターンと同様、このパターンも RTL 生成以後の フェーズでも使われる。その場合、関数から戻るのに通常複数の命令が 必要だが、関数のクラスによっては、戻るのに命令を一個しか必要としない ものもあるような機種を支援するためである。 通常、利用可能な関数は、なんらレジスタをセーブしたり、スタック空間を 割り当てたりする必要がないような関数になる。

このような機種については、このパターンで指定された条件は、 reload_completed がゼロでなく、関数のエピローグがただ一つの命令に なる場合にのみ真とならなければならない。レジスタウィンドウのある機種に ついては、leaf_function_p ルーチンを使って、レジスタウィンドウの プッシュが必要かどうかを決定することができる。

条件付きリターン命令のある機種では以下のようにパターンを定義すべきである。

 
(define_insn ""
  [(set (pc)
        (if_then_else (match_operator
                         0 "comparison_operator"
                         [(cc0) (const_int 0)])
                      (return)
                      (pc)))]
  "condition"
  "…")

ここで、condition は普通は、名前付き ‘return’ パターンで 指定されるのと同じ条件である。

untyped_return

型指定なしのサブルーチンからの復帰命令。この命令パターンは、 任意の型の値を返すのに特別な命令を必要とする機種では、__builtin_return をサポートするために定義すべきである。

オペランド 0 は、__builtin_apply により関数を呼び出した結果が 格納されるメモリ位置である。オペランド 1 は、parallel 式であり、 この式の各要素はその結果のブロックから関数の戻り値をリストアすることを 指示する set 式である。

nop

ノップ命令。この命令パターン名は常に定義する必要があり、アセンブラコードで ノップを出力しなければならない。(const_int 0) は RTL パターンとして の役割を果たす。

indirect_jump

オペランド 0 のアドレスにジャンプする命令。 このパターンは全機種で必須である。

casesi

ディスパッチテーブルを通してのジャンプ命令であり、範囲チェックを含む。 この命令は次の5つのオペランドを取る。

  1. ディスパッチ先のインデックス。モードは SImode である。
  2. テーブルのインデックスの下限であり、整数定数である。
  3. テーブルのインデックスの全範囲。最大のインデックスから最小の インデックスを引いたものである。最大、最小とも範囲に含まれる
  4. テーブル自身に先行するラベル。
  5. インデックスの値が範囲外にあるときにジャンプすべきラベル。 マシン記述マクロ CASE_DROPS_THROUGH が定義されていると、 範囲外のインデックスの場合は、このラベルにジャンプする代わりに、 ジャンプテーブルに続くコードにそのまま落ちて行く。 その場合、このラベルは ‘casesi’ 命令では実際には使われない。

このテーブルは、jump_insn の中の addr_vecaddr_diff_vec である。このテーブルの要素数は、 上限値と下限値の差に 1 を加えたものである。

tablejump

可変アドレスにジャンプする命令。これは低レベルの機能であり、 ‘casesi’ パターンがない場合に分岐テーブルを実装するのに 使うことが出来る。

このパターンにはオペランドが二つ必要である。アドレスまたはオフセット、 それとジャンプ表の直前に置くべきラベルである。マクロ CASE_VECTOR_PC_RELATIVE を評価した結果ゼロでない値になれば、 最初のオペランドはその表のアドレスからのオフセットである。 定義されていない場合は、ジャンプ先の絶対アドレスである。 どちらの場合も、最初のオペランドのモードは Pmode である。

tablejump’ insn は、常に、それを使うジャンプ表の前にある最後の insn になる。このアセンブラコードは普通は第二のオペランドを使う必要が ないが、それを RTL パターンに取り込むことで 、ジャンプ最適化フェーズが その表を到達不能コードとして削除しないようにしなければならない。

canonicalize_funcptr_for_compare

オペランド 1 にある関数ポインタを正規化し、その結果をオペランド 0 に 格納する。

オペランド 0 は常に reg であり、モードは Pmode である。 オペランド 1 は、regmemsymbol_refconst_int 等であり、モードは Pmode である。

関数ポインタの正規化には、間接呼び出しの文脈で関数ポインタが 使われた場合呼び出される関数のアドレスを計算することが通常含まれる。

ターゲット機種の関数ポインタが、間接の呼び出しに使われた場合、 値は異なりうるが、呼び出す関数は同じという場合にだけ、このパターンを 定義すること。

save_stack_block
save_stack_function
save_stack_nonlocal
restore_stack_block
restore_stack_function
restore_stack_nonlocal

多くの機種には、モード Pmode のオブジェクトへ コピーしたり、あるいはそのオブジェクトからコピーすることで、 スタックポインタをセーブしたり、リストアする。 そういう機種ではこれらのパターンを定義しないこと。

機種によっては、スタックポインタのセーブとリストアには特別な 取扱いが必要なものもある。そういう機種では、非標準のケースに 対応するパターンを、必要とされる insn を生成する define_expand (see section コード生成のための RTL 列の定義) を使って、定義する。 セーブとリストアには以下の三つのタイプがある。

  1. save_stack_block’ は可変長オブジェクトを割当要るブロックの 開始点でのスタックポインタをセーブする。‘restore_stack_block’ は そのブロックを抜けた時点でスタックポインタをリストアする。
  2. save_stack_function’ と ‘restore_stack_function’ は、 関数の最も外側のブロックに対して同様の処理を行ない、その関数が 可変長オブジェクトを確保したり、alloca を呼び出したときに 使われる。リストアされたスタックポインタを使うのは エピローグだけなので、機種によってはセーブやリストアの命令列が 簡単になる。
  3. save_stack_nonlocal’ は、ネストした関数から分岐してくるラベルを 含む関数の中で使われる。これは、内側の関数が ‘resotre_stack_nonlocal’ を使ってスタックポインタをリストアできるよう な方法で、スタックポインタをセーブする。 GCC はフレームポインタと引数ポインタのレジスタをリストアするコードを 生成するが、機種によっては、その他に、例えば、レジスタウィンドウ情報や スタックのバックチェーンのようなデータをセーブ、リストアする必要が あるものがある。これらのパターンに insn を置いて、そういう必要なデータを セーブ、リストアする。

スタックポインタをセーブするときは、オペランド 0 がセーブ領域であり、 オペランド 1 がスタックポインタである。セーブ領域を確保するのに使う モードはデフォルトでは VOIDmode になるが、マクロ STACK_SAVEAREA_MODE (see section 記憶領域のレイアウト) を定義することで 上書きできる。整数モードか、あるいは、 特定のタイプのセーブの場合はセーブ領域がひつようでない場合は VOIDmode を指定しなければならない。 リストアの場合は、オペランド 0 がスタックポインタで、オペランド 1 が セーブ領域である。‘save_stack_block’ が定義されているなら、 オペランド 0 は VOIDmode であってはならない。こういうセーブは 好きなだけ重ねられるからである。

セーブ領域は、スタックポインタが非局所 goto で使うために セーブされるときは、ある mem であり、virtual_stack_vars_rtx から一定のオフセットにある。 他の二つの場合は、reg である。

allocate_stack

オペランド 1 をスタックポインタから減算(STACK_GROWS_DOWNWARD が 定義されていれば加算)することで、動的に確保するデータ用のスペースを作る。

このスペースを指す、減算(あるいは加算)後のポインタをオペランド 0 に 格納する。主スタックからスペースを割り当てているなら、これは virtual_stack_dynamic_rtx をオペランド 0 にコピーする移動命令を 生成することで行なうこと。その他の場所からスペースを割り当てている場合は、 スペースのその位置をオペランド 0 にコピーするコードを生成すること。 後者の場合、主スタック上の対応するスペースが解放された 時に、このスペースが解放されることを保証しなければならない。

やらなければならないことがこの減算だけであるならこのパターンは定義しないこと。 機種によっては、その他の、スタック探針やバックチェーンの維持等の 操作を必要とするものがある。その場合には、このパターンで、 スタックポインタの更新に加えてそれらの操作を生成するように定義する。

probe

機種によっては、スタックからスペースを割り当てた後に実行すべき 命令を必要とする場合がある。例えば、スタックの基底への参照を 生成するためである。

スタックの調整が完了するまえに命令群を出す必要があるなら、 その命令群を ‘allocate_stack’ パターンに入れるようにする。 その必要がなければ、‘probe’ パターンが必要な命令を出すように 定義する。

オペランドはない。

check_stack

スタック検査を行なうのに、ロード命令あるいはストア命令を使って スタックを探査する方法(see section スタック検査方法の指定)が使えないシステムでは、 このパターンを定義して、必要な検査を行ない、スタックがオーバーフロー したなら、エラーを発するようにする。オペランドは一つで、 検査する必要のある現在のスタックポインタから最も遠いスタック上の 位置である。このパターンが必要な機種では、普通、スタックの限界は、 グローバルまたスレッド固有である、変数またはレジスタから得ることになる。

nonlocal_goto

非局所 goto すなわち、ある関数から外側の関数中のラベルへのジャンプを 生成するコードを出す。このパターンには引数が四つあり、 それぞれがジャンプで使われる値を表す。先頭の引数は、フレームポインタに ロードされる、二番目の引数は、分岐先アドレス(実際のラベルへディスパッチする コード)である。三番目は、スタックがセーブされる位置のアドレスであり、 最後の引数は、ラベルのアドレスであり、入力静的連鎖の位置に置かれる ものである。

ほとんどの機種ではこのパターンを定義する必要がない。GNU CC が 既に正しいコードを生成しているからである。この正しいコードでは、 フレームポインタと静的連鎖をロードし、スタックをリストアし (定義されていれば ‘restore_stack_nonlocal’ パターンを使って)、 ディスパッチ部へ間接的にジャンプする。このコードでは正しく動作しない 機種の場合だけ、このパターンを自分で定義する必要がある。

nonlocal_goto_receiver

このパターンは、定義されていれば、非局所 goto の飛び先に GNU CC が 生成済みのコードの後で必要なコードが入っている。 普通はこのパターンを定義する必要はない。 このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな 表へのポインタのようなものが、フレームポインタがリストアされたときに リストアされなくてはならない場合である。 非局所 goto は翻訳単位内でしか起こらないので、指定されたモジュールの 全ての関数により共有されるグローバル・テーブル・ポインタを リストアする必要はない。引数はない。

exception_receiver

このパターンは、定義されていれば、非局所 goto の位置には必要ないが、 例外ハンドラの位置では必要とされるコードが入っている。 普通はこのパターンを定義する必要はない。 このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな 表へのポインタのようなものが、制御の流れが例外ハンドラに分岐した後で リストアされなくてはならない場合である。引数はない。

builtin_setjmp_setup

このパターンは、定義されていれば、jmp_buf を初期化するのに 必要な追加のコードを保持している。普通は、このパターンを定義する必要は ない。このパターンが必要になる代表的な理由としては、何かの値、 例えばグローバル変数テーブルへのポインタのような値がリストア する必要がある場合である。そのようなポインタ値は可能な限り (例えばラベルのアドレスが与えられているような場合)再計算するのが 望ましいのではあるが。引数は一つであり、jmp_buf へのポインタである。 このバッファは 5語長であり、最初の 3語分は普通は汎用的な機構が 使うことに注意。

builtin_setjmp_receiver

このパターンは、定義されていれば、非局所 goto の位置には必要ないが、 組み込みの setjmp の位置では必要とされるコードが入っている。 普通はこのパターンを定義する必要はない。 このパターンが必要な理由の典型的なものは、ある値、例えばグローバルな 表へのポインタのようなものが、リストアされなくてはならない場合である。 これは引数を一つ取る。それは制御を渡してきた builtin_longjmp に 付くラベルである。このパターンはそのラベルから小さなオフセット分だけ 後に生成される。

builtin_longjmp

このパターンは、定義されていれば、longjmp の全動作を実行する。 builtin_setjmp_setup も定義しているのでない限り、普通は このパターンを定義する必要はない。引数は一個で、jmp_buf への ポインタである。

eh_epilogue

このパターンは、__builtin_eh_return、それに伴って __throw の構築方法に影響を与える。例外処理機構とそのターゲット向けの通常の エピローグコードとの間の通信を可能にすることを意図している。

このパターンには引数が三つある。一番目は、例外今テキストポインタである。 これは、ポインタに適した関数戻りレジスタに既にコピーされているであろう。 普通はこれを無視出来る。二番目の引数は、スタックポインタに加算すべき オフセットである。これはある勝手な呼出し時破壊ハードレジスタに コピーされるので、再ロード後、通常のエピローグが生成される間での 間生き残る。三番目の引数は、この関数が戻るべき例外ハンドラの アドレスである。これは通常、このパターンによりある特別なレジスタに コピーされる必要がある。

このパターンは、もし RETURN_ADDR_RTX が、何か信頼性があり 永久的な修正が可能であるもの、例えば固定ハードレジスタやスタックメモリ 参照のようなものを生み出さない場合は、定義しなければならない。

prologue

このパターンが定義されていると、関数の入り口点に対する RTL を生成する。 関数の入り口点には、スタックフレームの設定、フレームポインタレジスタの 初期化、被呼出し側セーブレジスタのセーブ等の役割がある。

prologue パターンの方が、FUNCTION_PROLOGUE を 定義するよりも、プロローグ用アセンブリ・コードを 生成する方法として一般に望ましい。

prologue パターンは、命令スケジューリングを行うターゲットには 特に有効である。

epilogue

このパターンが定義されていると、関数の出口点に対する RTL を生成する。 関数の出口点には、スタックフレームの解放、 被呼出し側セーブレジスタのリストア、リターン命令の生成等の役割がある。

epilogue パターンの方が、FUNCTION_EPILOGUE を 定義するよりも、エピローグ用アセンブリ・コードを 生成する方法として一般に望ましい。

prologue パターンは、命令スケジューリングを行ったり、 リターン命令に遅延スロットが伴うターゲットには特に有効である。

sibcall_epilogue

このパターンが定義されていると、最終的に呼出し元関数へ分岐して戻らない 関数の出口点に対する RTL を生成する。 このパターンは、任意の同族呼出し(別名末尾呼出し)位置の前に生成される。

sibcall_epilogue パターンは、パラメータの受渡しに使われる引数や 現在の関数に渡された引数用のスタックスロットはどれも破壊してはならない。


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

This document was generated using texi2html 1.78.