曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5227|回复: 2
打印 上一主题 下一主题

浮点条件分支

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2010-3-13 14:00:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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 中的 奇偶校验标志。
      把 C3 位传送到 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 中的值来知道判断的结果:
$ ./fcom
$ echo $?
1

关于相等性比较的一点说明:
当把浮点值加载到 FPU 寄存器中时,它被转换为扩展双精度浮点值。这一处理可能导致一些舍入错误。单精度或者双精度值在加载到 FPU 寄存器之后有可能不等于原始值。检测浮点值的完全相等性不是一个好主意,而要检测它们是否在预期值的小误差之内。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2010-3-13 16:35:44 | 只看该作者

FCOMI 指令系列

FCOMI 系列指令是相当于 FSTSW 和 SAHF 的指令组合。
FCOMI 系列指令执行浮点比较并且把结果存放到 EFLAGS 寄存器中的进位、奇偶校验和零标志。
指令
描述
FCOMI
比较ST0寄存器和ST(x)寄存器
FCOMIP
比较ST0寄存器和ST(x)寄存器,并且弹出堆栈
FUCOMI
在比较之前检查无序值
FUCOMIP
在比较之前检查无序值,并且在比较之后弹出堆栈
从上表可以看出,FCOMI 指令系列的局限性在于它们只能比较 FPU 寄存器中的两个值,而不能比较 FPU 寄存器和内存中的值

上表中最后两条指令执行 FCOM 指令系列没提供的功能。FUCOMI 和 FUCOMIP 指令确保被比较的值是合法的浮点数(使用 FPU 标记寄存器)。如果出现无序值,就会抛出异常。

FCOMI 指令的输出使用 EFLAGS 寄存器,如下表所示:
条件
ZF
PF
CF
ST0>ST(X)
0
0
0
ST0<ST(X)
0
0
1
ST0=ST(X)
1
0
0

下面程序验证 FCOMI 指令功能:
.section .data
value1:
    .float 10.923
value2:
    .float 4.5532

.section .text
.global _start

_start:
    nop
    flds value2
    flds value1
    fcomi %st(1), %st(0)
    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
运行与输出:
$ ./fcomi
$ echo $?
2
说明
FCOMI 指令是用目标操作数(ST0)减去源操作数(ST1)。

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
板凳
 楼主| 发表于 2010-3-13 17:10:33 | 只看该作者

FCMOV 指令系列

和用于整数的 CMOV 指令类似,FCMOV 指令用于浮点值的条件传送。根据 EFLAGS 中的值,FCMOV 系列的指令把 FPU 寄存器 ST(x) 中的源操作数传送到 FPU 寄存器 FT(0) 中的目标操作数。如果条件为 true,就把 ST(x) 寄存器中的值传送到 ST(0) 寄存器中。

下表是 FCMOV 系列指令的说明:
指令
描述
FCMOVB
如果ST(0)小于ST(x),则进行传送
FCMOVE
如果ST(0)等于ST(x),则进行传送
FCMOVBE
如果ST(0)小于或者等于ST(x),则进行传送
FCMOVU
如果ST(0)无序,则进行传送
FCMOVNB
如果ST(0)不小于ST(x),则进行传送
FCMOVNE
如果ST(0)不等于ST(x),则进行传送
FCMOVNBE
如果ST(0)不小于或者等于ST(x),则进行传送
FCMOVNU
如果ST(0)非无序,则进行传送

指令的 GNU 格式是:
fcmovxx source, destination
上面,source 是 st(x) 寄存器,destination 是 st(0) 寄存器。

演示程序
.section .data
value1:
    .float 20.5
value2:
    .float 10.90

.section .text
.global _start
_start:
    nop
    finit
    flds value1
    flds value2
    fcomi %st(1), %st(0)
    fcmovb %st(1), %st(0)

    movl $1, %eax
    movl $0, %ebx
    int $0x80
说明
程序中,fcomi 指令会改变 EFLAGS 中的相应位。然后,fcmovb 根据这些相应位决定是否传送。因为 10.90 < 20.5 ,那么 fcmovb 进行传送,结果是 st1 和 st0 中的值都变为 20.5 。这在 gdb 中也可以看到:
st0            20.5    (raw 0x4003a400000000000000)
st1            20.5    (raw 0x4003a400000000000000)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-4 01:41 , Processed in 0.085797 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表