[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
RTL テンプレートを使い、どの insn が特定のパターンにマッチするのか、および、 そのオペランドの見つけ方を定義する。名前付きパターンの場合は、 RTL テンプレートは、指定されたオペランドからどのように insn を構築するかに ついても指示する。
構築するということには、指定されたオペランドをテンプレートのコピーに 代入することも含まれる。 照合することには、一致しようとしている insn のオペランドの役割を 果たす値を決定することも含まれる。 どちらの動作も、照合とオペランドの代入を指示する特別な式の型に より制御される。
(match_operand:m n predicate constraint)
この式は、insn の n 番目のオペランドのプレースホルダーである。 insn の構築時に、n番目のオペランドがここに挿入される。 insn の照合時には、insn のこの位置に現れるものは何であれ、 n 番目のオペランドとして扱われる。ただし、その場合 predicate を 満たしている必要があり、さもなければこの命令パターンは全くマッチしない。
オペランド番号は、各命令パターンにおいて 0 から始まる数字に
ならなければならない。各オペランド番号について、パターンには
match_operand
式が一個だけ存在し得る。
普通は、オペランドは match_operand
式群に現れた順に
番号が付く。
define_expand
の場合には、match_dup
式でのみ
使用されるオペランド番号はどれも、他のどのオペランド番号よりも
大きな値になる。
predicate は、ある C の関数名を表す文字列でり、その関数は
二つの引数、すなわち一個の式と一個のマシンモードを受け付ける。
照合が行なわれる間に、式として仮想的なオペランド、モード引数として m を
使ってその関数が呼び出される。(m が指定されない場合は、
VOIDmode
が使われ、predicate は任意のモードを受け付けることに
なる。)
この関数が 0 を返した場合は、この命令パターンの照合に失敗することになる。
predicate は空の文字列であっても良い。
その場合、オペランドについては何のテストも行なわれず、この位置に
現れるものは何でも有効になる。
ほとんどの場合、predicate は m 以外のモードを受け付けない。
ただし、いつでも受け付けないわけではない。
例えば、述語(predicate) address_operand
は、m を、
そのアドレスが有効なメモリ参照のモードとして使う。
多くの述語は、それらのモードが VOIDmode
であっても const_int
ノードを受け付ける。
constraint は再ロードとある値に最適なレジスタクラスの選択を 制御する。これについては後で説明する (see section オペランド制約)。
制約と述語の違いが良く判らないという人が多い。 述語は、ある与えられた insn がパターンにマッチするかどうかを 判断する手助けをする。 一方、制約は、この判断には関与しない。代わりに、 insn がパターンにマッチした場合の色々な判断を制御するのである。
CISC では、最も良く出てくる述語は、"general_operand"
である。これは、仮想オペランドが、定数であるのか、レジスタなのか、
メモリ参照なのかを調べ、それがモード m で有効なのものかどうかを
確かめる。
レジスタでなければならないオペランドの場合は、述語としては
"register_operand"
を使うべきである。再ロード過程で
"general_operand"
を使っても、
任意の非レジスタオペランドをレジスタにコピーするという処理を行うので
大丈夫だが、そうすると GCC に余計な仕事をさせることになるし、
ループからの不変オペランド(例えば定数)の除去や最適なレジスタ割り付け
の妨げにもなる。
RISC の場合には、述語としては、制約が許す範囲のオブジェクトのみを
受け付けるようにするのが一般には最も効率が良い。
定数であるはずのオペランドの場合には、述語として "immediate_operand"
を使うか、命令パターンの付加条件が定数を要求するようにするか、あるいは両方を
行うようにする必要がある。制約を使えば同じことが出来るだろうと考えては
いけない。
制約の方が定数のみを許すようになっていても、述語がそれ以外のものを
許しているなら、実際にそのケースが発生したときに
GCC は落ちてしまうのである。
(match_scratch:m n constraint)
この式もオペランド番号 n のプレースホルダであり、オペランドは
scratch
式か reg
式でなければならないことを指定する。
パターン照合の際には、これは、以下の式と等価である。
(match_operand:m n "scratch_operand" pred) |
しかし、RTL 生成フェーズでは、これは (scratch
:m) という式を
生成する。
parallel
の中の最後の幾つかの式が clobber
式であり、
その clobber
式のオペランドがハードレジスタか match_scratch
なら、結合器(combiner) は必要なときにそういうオペランドを追加したり、
削除したりすることができる。
(match_dup n)
この式もオペランド番号 n のプレースホルダーである。 オペランドが insn の二箇所以上に現れる必要があるときに使われる。
構築の際には、match_dup
はちょうど match_operand
と同様に動作する。オペランドは、構築されつつある insn に代入される。
しかし、マッチングでは、match_dup
の動作は異なる。
オペランド番号 n は認識テンプレートに先に現れる match_operand
により既に決まっており、見た目が同一の式にしかマッチしないということを
想定している。
(match_operator:m n predicate [operands…])
このパターンは、可変な RTL 式コードの一種のプレースホルダーである。
insn 構築の際には、ある RTL 式を表す。 この RTL 式の式コードは、オペランド n から取られ、 オペランドはパターンの operands から構築される。
式と照合する際は、関数 predicate がその式についてゼロでない 値を返し、かつ パターンの operands がその式のオペランドに マッチしたときに、その式にマッチする。
関数 commutative_operator
が以下のように定義されていると
する。演算子が RTL の交換可能な算術演算子の一つで、モードが mode
である任意の式にマッチするように定義されている。
int commutative_operator (x, mode) rtx x; enum machine_mode mode; { enum rtx_code code = GET_CODE (x); if (GET_MODE (x) != mode) return 0; return (GET_RTX_CLASS (code) == 'c' || code == EQ || code == NE); } |
そうすると、以下のパターンは、二つの一般オペランドに適用される交換可能な 演算子を含む任意の RTL 式にマッチする。
(match_operator:SI 3 "commutative_operator" [(match_operand:SI 1 "general_operand" "g") (match_operand:SI 2 "general_operand" "g")]) |
ここでベクトル [operands…]
は、二つのパターンを
含んでいる。なぜなら、マッチすべき式は全て二つのオペランドを
含んでいるからである。
このパターンがマッチしたとき、交換可能な演算子の二つのオペランドは、
この insn のオペランド 1 とオペランド 2 として記録される。
(これは、二つの match_operand
により行なわれる。)
この insn のオペランド 3 は、交換可能な式全体である。
match_operator
のマシンモード m は、match_operand
の
ものと同様に振る舞う。述語関数の二番目の引数として渡され、
その関数だけが、マッチすべき式がそのモードを「持っているか」どうかを
決定する責任がある。
insn を構築する際には、生成関数の第三引数が、作成されるべき式の 演算(すなわち式コード)を指定する。 この引数は一個の RTL 式であるべきで、その式コードが、 生成関数の引数 1 と 2 をオペランドとする新しい式にコピーされる。 引数 3 のサブ式は使われない。式コードだけが問題になる。
match_operator
が、insn と照合されるパターンで使われているとき、
その match_operator
のオペランド番号が、その insn の
実際のオペランド番号よりも大きいのが通常は最善である。
これによりレジスタ割当が改良される。レジスタ割当では、
insn のオペランド 1 と 2 を見て、レジスタの結び付けが可能かどうかを
見るからである。
match_operator
に制約を指定する方法はない。
match_operator
に対応する insn のオペランドは
どんな制約も持つことはない。全体として再ロードされることがないからである。
だが、その operands の一部が match_operand
パターンに
より照合が行なわれると、その一部はそれ自身の制約があって良い。
(match_op_dup:m n[operands…])
match_dup
に似ているが、オペランドではなく演算子に適用される。
insn を構築するときは、オペランド番号 n がここに代入される。
しかし、マッチングの際には match_op_dup
の動作は異なる。
オペランド番号 n は認識テンプレートに先に現れる match_operator
により既に決まっており、見た目が同一の式にしかマッチしないということを
想定している。
(match_parallel n predicate [subpat…])
このパターンは、可変数要素の parallel
式一個からなる insn の
プレースホルダーである。
この式は、insn パターンの最上位レベルにのみ現れるべきである。
insn を構築する際には、オペランド番号 n がこの点で置き換えられる。
insn との照合の際には、insn 本体が parallel
式であり、この
parallel
式が、
少なくとも match_parallel
中の subpat 式の insn ベクトルの
要素数と同じ要素数を持つのであれば、各 subpat が parallel
の
対応する要素に一致し、かつ、関数 predicate が insn の本体で
ある parallel
に対してゼロでない値を返すなら、一致が起きる。
match_parallel
に列挙されたもの以外の parallel
の要素を
確認するのは述語の役割である。
match_parallel
の代表的な使い方は、ロードマルチプル式と
ストアマルチプル式にマッチさせることである。
例えば、
(define_insn "" [(match_parallel 0 "load_multiple_operation" [(set (match_operand:SI 1 "gpc_reg_operand" "=r") (match_operand:SI 2 "memory_operand" "m")) (use (reg:SI 179)) (clobber (reg:SI 179))])] "" "loadm 0,0,%1,%2") |
この例は、‘a29k.md’ から取ったものである。
関数 load_multiple_operations
は、‘a29k.c’ で
定義されており、parallel
中の後続の要素が、このパターンの
中のset
と同じであるかどうかを検査している。
その要素が、後続のレジスタとメモリ位置を参照している場合を除く。
このパターンにマッチする insn は以下のような形式である。
(parallel [(set (reg:SI 20) (mem:SI (reg:SI 100))) (use (reg:SI 179)) (clobber (reg:SI 179)) (set (reg:SI 21) (mem:SI (plus:SI (reg:SI 100) (const_int 4)))) (set (reg:SI 22) (mem:SI (plus:SI (reg:SI 100) (const_int 8))))]) |
(match_par_dup n [subpat…])
match_op_dup
と同様だが、match_operator
ではなく
match_parallel
用である。
(match_insn predicate)
完全な insn にマッチする。他の match_*
認識器とは異なり、
match_insn
はオペランド番号を取らない。
match_insn
のマシンモード m は、match_operand
と同様の働きをする。述語関数の第二引数として渡され、
マッチした式のモードがそのモードになっているかどうかを決定する
責任はその関数にだけある。
(match_insn2 n predicate)
完全な insn にマッチする。
match_insn2
のマシンモード m は、match_operand
と同様の働きをする。述語関数の第二引数として渡され、
マッチした式のモードがそのモードになっているかどうかを決定する
責任はその関数にだけある。
(address (match_operand:m n "address_operand" ""))
この複雑な式は、「ロードアドレス」命令中のオペランド番号 n の プレースホルダーである。 このオペランドは普通はメモリ位置を指定するが、実際のオペランド値 として使われるのはその位置のアドレスであり、その位置の内容ではない。
address
式は RTL コードには決して現れず、マシン記述でのみ
使われる。そして、オペランド制約の機能を使わないマシン記述でしか
使われることがない。
オペランド制約が使われる場合は、制約の文字 ‘p’ がこの目的を
果たす。
m は、アドレスとなるメモリ位置のマシンモードであり、
アドレス自身のマシンモードではない。
このモードは、ある与えられたターゲットマシン上では常に同じなので
(Pmode
で、これは普通は SImode
である)、
それをわざわざ明記する意味はない。
つまり、address
式にはマシンモードは書かないのである。
いつの日か、異なる種類のオブジェクトのアドレスが異なって見えたり、
(PDP-10 のように)使い方が異なっていたりするマシンがサポートされたら、
異なる形式はおそらく異なるマシンモードを必要とし、そのモードを
address
式に書くことになるだろう。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated
using texi2html 1.78.