如何将 NaN 插入 xmm 寄存器?

Mar*_*kus 9 x86 assembly sse nan

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

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

Pet*_*des 13

All-ones 是一个安静的(无信号,又名正常)NaN,这就是您想要的。产生 1 的最简单方法是使用 SSE2pcmpeqd xmm0,xmm0将寄存器中的每一位设置为1,即 2 的补码整数-1。(有效地将 CPU 寄存器中的所有位设置为 1 / 动态生成向量常量的最佳指令序列是什么?

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


想要返回 NaN 的数学函数通常还想确保在 MXCSR 中设置了 FP 无效的粘性异常位(或者如果您的调用者取消屏蔽该异常,则实际上引发异常)。要做到,你可以乘或与自身添加为NaN。例如

    ...
.error_return_path:
    pcmpeqd   xmm0, xmm0
    mulsd     xmm0, xmm0       ; Cause an FP-invalid operation.
    ret
Run Code Online (Sandbox Code Playgroud)

或者mulss对于单精度float. mulpd/mulps也是合适的。

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

将返回值作为mulsdor addsd(or divsd)的结果还具有以下优点:如果调用者在循环中重复使用该寄存器,则不会有跨域绕过延迟。(在 Sandybridge 系列上,这addsd xmm1, xmm0将永远持续下去。例如,如果 xmm0 来自pcmpeqd,每个从 xmm1 输入到 xmm1 输出的延迟周期都将延长,即使那是很久以前并且整数 SIMD uop 已经退役。)


如果您使用cmpsdor ,您甚至可以无分支地执行此操作cmppd:您可以orps将 0 / -1 掩码转换为结果以使其为 NaN 或不变。如果某些其他计算将(或已经)设置 FP-invalid 标志,或者如果您不关心这一点,那么您都已设置好。

小心使用额外的 cmp / 或延长关键路径;如果你希望它是超级罕见的,你可能仍然相当比较和分支,例如用movmskpd/ test eax,eax/jnz上cmppd结果,看看是否任何位被设置的SIMD元素=>一个失败的一些检查。