如何将NaN插入xmm寄存器?

9

对于我正在编写的函数,如果输入没有意义,我希望返回NaN。

最简单的方法是如何将NaN插入xmm寄存器?


1
你如何确定哪个“输入没有意义”?如果这是比较的结果,你可以将“正常”结果与比较的结果掩码按位或运算。 - chtz
1个回答

13

全为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。

返回值为mulsdaddsd(或divsd)的结果还具有这样一个优点:如果调用者在循环中反复使用该寄存器,则它不会具有域交叉旁路延迟。(在Sandybridge系列上,这将持续很长时间。例如,即使xmm0来自pcmpeqd,每个addsd xmm1,xmm0从xmm1输入到xmm1输出都会增加一个周期的延迟,即使那已经很久以前,整数SIMD uop已经退役。)


如果使用cmpsdcmppd,甚至可以无需分支就完成它:您可以将0 / -1掩码orps到结果中,使其成为NaN或不变。如果某些其他计算将(或已经)设置了FP无效标志,或者如果您不关心它,那么您就可以使用该方法。

注意不要通过额外的cmp / or延长关键路径;如果您认为它很少发生,您可能仍然想比较和分支,例如在movmskpd / test eax,eax / jnz上,对于cmppd结果进行测试以查看任一位是否设置=> SIMD元素之一未能通过某些检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接