| [ < ] | [ > ] | [ << ] | [ 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.