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

16.6.1 単純制約

最も単純な種類の制約は全部が英文字からなる文字列である。 その一つ一つの文字が、許されるオペランドの一つの種類を記述する。 以下に許される英文字を示す。

m

メモリオペランドを指定する。その機種が一般にサポートしている アドレスならどれでも良い。

o

メモリオペランドを指定する。ただし、許されるアドレスは「オフセット指定可能な」 アドレスだけである。 つまり、そのアドレスに小さな整数(実際には、マシンモードにより決まる、 バイト数で表したオペランドの幅に収まる数)を加算した結果も また有効なメモリアドレスとなる。

例えば、アドレスが定数であれば、それはオフセット指定可能である。 一個のレジスタと一個の定数(ちょっと大きめの定数もその機種で サポートされている範囲のアドレスのオフセットになっている限り) の和もオフセット指定可能である。 しかし、自動インクリメント、自動デクリメントのアドレスは オフセット指定可能でない。 もっと複雑な間接/インデックス修飾アドレスがオフセット指定可能か どうかは、その機種がサポートする他のアドレッシングモードに 依存する。

別のオペランドにマッチ可能な出力オペランドにおいては、 制約文字 ‘o’は、‘<’(ターゲット機種に事前デクリメントアドレッシング があれば)と‘>’(ターゲット機種に事前インクリメントアドレッシングが あれば)の両方を伴う場合にのみ有効である。

V

オフセット指定可能でないメモリオペランドを指定する。 言い換えると、制約 ‘m’ には収まるが、‘o’ には収まらないものは 何でもここに入る。

<

自動デクリメントのアドレスのメモリオペランドを指定する。 プリデクリメントでもポストデクリメントのどちらでも良い。

>

自動インクリメントのアドレスのメモリオペランドを指定する。 プリインクリメントでもポストインクリメントのどちらでも良い。

r

レジスタオペランドが許される。ただし、レジスタは汎用レジスタである。

d’, ‘a’, ‘f’, …

他の文字は、機種依存の方法で、特定のレジスタクラスを表すように 定義することができる。 68000/68020 では、‘d’、‘a’、‘f’ が 定義されており、それぞれ、データレジスタ、アドレスレジスタ、 浮動小数点レジスタを表す。

i

整数の即値オペランド(定数値のもの)が許される。 これには、値がアセンブル時にならないとわからないシンボリックな定数も 含まれる。

n

既知の数値を持つ整数即値のオペランドが許される。 多くのシステムでは、語長よりも小さいオペランドにはアセンブル時の定数は 使えない。そのようなオペランドの制約には ‘i’ ではなく ‘n’ を 使うべきである。

I’, ‘J’, ‘K’, … ‘P

他の、‘I’ と ‘P’ の間にある文字は、機種依存の方法で、 指定された範囲の明示された整数値を持つ整数の即値オペランドを許すように 定義することができる。 例えば、68000 では、‘I’ は、1 〜 8 の範囲の値を表すと 定義されている。これは、シフト命令で許されているシフト幅の範囲である。

E

浮動小数点の即値オペランド(式コードは const_double)が 許される。ただし、ターゲットの浮動小数点形式がホストマシン(コンパイラが 動作するマシン)のものと同じ場合に限られる。

F

浮動小数点の即値オペランド(式コードは const_double)が 許される。

G’, ‘H

G’ と ‘H’ は、機種依存の方法で、特定の範囲の値の 浮動小数点即値オペランドを許すように定義することができる。

s

値が明示的な整数ではない、整数即値オペランドが許される。

これは奇異に聞こえるかもしれない。 もし、ある insn がコンパイル時には決まっていない値をもつ定数オペランドを 許すなら、当然、どんな既知の値でも許さなければならないはずだ。 どうして、‘i’ の代わりに ‘s’ を使うのか? その方が、良いコードが生成されることがあるからなのだ。

例えば、68000 の全ワードの命令では即値オペランドを使うことができる。 しかし、即値の範囲が -128 と 127 の間にあるなら、その値をレジスタに ロードして、そのレジスタを使った方が良いコードになるのである。 これは、レジスタへのロードが ‘moveq’ 命令で行なえるからである。 我々はこれが起きるように、文字 ‘K’ が「-128 と 127 の範囲の 外側の整数」という意味を持つように定義し、オペランドの制約に ‘Ks’ と指定している。

g

任意のレジスタ、メモリ、整数の即値のオペランドが許される。 ただし、汎用レジスタでないレジスタは除く。

X

どんなオペランドでも、たとえ general_operand を満たさないもので あっても許される。 これは、通常、特定の選択肢が実際にはスクラッチレジスタを必要としないときに、 match_scratch の制約で使われる。

0’, ‘1’, ‘2’, … ‘9

指定したオペランド番号にマッチするオペランドが許される。 数字を同じ選択肢の中で英文字と組み合わせて使うなら、数字は 最後に書くこと。

これは、照合制約と呼ばれており、それが実際に意味することは、 アセンブラには二つの役割を果たす一個のオペランドしかないということである。 この二つの役割は RTL insn で別のものと考えられている。 例えば、add insn は RTL には、二つの入力オペランドと一つのオペランドを 持っているが、多くの CISC マシンでは、add 命令にはオペランドが二つしかなく、その一つは 入力と出力兼用オペランドである。

 
addl #35,r12

照合制約は以下の状況で使われる。 もっと正確に言えば、マッチする二つのオペランドのうち、一つは入力専用で、 もう一つは出力専用でなければならない。さらに、数字は制約で使われている オペランド数より小さな数でなければならない。

ある特定の場合にマッチするオペランドは普通それらが見かけが同じである RTL 式になっているということを意味する。しかし、2,3の特別な場合には 特定の種類の違いは許される。例えば、入力オペランドとしての *x は 出力オペランドとしての *x++ にマッチする。 このような場合に正しい結果を得るには、出力テンプレートでは オペランドを出力するさいに常に出力オペランドの番号を使う必要がある。

p

有効なメモリアドレスであるオペランドが許される。 これは、「ロード・アドレス」命令と「プッシュ・アドレス」命令向けである。

制約の中の ‘p’ には、match_operand の述語のように、 address_operand が付随しなければならない。 この述語は、match_operand で指定されたモードを、 アドレスが有効であるメモリ参照のモードとして解釈する。

Q’, ‘R’, ‘S’, … ‘U

Q’ から ‘U’ の範囲の文字は、機種依存の形式で 定義して、任意のオペランド型を表すのに使える。 マシン記述マクロ EXTRA_CONSTRAINT には、一番目の引数として そのオペランドが、二番目の引数として制約文字が渡される。

これの典型的な使い方は、他の insn のオペランドに影響する メモリ参照の一定の型を区別することである。

これらの制約文字は、レジスタ選択(reg)を受け付けるようには 定義しないこと。再ロードパスが想定していないことであり、正しく扱え ないだろう。

アセンブラコードを正しいものにするために、各オペランドはその制約を 満たさなければならない。 しかし、制約を満たさなくても、そのパターンがある insn に適用されるのを 妨げるものではない。 代わりに、コンパイラがコードを修正して、制約が満足されるようにする。 通常これはオペランドをレジスタにコピーすることにより行なわれる。

このため、以下の二つの命令パターンを比べてみよう。

 
(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r")
        (plus:SI (match_dup 0)
                 (match_operand:SI 1 "general_operand" "r")))]
  ""
  "…")

これにはオペランドが二つあり、そのうちの一つは二箇所に現れなければならない。 そして、

 
(define_insn ""
  [(set (match_operand:SI 0 "general_operand" "=r")
        (plus:SI (match_operand:SI 1 "general_operand" "0")
                 (match_operand:SI 2 "general_operand" "r")))]
  ""
  "…")

こちらは、オペランドが三つあり、そのうちの二つは制約により等しいことが 要求される。以下の形の insn を考えてみると、

 
(insn n prev next
  (set (reg:SI 3)
       (plus:SI (reg:SI 6) (reg:SI 109)))
  …)

最初のパターンは全く適合しない。この insn には、正しい場所に二つの 同じ部分式がないからである。 最初のパターンは、「加算命令には見えないので、他のパターンを試してね。」 と言うだろう。 一方、二番目のパターンは、「うん、これは加算命令だ。だけどちょっと 間違ってるな。」と言うだろう。 コンパイラの再ロードパスに対して insn を追加で生成させ、制約が 満たされるようにすることを指示する。 その結果は以下のようになるだろう。

 
(insn n2 prev n
  (set (reg:SI 3) (reg:SI 6))
  …)

(insn n n2 next
  (set (reg:SI 3)
       (plus:SI (reg:SI 3) (reg:SI 109)))
  …)

各パターンの各オペランドが、それぞれのオペランド向けに存在 しうる、どんな RTL 式も扱えるような制約を持つことを保証するのは 読者の責任である。 (複数の選択肢が使われている場合は、各パターンは、オペランド式の 可能な組合せ毎に、その組合せを扱うことが出来る選択肢を少なくとも 一つ持たなければならない。) その制約は可能なオペランドをなんでも許す必要はない。なんでも許すのであれば それは制約ではない。だが、その制約は少なくとも、それに適するような 何らかの可能なオペランドを再ロードする方法を指し示す必要がある。

オペランドの述語はレジスタを認識できるが、制約の方はレジスタを許さない場合は コンパイラが落ちる可能性がある。 このオペランドがレジスタになったとき、再ロードパスがうまくいかなくなる。 レジスタを一時的にメモリにコピーする方法が分からないためである。

述語が単項演算子を受け付けるなら、制約はそのオペランドに適用される。 例えば、ISA レベル 3 の MIPS プロセッサは、SImode の二つの レジスタを加算して、DImode の結果を生成する命令をサポートしているが、 これはレジスタが正しく符号拡張される場合だけである。 入力オペランドに対するこの述語は、ある SImode のレジスタの sign_extend を受け付ける。sign_extend の オペランドとして必要なレジスタのタイプを示すように制約を書くこと。


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

This document was generated using texi2html 1.78.