I always assumed, that there is practically no difference between testing for NAN
via
x!=x
or
std::isnan(x)
However, gcc provides different assemblers for both versions (live on godbolt.org):
;x!=x:
ucomisd %xmm0, %xmm0
movl $1, %edx
setne %al
cmovp %edx, %eax
ret
;std::isnan(x)
ucomisd %xmm0, %xmm0
setp %al
ret
However, I'm struggling to understand both version. My naive try to compile std::isnan(x)
would be:
ucomisd %xmm0, %xmm0
setne %al ;return true when not equal
ret
but I must be missing something.
Probably, there is missed optimization in the x!=x
-version (Edit: it is probably a regression in gcc-8.1).
My question is, why is the parity flag (setp
, PF=1
) and not the equal flag (setne
, ZF=0
) used in the second version?
The result of x!=x
is due to a regression introduced to gcc-8, clang produces the same assembler for both versions.
My misunderstanding about the way ucomisd
is functioning was pointed out by @tkausl. The result of this operation can be:
unordered < > ==
ZF 1 0 0 1
PF 1 0 1 0
CF 1 1 0 0
In the case of ucomisd %xmm0, %xmm
only the outcomes "unordered" and "==" are possible.
The case of NaN
is unordered and for this ZF is set the same as in the case of ==
. Thus we can use the flags PF
and CF
to differentiate between two possible outcomes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With