Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there advantages of using `setp` instead of `setb`?

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

like image 490
ead Avatar asked Jul 16 '18 19:07

ead


1 Answers

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)

like image 198
Peter Cordes Avatar answered Nov 03 '22 23:11

Peter Cordes