16

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

比較したい2つの値が浮動小数点スタック上の唯一の値であると仮定すると、fcomi命令は値を比較し、CPUフラグを設定して、、、、...je命令を使用できるようにします。jnejl

これはたまにしか機能しないので、私は尋ねています。例えば:

.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

「Hallo」は印刷されるべきだと思いますが、印刷されません。f1とf2を切り替えても、印刷されません。これは論理的な矛盾です。ただし、正常に機能しているようですjejne

私は何が間違っているのですか?

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

4

1 に答える 1

41

TL:DR:上記/以下の条件(符号なし整数など)を使用して、比較の結果をテストします。

さまざまな歴史的理由( FPステータスワードから//を介したFLAGSへのfcomマッピングfstswsahf(PProfcomiの新機能)が一致)により、FPはOF/SFではなくセットCFを比較しますhttp://www.ray.masmcode.com/tutorial/fpuchap7.htmも参照してください。


これはすべて、 Intel64およびIA-32アーキテクチャソフトウェア開発者マニュアルの第2巻からのものです。

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

ジャンプしたい条件に応じて、可能な比較結果を見て、いつジャンプしたいかを決定する必要があります。

+ -------------------- + --- + --- + --- +
| 比較結果| Z | P | C |
+ -------------------- + --- + --- + --- +
| ST0> ST(i)| 0 | 0 | 0 |
| ST0 <ST(i)| 0 | 0 | 1 |
| ST0 = ST(i)| 1 | 0 | 0 |
| 順不同| 1 | 1 | 1 | 一方または両方のオペランドはNaNでした。
+ -------------------- + --- + --- + --- +

わかりやすくするために、この小さなテーブルを作成しました。

+ -------------- + --- + --- + ----- + -------------------- ---------------- +
| テスト| Z | C | Jcc | ノート|
+ -------------- + --- + --- + ----- + -------------------- ---------------- +
| ST0 <ST(i)| X | 1 | JB | CF = 1 |の場合、ZFは設定されません。
| ST0 <= ST(i)| 1 | 1 | JBE | ZFまたはCFのどちらでも問題ありません|
| ST0 == ST(i)| 1 | X | JE | この場合、CFは設定されません|
| ST0!= ST(i)| 0 | X | JNE | |
| ST0> = ST(i)| X | 0 | JAE | CFが明確である限り、私たちは良いです|
| ST0> ST(i)| 0 | 0 | JA | CFとZFの両方が明確でなければなりません|
+ -------------- + --- + --- + ----- + -------------------- ---------------- +
凡例:X:気にしない、0:クリア、1:セット

つまり、条件コードは、符号なし比較を使用する場合の条件コードと一致します。を使用している場合も同様ですFMOVcc

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


ここでは、印刷するJA場合(つまりif (!(f2 > f1)) { puts("hello"); }、)と印刷JBEしない場合(に対応)を使用する必要がありますif (!(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
于 2011-08-14T15:36:33.620 に答える