【发布时间】:2016-09-13 15:21:59
【问题描述】:
我正在阅读有关数学协处理器 (Paul Carters PC Assembly Book) 及其进行浮点计算的指令(在 ASM i386 上)。然后我遇到了以下代码,它应该返回两个给定双精度值中较大的双精度值(C 调用约定):
1 %define d1 ebp+8
2 %define d2 ebp+16
3 global dmax
4
5 segment .text
6 dmax:
7 enter 0,0
8
9 fld qword [d2]
10 fld qword [d1] ;Now ST0 = d1 and ST1 = d2
11 fcomip st1 ;Compares ST0 with ST1 and pops ST0 out
12 jna short d2_bigger ;If not above (ST0<ST1)
13 fcomp st0 ;Get rid of ST0, which is actually d2 now (line 11)
14 fld qword [d1]
15 jmp short exit
16 d2_bigger:
17 exit:
18 leave
19 ret
我正在考虑更改此代码的两件事。首先,我可能会在比较(第 11 行)中使用 FCOMI 而不是 FCOMIP 以避免 1 个不必要的协处理器寄存器弹出。这样做,如果 ST0=ST1 根本就没有弹出(因为它已经在堆栈的顶部)。我可以看到不这样做的唯一原因是它会留下一个非空的协处理器寄存器堆栈。但是,我认为 C 的唯一相关值是 ST0,这将是 double 函数的返回值。如果另一个函数将超过 8 个浮点/双精度值推送到协处理器堆栈,存储在协处理器堆栈 (ST7) 的最低成员中的值不会被丢弃吗?那么在不清除协处理器堆栈的情况下离开函数真的是个问题吗? => (阅读编辑)
我想改变的第二件事是我可能不会使用第 13 行的指令 FCOMP。我理解 将 ST0 从堆栈中弹出的原因使 ST1 到达顶部。但是,我认为进行整体比较并设置协处理器标志只是为了弹出值有点开销。我寻找仅用于弹出 ST0 的指令,显然没有。我认为使用FADDP ST0, ST0(将ST0 添加到ST0 并弹出ST0)或FSTP ST0(将ST0 的值存储到ST0 并弹出ST0)会更快。它们只是在我的脑海中看起来像是协处理器的工作量减少了。
我尝试测试 3 个选项的速度(上面代码中的一个,FSTP ST0 和 FADDP ST0, ST0),经过几次快速测试后,它们都以非常相似的速度运行。从价值观中得出结论有点不准确。 显然FADDP ST0,ST0 快一点,然后是FSTP ST0,最后是FCOMP ST0。 是否有关于使用哪一个的建议? 还是我太在意对整体速度影响如此微不足道的事情?
我只是问自己,因为 Assembly 是以尽可能快的方式做事,也许在其中一种方法之间进行选择可能会有好处。
编辑:
我正在阅读 Intel 64 和 IA-32 指令集参考,如果堆栈上溢或下溢(异常 #IS),协处理器显然会引发异常。所以使用堆栈而不是清空它(在这种情况下,只留下 ST0 以便 C 将弹出它的返回值)显然不是一个选项。
【问题讨论】:
-
世界正在迅速耗尽这种代码仍然有意义的机器。特别是当您使用汇编时。请改用 SSE2 代码。如果您不知道它是什么样子,请使用最新的 C 编译器。
-
@HansPassant IIRC NASA 在卫星中确实坚持使用旧的 386-486 CPU 有一段时间了。凭借它们的大晶体管,它们不太容易受到改变某些位值的宇宙射线的影响。但这是几年前的信息,我不知道目前的状态。 :) 在其他地方,它可能与您编写的一样,SSE2 和更多可用。
-
@Ped7g:这使用了 FCOMI,它只在 p6 上可用。
标签: performance assembly floating-point x86 x87