Answers:
All-ones是一个安静的(非信令,又称正常)NaN,这就是您想要的。产生一个的最简单方法是使用SSE2 pcmpeqd 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
或mulss
用于单精度float
。 mulpd
/ mulps
也将是适当的。
将NaN与NaN相乘或相加的位模式肯定仍然是NaN,并且仍然应该是相同的有效负载,因此仍然是全1。
将返回值作为mulsd
或addsd
(或divsd
)的结果还具有以下优点:如果调用方在循环中重复使用该寄存器,则不会有跨域旁路等待时间。(在Sandybridge系列上,这种情况addsd xmm1, xmm0
将永远持续下去。例如pcmpeqd
,即使xmm0来自,即使从很早以前开始,并且整数SIMD uop已经退休,从xmm1输入到xmm1输出的每个延迟都会有一个额外的延迟周期。)
如果使用cmpsd
或,您甚至可以无分支地进行此操作cmppd
:您可以orps
将0 / -1掩码转换为结果以使其为NaN或保持不变。如果其他一些计算将(或已经)设置了FP-invalid标志,或者如果您对此不关心,则全部设置完毕。
提防使用额外的cmp延长关键路径/或;如果您认为它非常稀有,则最好还是比较并分支,例如对cmppd结果使用movmskpd
/ test eax,eax
/ jnz
来查看是否设置了任何一位=> SIMD元素之一未通过某些检查。