【问题标题】:How can you insert a NaN into a xmm register?如何将 NaN 插入 xmm 寄存器?
【发布时间】:2020-05-07 08:18:59
【问题描述】:

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

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

【问题讨论】:

  • 你如何确定哪个“输入没有意义”?如果这是比较的结果,您可以使用比较的结果掩码按位或“正常”结果。

标签: assembly x86 nan sse


【解决方案1】:

All-ones 是一个安静的(非信号,也就是正常的)NaN,这就是你想要的。最简单的方法是使用 SSE2 pcmpeqd xmm0,xmm0 将寄存器中的每一位设置为 1,即 2 的补码整数 -1。 (Set all bits in CPU register to 1 efficiently/What are the best instruction sequences to generate vector constants on the fly?)

它实际上是一个-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

mulss 用于单精度floatmulpd / mulps 也是合适的。

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

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


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

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

【讨论】:

    猜你喜欢
    • 2012-04-27
    • 2020-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-29
    • 2020-02-14
    相关资源
    最近更新 更多