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

16.3 RTL テンプレート

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 は空の文字列であっても良い。 その場合、オペランドについては何のテストも行なわれず、この位置に 現れるものは何でも有効になる。

ほとんどの場合、predicatem 以外のモードを受け付けない。 ただし、いつでも受け付けないわけではない。 例えば、述語(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 ベクトルの 要素数と同じ要素数を持つのであれば、各 subpatparallel の 対応する要素に一致し、かつ、関数 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.