|
FCOM 指令系列:
FCOM 指令系列用于在 FPU 中比较两个浮点值。指令比较的一方是加载到 FPU 寄存器 ST0 中的值,另一方要么是另一个 FPU 寄存器,要么是内存中的浮点值。另外,在比较之后还可以把一个值或两个值弹出 FPU 堆栈。
指令
| 描述
| FCOM
| 比较ST0和ST1寄存器
| FCOM ST(x)
| 比较 ST0 寄存器和另外一个 FPU 寄存器
| FCOM source
| 比较 ST0 寄存器和32位或64位的内存值
| FCOMP
| 比较ST0和ST1寄存器,并且弹出堆栈
| FCOMP ST(X)
| 比较ST0和另外一个FPU寄存器,并且弹出堆栈
| FCOMP source
| 比较ST0和32位或64位的内存值,并且弹出堆栈
| FCOMPP
| 比较ST0寄存器和ST1寄存器,并且两次弹出堆栈
| FTST
| 比较寄存器和值0.0
|
比较的结果设置在状态寄存器的 C0, C2 和 C3 条件代码位中,比较可能产生的值如下表所示:
条件
| C3
| C2
| C0
| ST0>source
| 0
| 0
| 0
| ST0<source
| 0
| 0
| 1
| ST0=source
| 1
| 0
| 0
| 对于比较结果,必须使用 FSTSW 指令把状态寄存器的值复制到 AX 寄存器或者内存位置中,然后使用 TEST 指令判断比较的结果,下面是演示程序:
.section .data
value1:
.float 3.5532
value2:
.float 4.5532
.section .text
.global _start
_start:
nop
flds value1
fcoms value2
fstsw
sahf
ja greater
jb lessthan
movl $1, %eax
movl $0, %ebx
int $0x80
greater:
movl $1, %eax
movl $2, %ebx
int $0x80
lessthan:
movl $1, %eax
movl $1, %ebx
int $0x80 程序说明:
在使用 FSTSW 指令将 FPU 状态寄存器的值存往 AX 寄存器中后,需要进一步判断 C0, C2, C3 中的值。这里有一个技巧 --- 使用 SAHF 指令把 AH 寄存器中的值加载到 EFLAGS 寄存器中。
SAHF 指令把 AH 寄存器的第0, 2, 4, 6 和 7 位分别传送到进位、奇偶校验、对准、零和符号标志,而不影响 EFLAGS 中的其他位。AH 寄存器中的这些位正好包含 FPU 状态寄存器的条件代码值。 FSTSW 和 SAHF 指令的组合传送如下:
把 C0 位传送到 EFLAGS 中的 进位标志。 把 C2 位传送到 EFLAGS 中的 奇偶校验标志。 传送完成后, EFLAGS 中的进位、奇偶校验和零标志就具有了 C0, C2 和 C3 条件代码位的值,这样就可以使用 JA, JB 和 JZ 来确定两个浮点值的比较结果。
在运行过 SAHF 指令后,在 GDB 中可以查看上面程序的 EFLAGS 寄存器的状态:eflags 0x200213 [ CF AF IF ID ] 由上可见,CF 位被置位,即是 C0=1,综合C2=0, C3=0 来判断,可知道 value1 < value2。
同样可以通过运行程序查看返回到 shell 中的值来知道判断的结果:
关于相等性比较的一点说明:
当把浮点值加载到 FPU 寄存器中时,它被转换为扩展双精度浮点值。这一处理可能导致一些舍入错误。单精度或者双精度值在加载到 FPU 寄存器之后有可能不等于原始值。检测浮点值的完全相等性不是一个好主意,而要检测它们是否在预期值的小误差之内。 |
|