[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
あるパターンを複数の insn に分割する方法を指定しなければならない場合が 二つある。遅延スロット(see section 遅延スロットの定義)を必要とする命令や 出力が複数サイクルの間利用できない命令(see section insn スケジューリングに必要な情報の指定)を 持つ機種では、これらのケースを最適化するコンパイラフェーズでは、 insn を一つの命令の遅延スロットに移動できる必要がある。しかし、 insn の中には複数の機械命令を生成するものもある。そういう insn は 遅延スロットに置くことはできない。
一個の insn を個々の insn のリストに書き直せることが多い。 この場合、個々の insn はそれぞれ一個の機械命令に対応する。 こうすると不利な点は、コンパイルが遅くなり、必要とするメモリスペースが 多くなることである。書き換え後の insn が複雑過ぎると、そのために いくつかの最適化を妨げることにもなる。命令スケジューリングまたは 遅延スロットスケジューリングが改善されると信じる根拠がある場合は、 コンパイラは insn を分割する。
insn の組合せフェーズでは、交換可能な insn の分割も行なう。
三つの insn が複雑な式の一つの insn に統合されたものの、
なんらかの define_insn
パターンにマッチすることが
不可能になった場合、組合せフェーズは複雑なパターンを認識できる
二つの insn に分割しようとする。普通は、複雑なパターンを
いくつかの部分式に分割することで二つのパターンに分ける。
だが、場合によっては、RISC 機種で、ある大きな定数の加算を二つの insn で
行なうような場合、その加算を二つの insn に分割する方法は
機種依存である。
define_split
の定義で、GNU CC に対し、複雑な insn をいくつかの
もっと単純な insn に分割する方法を指定する。
(define_split [insn-pattern] "condition" [new-insn-pattern-1 new-insn-pattern-2 …] "preparation statements") |
insn-pattern は、分割する必要のあるパターンであり、
condtion は define_insn
の場合と同様、
最後にテストされる条件である。insn-pattern にマッチし、
condition を満たす insn が見つかると、
その insn は、insn のリストの中で、new-insn-pattern-1、
new-insn-pattern-2 等で与えられるinsn に置き換えられる。
preparation statements は、define_expand
(
see section コード生成のための RTL 列の定義)で指定される文と同様のもので、
生成されるコードの準備をしたり、パターンが固定していない insn を
いくつか生成したりするために、新しい RTL が生成される前に実行される。
ただし、define_expand
にあるものと違って、これらの文は
疑似レジスタを新たに生成してはならない。
また、再ロードが一度完了したら、スタックフレームからスペースを
割り当ててはならない。
パターンが insn-pattern とマッチするのには、二つの異なる状況がある。
ある insn が遅延スロットスケジューリングや命令スケジューリング向けに
分割する必要がある場合は、その insn は有効であることが既に知られている。
この事は、何かの define_insn
にマッチしていなければならず、
reload_completed
がゼロでなければ、その define_insn
の
制約を満たすことが知られているということを意味する。その場合、
新しい insn パターンも何かの define_insn
にマッチしなければならず、
reload_completed
がゼロでなければ、その定義の制約を満たさなければ
ならない。
この define_split
の使い方の例として、‘a29k.md’ から
取った以下の例を考えてみる。この例では、HImode
から SImode
への sign_extend
を二つのシフト insn の対に分割している。
(define_split [(set (match_operand:SI 0 "gen_reg_operand" "") (sign_extend:SI (match_operand:HI 1 "gen_reg_operand" "")))] "" [(set (match_dup 0) (ashift:SI (match_dup 1) (const_int 16))) (set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 16)))] " { operands[1] = gen_lowpart (SImode, operands[1]); }") |
命令組合せ過程が insn パターンを分割しようとするのは、いつでも、
そのパターンがどの define_insn
にもマッチしない場合
である。組合せ過程は、最初に一個の set
式を分割しようとし、
次に parallel
の中にあるが、スクラッチレジスタとして使うための
疑似レジスタの clobber
が後ろに続くような、同じ set
式を
分割する。
これらの場合、組合せ過程は、新しい insn パターンがちょうど二つ
生成されることを想定する。組合せ過程がこれらのパターンが
なんらかの define_insn
による定義にマッチするかどうかを
検査するので、読者が自分で define_split
の中でこの検査を
行なう必要はない(当たり前だが、マッチする insn を決して
生成しないように define_split
を書くのは意味がない)。
以下に define_split
のこの使い方の例を示す。‘rs6000.md’
から取ったものである。
(define_split [(set (match_operand:SI 0 "gen_reg_operand" "") (plus:SI (match_operand:SI 1 "gen_reg_operand" "") (match_operand:SI 2 "non_add_cint_operand" "")))] "" [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 3))) (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))] " { int low = INTVAL (operands[2]) & 0xffff; int high = (unsigned) INTVAL (operands[2]) >> 16; if (low & 0x8000) high++, low |= 0xffff0000; operands[3] = GEN_INT (high << 16); operands[4] = GEN_INT (low); }") |
ここで述語 non_add_cint_operand
は、一個の加算 insn の有効な
オペランドではない const_int
にマッチする。
小さな変位付きの加算は、次の演算のアドレスに代入できるように
書かれる。
同じファイルから、スクラッチレジスタの使い方の例を見てみる。 この例では、レジスタと大きな定数の等値性比較を生成している。
(define_split [(set (match_operand:CC 0 "cc_reg_operand" "") (compare:CC (match_operand:SI 1 "gen_reg_operand" "") (match_operand:SI 2 "non_short_cint_operand" ""))) (clobber (match_operand:SI 3 "gen_reg_operand" ""))] "find_single_use (operands[0], insn, 0) && (GET_CODE (*find_single_use (operands[0], insn, 0)) == EQ || GET_CODE (*find_single_use (operands[0], insn, 0)) == NE)" [(set (match_dup 3) (xor:SI (match_dup 1) (match_dup 4))) (set (match_dup 0) (compare:CC (match_dup 3) (match_dup 5)))] " { /* Get the constant we are comparing against, C, and see what it looks like sign-extended to 16 bits. Then see what constant could be XOR'ed with C to get the sign-extended value. */ int c = INTVAL (operands[2]); int sextc = (c << 16) >> 16; int xorv = c ^ sextc; operands[4] = GEN_INT (xorv); operands[5] = GEN_INT (sextc); }") |
混乱を避けるために、一個の define_split
を、ある define_insn
にマッチする insn とマッチしない insn を同じように受け付けるように
書いてはならない。代わりに、二つの define_split
を
別々に書いて、一つを有効な insn 用とし他方を有効でない insn 用とすること。
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated
using texi2html 1.78.