如何将 NaN 插入 xmm 寄存器?

How can you insert a NaN into a xmm register?

对于我正在编写的函数,如果输入没有意义,我想 return 一个 Nan。

如何以最简单的方式将 NaN 插入 xmm 寄存器

全一是一个安静的(非信号,又名正常)NaN,这就是你想要的。生成一个的最简单方法是使用 SSE2 pcmpeqd xmm0,xmm0 将寄存器中的每一位设置为 1,即 2 的补码整数 -1。 ( / )

它实际上是一个 -NaN - 设置了符号位。如果不需要,请考虑整数右移 (psrld xmm0,1) 或除以零/零 (xorps xmm0,xmm0 / divpd xmm0,xmm0)。


想要 return NaN 的数学函数通常还想确保 MXCSR 中的 FP 无效粘性异常位被设置 (或者实际上引发异常,如果您的来电者揭露了该异常)。要做到 that,您可以将 NaN 与其自身相乘或相加。例如

    ...
.error_return_path:
    pcmpeqd   xmm0, xmm0
    mulsd     xmm0, xmm0       ; Cause an FP-invalid operation.
    ret

mulss单精度floatmulpd / mulps 也合适。

NaN 与 NaN 相乘或相加的位模式肯定仍然是 NaN,并且应该仍然是相同的有效负载,所以仍然是全一。

将 return 值作为 mulsdaddsd(或 divsd)的结果还有一个优点,即如果调用者在循环,它不会有跨域旁路延迟。 (在 Sandybridge 系列上,这会持续到永远。例如,如果 xmm0 来自 pcmpeqd,每个 addsd xmm1, xmm0 都会有一个额外的从 xmm1 输入到 xmm1 输出的延迟周期,即使那是很久以前的事,而且整数- SIMD uop 已经退役了。)


如果您使用 cmpsdcmppd,您甚至可以无分支地执行此操作:您可以 orps 将 0 / -1 掩码到结果中以使其成为 NaN 或不变。如果其他一些计算将(或已经)设置 FP-invalid 标志,或者如果您不关心它,那么您已经准备就绪。

注意不要用额外的 cmp / or 来延长关键路径;如果您希望它非常罕见,您可能宁愿比较和分支,例如在 cmppd 结果上使用 movmskpd / test eax,eax / jnz 查看是否设置了任一位 => 其中一个 SIMD 元素未通过某些检查。