[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
ここまで説明してきた式コードは値を表すものであり、動作を 表すものではなかった。 しかし機械命令というものは決して値を生み出すものではない。 機械命令は、マシンの状態に副作用を与えるという点でのみ意味を持つ。 特別な式コードを使って、副作用を表現する。
命令の本体は、必ず以下の副作用を表すコードの一つである。 これまで説明してきた、値を表現するコードは、これらのオペランドとしてのみ 現れるのである。
(set lval x)
x の値を lval で表される場所に格納する動作を表現する。
lval は、その中に格納可能であるような場所を表す式である。
すなわち、reg
(あるいは subreg
、または strict_low_part
)、
mem
、pc
、cc0
のどれかである。
lval が、reg
、subreg
、mem
のどれかなら、
マシンモードを持つ必要がある。その場合、x は、そのモードで
有効でなければならない。
lval が、マシンモードがそのレジスタの全幅より小さいような
reg
であれば、そのマシンモードにより指定されたレジスタの部分には
指定された値が与えられ、レジスタのその他の部分は未定義値となる。
同様に、lval が、レジスタのモードより狭いモードの subreg
なら、
レジスタのその他の部分がどのように変更されるかは不定である。
lval が、subreg
の strict_low_part
なら、
subreg
のマシンモードで指定されたレジスタの部分は、
値 x が与えられ、その他の部分は変更されない。
lval が (cc0)
なら、マシンモードがないので、
x は compare
式か、任意のモードを持つ値で良い。
後者の場合は、“test” 命令を表現する。
(set (cc0) (reg:m n))
という式は、
(set (cc0) (compare (reg:m n) (const_int 0)))
という
式に等価である。
前者の式を使ったほうが、コンパイル中のメモリを節約できる。
lval が (pc)
なら、それはジャンプ命令であり、
x の取りうる値は非常に限られてくる。
x は、label_ref
式とすることができる(無条件ジャンプ)。
if_then_else
(条件ジャンプ)とすることもでき、その場合、
第二オペランドか第三オペランドのどちらかが (pc)
(ジャンプしない場合に
使われる)でなければならず、またもう一方は label_ref
(ジャンプする場合に使われる)でなければならない。
また、x は mem
または (plus:SI (pc) y)
でも
良い。ここで、y は reg
か mem
である。
この最後のパターンは分岐テーブル経由のジャンプを表現するのに使われる。
lval が (cc0)
でも (pc)
でもなければ、
lval のモードは VOIDmode
としてはならず、x のモードは
lval のモードとして有効でなければならない。
lval は SET_DEST
マクロで、x は SET_SRC
マクロで
アクセスするようにするのが良い。
(return)
パターン中に単独の式として書くことで、現在の関数から戻ることを
表す。ただし、VAX のように一命令で戻ることができるマシンに
限られる。
関数から戻るためには、複数の命令からなる「エピローグ」を実行する必要が
あるマシンでは、関数からの復帰は、エピローグの直前に置かれるラベルへ
ジャンプすることで行なわれるので、return
式コードが使われることはない。
if_then_else
式の中に置いた場合は、呼び出し元に戻るための pc
に置かれる値を表す。
(return)
というパターンは、論理的には (set (pc) (return))
と等価であるが、後者の形式が使われることはない。
(call function nargs)
関数呼び出しを表現する。function は mem
式であり、
この式のアドレスは、呼び出される関数のアドレスである。
nargs は二つの目的で使われる式である。
あるマシンでは、スタックに積まれた引数のバイト数を表現する。
あるいは、引数レジスタの数を表現する。
どのマシンも function が持たなければならない標準的な
マシンモードを持っている。マシン記述では、
FUNCTION_MODE
というマクロを、その不可欠のモード名に
展開されるように定義している。
このモードの目的は、どの種類のアドレッシングが許されるかが
アドレスの対象となるマシンモードに依存するマシンにおいて、
どの種類のアドレッシングが許されているかを指定することである。
(clobber x)
予期できない値を x に格納すること、または格納する可能性が
あることを表す。x は、reg
式か、scratch
式か、
mem
式のどれかでなければならない。
これが使われるのは一つは、標準的な値を特定のハードレジスタに格納する 文字列命令においてである。 格納される値を記述する手間をかける必要はないが、 文字列命令を越えてその値を保持しようとしないように、 コンパイラにレジスタの値が変更されることを知らせるのが本質的な 事である。
もし x が (mem:BLK (const_int 0))
なら、
全メモリ位置が上書きされると見なされなければならないことを意味する。
マシン記述では、ある種類のハードレジスタを「呼びだし時破壊」
(“call-clobbered”) として分類していることに注意。
全ての関数の呼びだし命令は、デフォルトでこれらのレジスタを破壊すると
仮定されているので、この事実を示すために clobber
式を
使う必要はない。
また、各関数呼び出しは、その関数が const
と宣言されていない限り、
任意のメモリ位置を変更する可能性があると仮定されている。
parallel
の最後の組の式が、それぞれ reg
か
match_scratch
式 (see section RTL テンプレート)を引数とする
clobber
式なら、組合せフェーズは、そうすることでパターンが
マッチするようになるなら、適切な clobber
式を、構築されたばかりの
insn に追加する。
この機能は、例えば、乗算命令と加算命令は MQ レジスタを使わないが、 アキュムレータへの加算命令が MQ レジスタを上書きするようなマシンで 使うことができる。 一個の組み合わされた命令(? combined instruction)は一時レジスタを 必要とするが、一方、それを構成する命令は一時レジスタを必要としない 場合も同様である。
あるレジスタに対する clobber
式が、他に副作用のある parallel
の中に現れた場合は、レジスタ確保部が、そのレジスタがその insn の前後
どちらにおいても占有されることがないことを保証する。
しかし、選ばれた選択肢に対して制約 ‘&’ が指定されていない限り、
再ロードパスが入力の一つとして使われたレジスタを確保する場合がある
(see section 制約修飾子文字)。
特定のハードレジスタ、または疑似レジスタ、あるいは scratch
式の
どれかを上書きすることができる。後の二つの場合には、
GNU CC は、その時点で一時的に使用可能なハードレジスタを確保する。
一時レジスタを必要とする命令については、疑似レジスタの代わりに
scratch
を使うべきである。
そうしておくと、組合せフェーズが必要なときに clobber
を追加すること
を許すからである。
このためには (clobber
(match_scratch
…)) と
書けば良い。
疑似レジスタを上書きするなら、他のどこにも現れていないものを
使うこと。つまり、そのたびに新しいものを生成して使うこと。
そうしないと、CSE のフェーズが混乱する。
parallel
中で疑似レジスタを上書きすることのもう一つの使い道が
ある。insn の入力オペランドの一つがやりその insn により上書きされる
場合である。
この場合、insn 中の clobber の中と、別のところとに同じ疑似レジスタを
使うと期待どおりの結果が得られる。
(use x)
x の値が使われるということを表す。
プログラムのこの時点での x の値が必要であることを示す。
たとえ、なぜ必要であるかがはっきりしていなくてもである。
このため、GCC は、x に値を格納するという
効果しか持たない命令が直前にあっても、その命令を削除しない。
x は、reg
式でなければならない。
再ロードフェーズの間、パターンとして use
がある insn は、
reg_equal
ノートを保持することが可能である。
このような use
insn は、再ロードフェーズが終了する前に
削除される。
遅延分岐スケジューリングのフェーズの間は、x は insn でも良い。
これは、x が以前にコード中のこの場所にあって、そのデータ依存関係
を考慮する必要があるということを意味する。
このような use
insn は、遅延分岐スケジューリングのフェーズの
終了前に削除される。
並列に実行される様々な副作用を表す。
大カッコはベクトルを表す。parallel
のオペランドは
式を要素とする一個のベクトルである。
x0、x1 等は個々の副作用を表す式である。
これらの式のコードは、set
や call
、return
、
clobber
、use
のどれかである。
「並列に」という意味は、最初に個々の副作用で使われる全ての値が 計算され、次に全ての副作用が実行されることを表す。
(parallel [(set (reg:SI 1) (mem:SI (reg:SI 1))) (set (mem:SI (reg:SI 1)) (reg:SI 1))]) |
例えば、上の式はハードレジスタ 1 の値と、ハードレジスタ 1 により
指定されるメモリ位置の値を交換するということを曖昧さなしに
表している。
(reg:SI 1)
がメモリアドレスとして現れているところでは、どちらも、
insn を実行する前のレジスタ 1 の値を参照している。
このため、parallel
を使ったときに、ある一つの set
の
結果が次の set
で使えると考えるのは間違いという
ことになる。
例えば、人は良く、条件が 0 なら分岐する命令を以下のように表そうとする。
(parallel [(set (cc0) (reg:SI 34)) (set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref …) (pc)))]) |
しかし、この書き方は間違いである。何故なら、これだと分岐条件は この命令の前の条件コードの値に依存しており、 この命令により設定される新しい値を使っていないからである。
のぞき穴最適化は、最終フェーズのアセンブリコード出力と一緒に行なわれる。
この最適化により、一個の parallel
からなるパターンの insn を
生成することができる。この場合、parallel
の各要素は、
結果となるアセンブラコードを出力するのに必要なオペランド—多くの場合、
reg
あるいは mem
、定数式である。
これは、他のどのコンパイル過程でも適切な形式の RTL ではないが、
その後には、もはや実行すべき最適化過程が残っていないので、問題ないのである。
ただし、マクロ NOTICE_UPDATE_CC
をもし定義するなら、
その定義では、なんらかののぞき穴最適化を定義するなら上記のような
insn を取り扱わなければならない。
(sequence [insns …])
ある insn の列を表す。ベクトル中に現れる insns のそれぞれは、
insn の連鎖に現れるのに適したものであるために、insn
、
jump_insn
、call_insn
、code_labe
、barrier
、
note
のどれかでなければならない。
sequence
RTX は、RTL 生成の間は実際の insn には決して置かれること
がない。
この RTX は define_expand
から生ずる insn の列を表しており、
それは、insn が emit_insn
に渡され、insn の連鎖に挿入
されるまえに行なわれる。
実際に挿入された時点で、個々のサブ insn が分離し、sequence
が
捨てられる。
遅延スロットスケジューリングが完了した後、ある insn とその遅延スロットに
置かれている全ての insn は一まとめにされて、一個の sequence
に
収められる。遅延スロットを必要とする insn は、ベクトル中の先頭の
insn である。その後ろに続く insn は遅延スロットに置かれる。
遅延スロット中の insn には INSN_ANNULLED_BRANCH_P
が設定され、
遅延スロット中の insn の効果を条件により無効化するような
分岐 insn を使うべきであることを指示する。
以下の式コードは副作用の代わりに、insn の本体として現れる。 だが、厳密に言えばいつでも副作用を表すわけではない。
(asm_input s)
文字列 s で表されるアセンブラコードそのものを表す。
(unspec [operands …] index)
(unspec_volatile [operands …] index)
operands についてのマシン固有の演算を表す。
index で、複数のマシン固有演算の一つを選び出す。
unspec_volatile
を使って、揮発性の演算とトラップを起こす可能性の
ある演算を表す。
その他の演算には unspec
が使われる。
これらのコードは insn の pattern
の内側、
parallel
の内側、式の内側に現れる可能性がある。
(addr_vec:m [lr0 lr1 …])
ジャンプ先アドレスのテーブルを表す。
ベクトルの要素 lr0... 等は label_ref
式である。
モード m で各アドレスにどれだけのメモリを与えるかを指定する。
普通は m は Pmode
になる。
(addr_diff_vec:m base [lr0 lr1 …] min max flags)
ジャンプ先アドレスを base からのオフセットで表したテーブルを
表す。ベクトルの要素 lr0... 等は、label_ref
式であり、
base も label_ref
式である。
モード m で各アドレスの差分にどれだけのメモリを与えるかを
指定する。min と max は分岐の近距離化により設定され、
それぞれ最小と最大のアドレスを持つラベルを保持する。
flags は、それを保持する insn に対する base、min、
max と、base に対する min、max の相対的な
位置を表す。詳細については ‘rtl.def’ を参照のこと。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated
using texi2html 1.78.