回答:
すべて1は、静かな(非シグナリング、別名通常)NaNです。1を生成する最も簡単な方法は、SSE2 pcmpeqd xmm0,xmm0
を使用して、レジスタのすべてのビットを1
、つまり2の補数の整数に設定すること-1
です。(CPUレジスタのすべてのビットを1に効率的に設定します / オンザフライでベクトル定数を生成するのに最適な命令シーケンスは何ですか?)
実際には-NaN
-符号ビットが設定されています。整数の右シフト(psrld xmm0,1
)を検討するか、それが望ましくない場合はゼロ/ゼロ(xorps xmm0,xmm0
/ divpd xmm0,xmm0
)で除算してください。
NaNを返したい数学関数は、FPCSRで無効なスティッキー例外ビットが MXCSR に設定されていることを確認することも必要です(または、呼び出し元が例外をマスクしない場合は、実際に例外を発生させます)。これを行うには、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
or addsd
(またはdivsd
)の結果が戻り値になることには、呼び出し元がそのレジスタをループで繰り返し使用する場合に、ドメイン横断バイパスレイテンシがないという利点もあります。(Sandybridgeファミリでは、これは永遠に続きます。たとえばaddsd xmm1, xmm0
、xmm0がから来たpcmpeqd
場合、それがずっと前で、整数SIMD uopがすでに廃止されていたとしても、xmm1入力からxmm1出力までのレイテンシの追加サイクルがあります。)
cmpsd
or を使用すると、ブランチなしでそれを実行できる場合もあります。結果を0 / -1でマスクして、NaNまたは未変更にすることcmppd
ができますorps
。他の計算でFP-invalidフラグが設定される場合(または既に設定されている場合)、またはそれを気にしない場合は、すべて設定されています。
追加のcmp /またはでクリティカルパスを長くすることに注意してください。それが非常にまれであると予想する場合は、どちらか一方のビットが設定されているかどうかを確認するために、たとえばcmppd結果でmovmskpd
/ test eax,eax
/を使用jnz
して比較して分岐する可能性があります。