2011-08-14 35 views
15

コンパイラプロジェクトの一環として、浮動小数点値を比較するためのx86用のGNUアセンブラコードを記述する必要があります。私はオンラインでこれを行う方法に関するリソースを見つけようとしました。これは次のように動作することを理解したところからです:x86アセンブラ:浮動小数点比較

浮動小数点スタックの唯一の値であると仮定すると、fcomi命令は値を設定し、je, jne, jl, ...命令を使用できるようにCPUフラグを設定します。

これは時々動作するだけなので、私は尋ねています。たとえば:

.section .data 
msg: .ascii "Hallo\n\0" 
f1:  .float 10.0 
f2:  .float 9.0 

.globl main 
    .type main, @function 
main: 
    flds f1 
    flds f2 
    fcomi 
    jg leb 
    pushl $msg 
    call printf 
    addl $4, %esp 
leb: 
    pushl $0 
    call exit 

は、私はそれが必要だと思うにもかかわらず、「ハロー」が印刷されません、あなたはf1とf2を切り替えた場合、それはまだ論理的矛盾ではないであろう。 jejneが問題なく動作しているようです。

私は間違っていますか?

PS:fcomipは1つの値だけをポップしますか、それとも両方にポップしますか?

答えて

34

これは、第2巻からすべて Intel 64 and IA-32 Architectures Software Developer's Manualsです。

FCOMIは、CMPが実行するフラグの一部のみを設定します。あなたのコードは%st(0) == 9%st(1) == 10です。 (スタックされているためスタックされています)、Volume 2Aの3-348ページの表を参照すると、これは "ST0 < ST(i)"であることがわかります。したがって、ZFとPFがクリアされ、 CF。一方、 3-544 Vol。図2Aを参照すると、JGは「大きい場合は短くジャンプする(ZF = 0およびSF = OF)」を意味することが読み取れます。つまり、符号、オーバーフロー、ゼロフラグをテストしていますが、FCOMIは符号またはオーバーフローを設定しません。

ジャンプする条件に応じて、可能な比較結果を見て、ジャンプするタイミングを決めてください。

 
+--------------------+---+---+---+ 
| Comparison results | Z | P | C | 
+--------------------+---+---+---+ 
| ST0 > ST(i)  | 0 | 0 | 0 | 
| ST0 < ST(i)  | 0 | 0 | 1 | 
| ST0 = ST(i)  | 1 | 0 | 0 | 
+--------------------+---+---+---+ 

私はそれが簡単に把握できるように、この小さなテーブルを作った:

 
+--------------+---+---+-----+------------------------------------+ 
| Test   | Z | C | Jcc | Notes        | 
+--------------+---+---+-----+------------------------------------+ 
| ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 | 
| ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok    | 
| ST0 == ST(i) | 1 | X | JE | CF will never be set in this case | 
| ST0 != ST(i) | 0 | X | JNE |         | 
| ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good | 
| ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear  | 
+--------------+---+---+-----+------------------------------------+ 
Legend: X: don't care, 0: clear, 1: set 

言い換えれば、条件コードは、符号なしの比較を使用するためのものと一致します。 FMOVccを使用している場合も同様です。

fcomiのいずれか(または両方)のオペランドがNaNの場合は、ZF=1 PF=1 CF=1に設定されます。 (FP比較には、><==、または順序付けられていない4つの結果があります)。あなたのコードがNaNで何をしているか気にするなら、余分にjpまたはjnpが必要な場合があります。ただし必ずしもそうではありません。たとえば、jaは、CF = 0およびZF = 0の場合にのみ真であるため、順序付けられていない場合は取り込まれません。順序付けされていないケースに同じかそれ以下のパスを使用させたい場合は、jaだけ必要です。あなたがいない場合、あなたがそれを印刷したい場合は


ここでは、JAを使用する必要があります(すなわち。if (!(f2 > f1)) { puts("hello"); })とJBEif (!(f2 <= f1)) { puts("hello"); }に対応)。 (ジャンプしなければ印刷するという事実のため、少し混乱するかもしれないことに注意してください)。あなたの2番目の質問については


:デフォルトfcomiで何をポップしません。あなたはその近くのいとこfcomipがポップする%st0をしたい。使用後は常にfpuレジスタスタックをクリアする必要があります。したがって、すべてのプログラムで、メッセージを印刷することを前提に、このようなメッセージが出力されます。

.section .rodata 
msg: .ascii "Hallo\n\0" 
f1:  .float 10.0 
f2:  .float 9.0 

.globl main 
    .type main, @function 
main: 
    flds f1 
    flds f2 
    fcomip 
    fstp %st(0) # to clear stack 
    ja  leb # won't jump, jbe will 
    pushl $msg 
    call printf 
    addl $4, %esp 
leb: 
    pushl $0 
    call exit 
+7

非常に印象深い答えです。優れている。一つの小さなコメント: 'ja'の反対は' jb'ではなく 'jb'です。 –

+2

@Ray Toal:あなたは絶対に正しいです。このケースでは何の違いもありませんが、私はそれをより意味をなすので、例を変更しました。 – user786653

+0

nice!本当にありがとう! – JustMaximumPower

関連する問題