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

16.13 コード生成のための RTL 列の定義

機種によっては、RTL 生成用の標準のパターン名を一個の insn では 扱えないが、RTL insn の列なら表現できるという場合がある。 そのようなターゲット機種の場合は、define_expand を 書くことでその RTL 列を生成する方法を指定することができる。

define_expand は、ある一個の RTL 式であり、 ほぼ define_insn と同じである。 しかし、define_expand は、define_insn と違って、 RTL 生成にのみ使われ、一個以上の RTL insn を生成することができる。

define_expand RTX にはオペランドが4つある。

define_expand により生成されるRTL insn はどれも、マシン記述中の define_insn のどれかにマッチしなければならない。 どれにもマッチしない場合、その insn 用のコードを生成しようとしたり、 最適化しようとしたときに異常終了してしまう。

RTL テンプレートは、RTL insn の生成を制御することに加えて、 このパターンが使われるときに指定する必要があるオペランドをも 記述する。 特に、各オペランドに述語を与える。

真のオペランドは、パターンから RTL を生成するために指定する必要があり、 RTL テンプレートの先頭に現れる match_operand で記述する 必要がある。これにより、オペランドの述語についての情報が、その手の情報を 記録する表に入力される。GNU CC はこの情報を使って、正しい RTL コードとして 必要なら、オペランドをレジスタに事前ロードする。 このオペランドが複数回参照されているなら、それ以降で参照するときは match_dup を使う必要がある。

RTL テンプレートは、内部「オペランド」も参照する。 内部オペランドとは、一時レジスタやラベルであり、define_expand で 作られる列の中でしか使われない。内部オペランドは、match_dup に より RTL テンプレートに代入される。match_operand で代入される ことはない。内部オペランドの値は、GNU CC がこのパターンを使う必要が あるときに引数として渡されることはない。代わりに、 準備文により、パターン内で計算が行なわれる。準備文は、 値を計算し、operands の適切な要素に格納するので、 match_dup がそれを見つけられるようになる。

準備文の中で使う特別なマクロが二つ定義されている。 DONEFAIL である。これらは後ろにセミコロンを付けて 文として使うこと。

DONE

マクロ DONE を使って、このパターンに対する RTL 生成を終了させる。 この時にパターンから作られる RTL insn は、準備文の中で emit_insn を明示的に呼び出すことによって既に出力済みのものだけになる。 RTL テンプレートは生成されない。

FAIL

パターンに対する照合を失敗させる。あるパターンが照合に失敗すると、 そのパターンが利用できないことを意味する。 GNU CC の呼びだし側ルーチンは、他のパターンを使って、コード生成の 別の戦略を試す。

失敗は、現在、二項演算(加算、乗算、シフト等)とビットフィールド演算 (extvextzvinsv)でのみ使える。

次の例は、SPUR チップの左シフトの定義である。

 
(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "register_operand" "")
        (ashift:SI
          (match_operand:SI 1 "register_operand" "")
          (match_operand:SI 2 "nonmemory_operand" "")))]
  ""
  "
 
{
  if (GET_CODE (operands[2]) != CONST_INT
      || (unsigned) INTVAL (operands[2]) > 3)
    FAIL;
}")

この例では、define_expand を使って、 シフト量がサポート範囲の 0 から 3 の間に収まっていればシフトを行なう RTL insn を生成することができるようにしているが、機械命令が使えない ようなそれ以外の場合には失敗するようにしている。 失敗した場合には、別のパターン(例えば、ライブラリ呼びだしなど)を使った 別の戦略を試みる。

GNU CC が、名前付きパターンの自明でない条件文字列を扱うことが 出来たなら、define_insn をその場合に使うことができる。 以下に、define_expand の威力をさらに利用する別の例(68000 での ゼロ拡張である)を示す。

 
(define_expand "zero_extendhisi2"
  [(set (match_operand:SI 0 "general_operand" "")
        (const_int 0))
   (set (strict_low_part
          (subreg:HI
            (match_dup 0)
            0))
        (match_operand:HI 1 "general_operand" ""))]
  ""
  "operands[1] = make_safe_from (operands[1], operands[0]);")

ここでは二つの RTL insn が生成される。一つは出力オペランド全体を クリアし、もう一つは入力オペランドを出力オペランドの下位半分に コピーする。この insn 列は、入力オペランドが出力オペランド(の 古い値)を参照している場合は、正しくなくなる。 そのため、準備文でそうならないことを保証している。 関数 make_safe_from は、operands[1]operands[0] を参照していれば、operands[1] を 一時レジスタにコピーする。そのコピーは、もう一つの RTL insn を 生成することにより行なう。

最後に、三番目の例で内部オペランドの使い方を説明する。 SPUR チップのゼロ拡張は、結果を半語のマスクとの and を取ることで 行なわれる。 だが、このマスクは、定数値としては、この機種で正しいものになるには大きすぎて、 const_int では表現できない。このため、force_reg で レジスタにコピーして、そのレジスタを and の中で使わなければ ならない。

 
(define_expand "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "")
        (and:SI (subreg:SI
                  (match_operand:HI 1 "register_operand" "")
                  0)
                (match_dup 2)))]
  ""
  "operands[2]
     = force_reg (SImode, GEN_INT (65535)); ")

注意: define_expand を標準的な二項演算や単項演算、 あるいはビットフィールド演算に使うときは、それが最後に生成する insn は、 code_labelbarriernote であってはならない。 insnjump_insncall_insn でなくてはならない。 最後に実際の insn を置く必要がなければ、演算の結果を自分自身にコピーする insn を生成する。そういう insn はコードはなんら生成しないが、 GCC に問題が起きるのを回避する。


This document was generated using texi2html 1.78.