对于我正在编写的函数,如果输入没有意义,我希望返回NaN。
最简单的方法是如何将NaN插入xmm寄存器?
全为1(All-ones)是一个静默(非信号传递,也称为正常)的 NaN,这就是您想要的。最简单的方法是使用 SSE2 pcmpeqd xmm0,xmm0
指令将寄存器中的每个位都设置为 1
,即二进制补码整数 -1
。(高效设置 CPU 寄存器中所有位为 1 / 生成动态向量常量的最佳指令序列是什么?)
实际上这是一个负的 NaN,即符号位为 1。如果不需要这种情况,可以考虑使用整数右移操作 (psrld xmm0,1
) 或者除以零(xorps xmm0,xmm0
/ divpd xmm0,xmm0
)。
数学函数常常希望返回 NaN 并确保浮点无效异常粘附(sticky)位被设置在 MXCSR 中(或者实际上会引发异常,如果调用方未屏蔽该异常)。为了实现这一点,您可以将 NaN 与自身相乘或相加。例如:
...
.error_return_path:
pcmpeqd xmm0, xmm0
mulsd xmm0, xmm0 ; Cause an FP-invalid operation.
ret
对于单精度浮点数,可以使用mulss
。此外,也可以使用mulpd
/ mulps
。
将NaN与NaN相乘或相加的位模式肯定仍然是NaN,并且应该仍然具有相同的有效负载,因此仍然都是全1。
返回值为mulsd
或addsd
(或divsd
)的结果还具有这样一个优点:如果调用者在循环中反复使用该寄存器,则它不会具有域交叉旁路延迟。(在Sandybridge系列上,这将持续很长时间。例如,即使xmm0来自pcmpeqd
,每个addsd xmm1,xmm0
从xmm1输入到xmm1输出都会增加一个周期的延迟,即使那已经很久以前,整数SIMD uop已经退役。)
如果使用cmpsd
或cmppd
,甚至可以无需分支就完成它:您可以将0 / -1掩码orps
到结果中,使其成为NaN或不变。如果某些其他计算将(或已经)设置了FP无效标志,或者如果您不关心它,那么您就可以使用该方法。
注意不要通过额外的cmp / or延长关键路径;如果您认为它很少发生,您可能仍然想比较和分支,例如在movmskpd
/ test eax,eax
/ jnz
上,对于cmppd结果进行测试以查看任一位是否设置=> SIMD元素之一未能通过某些检查。