Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding compilation result for std::isnan

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?

like image 354
ead Avatar asked Jul 11 '18 21:07

ead


1 Answers

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.

like image 155
ead Avatar answered Oct 03 '22 09:10

ead