When compiling
double isnan(double x){
return x!=x
}
both clang and gcc utilize the parity-flag PF
:
_Z6is_nand: # @_Z6is_nand
ucomisd %xmm0, %xmm0
setp %al
retq
However, the two possible outcomes of the comparison are:
NaN Not-Nan
ZF 1 1
PF 1 0
CF 1 0
that means it would be also possible to use the CF
-flag as alternative, i.e. setb
instead of setp
.
Are there any advantages of using setp
over setb
, or is it a coincidence, that both compilers use the parity flag?
PS: This question is the following up to Understanding compilation result for std::isnan
The advantage is that the compiler emits this code naturally without needing a special case to recognize x!=x
and transform it into !(x >= x)
.
Without -ffast-math, x != y
has to check PF to see if the comparison is ordered, then check ZF for equality. In special case where both inputs are the same, presumably normal optimization mechanisms like CSE can get rid of the ZF check, leaving only PF.
In this case, setb
wouldn't be worse, but it has absolutely no advantage, and it's more confusing for humans, and it probably needs more special-case code for the compiler to emit it.
Your suggested transformation would only be useful when using the result with special instruction that use CF, like adc
. For example, nan_counter += arr[i] != arr[i]
. That auto-vectorizes trivially (cmp_unord_ps
/ psubd
), but scalar cleanup (or a scalar use-case over non-array inputs) could use ucomiss
/ adc $0, %eax
instead of ucomiss
/ setp
/ add
.
That saves an instruction, and a uop on Broadwell and later, and on AMD. (Earlier Intel CPUs have 2 uop adc, unless they special-case $0
, because they don't support 3-input uops)
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