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

16.12 機種固有の覗き穴最適化

命令パターンに加えて、ファイル ‘md’ には、 機種固有の覗き穴最適化の定義を書いても良い。

組合せフェーズが、特定の覗き穴最適化に気付かないときがある。 それはどういう時かというと、プログラムのデータの流れを見ても、 その覗き穴最適化を試すべきであるということが判らない時である。 例えば、二つの連続する insn の目的が関係している場合は、 二番目の insn が最初の insn で計算したレジスタを使わないように 見える場合でも、組合せが行なえることがある。 機種固有の覗き穴最適化器はそのような機会を検出する。

A definition looks like this:

 
(define_peephole
  [insn-pattern-1
   insn-pattern-2
   …]
  "condition"
  "template"
  "optional insn-attributes")

最後の文字列オペランドは、マシン記述で機種固有の情報をなんら使っていない のなら、省略可能である。省略しない場合は、define_insn と 同じ規則に従わなければならない。

このスケルトンでは、insn-pattern-1 等は連続する insn のマッチすべき パターンである。insn-pattern-1 が insn 列の先頭のものに、 insn-pattern-2 がその次に、という具合にマッチするなら、 その insn 列に最適化が適用される。

覗き穴によりマッチする各 insn は define_insn にもマッチしなければ ならない。覗き穴はコード生成の直前の最終段階でしか検査されない。 このため、覗き穴にはマッチするものの define_insn にはマッチしない insn は、最適化を行なわないコンパイルの場合のコード生成で、あるいは 色々な最適化の段階で、異常終了を引き起こす。

insn のオペランドは、通常同様、match_operandsmatch_operatormatch_dup にマッチする。 通常と違うのは、オペランド番号が定義の中にある全ての insn パターンに 適用されるという点である。このため、二つの insn にある同じオペランドを 検査するのに、片方の insn では match_operand を、もう一方では match_dup を使うことができる。

match_operand パターンで使われるオペランド制約は、 覗き穴が適用されるかどうかについては、なんら直接的な効果は持たない。 だが、後で検証されるので、この制約は、覗き穴がマッチするときは いつでも適用できるぐらい一般的なものになっていることを確認して欲しい。 覗き穴にはマッチするが、制約が満たされない場合は、コンパイラが落ちるだろう。

覗き穴最適化の場合は、全てのオペランドの制約を省略しても安全である。 あるいは、制約を書いて、既にテスト済みの規準を二重に検査することにしても 良い。

ある insn の列がそのパターンに一度一致すると、condition が 検査される。condition は一個の C の式であり、この最適化を 実行するかどうかを最終的に決定する(この式がゼロでなければ最適化を 行なう)。condition が指定されていないと(言い換えると、文字列が 空の場合)、この最適化はそのパターンに一致する、あらゆる insn の列に 適用される。

定義された覗き穴最適化はレジスタ割当が完了した後に適用される。 このため、このため、覗き穴最適化の定義では、どのオペランドが最終的に どの種類のレジスタに割り当てられたかを、単にそのオペランドを見ることで 調べることができる。

condition でオペランドを参照するには、オペランド番号が i なら operands[i] と書く((match_operand i …) によりマッチする)。マッチしつつある insn 群の最後のものを参照するには 変数 insn を使う。先行する insn 群を見つけるには prev_active_insn を使う。

中間結果の計算を最適化するときは、condition を使って、 その中間結果が他の場所で使われない時にのみ一致させることができる。 C の式 dead_or_set_p (insn, op) を使うこと。 ここで、insn は、最後に使われると想定している値が入っている insn である(insn の値から、prev_nonnote_insn を組み合わせて 得られる)。op は、中間結果である(operands[i] から 得られる)。

最適化を適用するということは、insn 列を一個の新たな insn で 置き換えるということを意味する。template が、この組み合わされた insn のアセンブラコードの最終的な出力を制御する。 template は、define_insn のテンプレートと全く同じように 動作する。このテンプレートのオペランド番号は、元の insn 列とマッチするのに 使われたのと同じ番号である。

定義した覗き穴最適化の結果は、マシン記述の insn パターンのどれにも マッチする必要はない。実は一致する機会すらないのである。 覗き穴最適化の定義は、それ自身が insn がどのように出力されるかを 制御する insn のパターンとして働く。

定義された覗き穴最適化はアセンブラコードが出力されるときに 実行されるので、生成される insn はどんな方法でも組み合わされたり、 並べ替えられたりすることはない。

以下の例は、68000 のマシン記述から取ったものである。

 
(define_peephole
  [(set (reg:SI 15) (plus:SI (reg:SI 15) (const_int 4)))
   (set (match_operand:DF 0 "register_operand" "=f")
        (match_operand:DF 1 "register_operand" "ad"))]
  "FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
  "*
{
  rtx xoperands[2];
  xoperands[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
#ifdef MOTOROLA
  output_asm_insn (\"move.l %1,(sp)\", xoperands);
  output_asm_insn (\"move.l %1,-(sp)\", operands);
  return \"fmove.d (sp)+,%0\";
#else
  output_asm_insn (\"movel %1,sp@\", xoperands);
  output_asm_insn (\"movel %1,sp@-\", operands);
  return \"fmoved sp@+,%0\";
#endif
}
")

この最適化により

 
jbsr _foobar
addql #4,sp
movel d1,sp@-
movel d0,sp@-
fmoved sp@+,fp0

が、以下のようになる。

 
jbsr _foobar
movel d1,sp@
movel d0,sp@-
fmoved sp@+,fp0

insn-pattern-1 等は、ほぼ define_insn の 第二オペランドに同じである。重要な違いが一つある。 define_insn の第二オペランドは、鍵括弧で囲まれた一つ以上の RTX からなる。普通は一つだけである。その場合、 同じ動作を define_peephole の要素として書くことができる。 しかし、define_insn に複数の動作があるときは、暗黙のうちに parallel で囲まれる。その場合、define_peephole では、 parallel とその中に鍵括弧を明示的に書かなければならない。 こうして、ある insn パターンが

 
(define_insn "divmodsi4"
  [(set (match_operand:SI 0 "general_operand" "=d")
        (div:SI (match_operand:SI 1 "general_operand" "0")
                (match_operand:SI 2 "general_operand" "dmsK")))
   (set (match_operand:SI 3 "general_operand" "=d")
        (mod:SI (match_dup 1) (match_dup 2)))]
  "TARGET_68020"
  "divsl%.l %2,%3:%0")

のようになていたとすると、この insn を覗き穴に書くには以下のようにする。

 
(define_peephole
  […
   (parallel
    [(set (match_operand:SI 0 "general_operand" "=d")
          (div:SI (match_operand:SI 1 "general_operand" "0")
                  (match_operand:SI 2 "general_operand" "dmsK")))
     (set (match_operand:SI 3 "general_operand" "=d")
          (mod:SI (match_dup 1) (match_dup 2)))])
   …]
  …)

This document was generated using texi2html 1.78.