TL:DR: 使用以上/以下条件(例如对于无符号整数)来测试比较结果。
由于各种历史原因(通过fcom/fstsw/sahf从FP状态字映射到FLAGS,新的PPro中的fcomi匹配),FP比较设置CF,而不是OF/SF。参见http://www.ray.masmcode.com/tutorial/fpuchap7.htm。请注意保留html标签。
现代 SSE/SSE2 标量比较使用 [u]
comiss
/
sd
] 将结果存入 FLAGS 中
也请参考此处。与 SIMD 比较不同,它们没有谓词作为指令的一部分,因为它们只对每个元素产生单个全零/全一的结果集,而不是一组 FLAGS。保留 html 标签。
这些内容来自于 Intel 64和IA-32体系结构软件开发手册的第2卷。
FCOMI
只设置了一些CMP
的标志。你的代码中有%st(0) == 9
和%st(1) == 10
。(因为它们在栈上加载),参考第2A卷第3-348页的表格,你可以看到这种情况是"ST0 < ST(i)",所以它将清除ZF和PF并设置CF。同时在第2A卷第3-544页上,你可以读到JG
的意思是"如果大于则跳转短(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的行为,您可能需要额外的
jp
或
jnp
。但并不总是需要:例如,
ja
仅在CF=0且ZF=0时为真,在无序情况下它将被视为未执行。如果您希望无序情况采用与以下相同的执行路径,则
ja
就足够了。
如果您想要打印(例如:if (!(f2 > f1)) { puts("hello"); }
),则应使用JA
,如果不想要打印,则应使用JBE
(对应于if (!(f2 <= f1)) { puts("hello"); }
)。请注意,这可能会有点令人困惑,因为我们只在不跳转时才打印。
关于您的第二个问题:默认情况下,
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
ja
的反义词是jbe
而不是jb
。 - Ray Toal