I am in a situation where I need to calculate something like size_t s=(size_t)floorf(f); . That is, the argument is a float, but it has an integer value (suppose that floorf(f) is small enough to be accurately represented). By optimizing this, I found something interesting.
Below are some conversions from float to integers (GCC 5.2.0-O3). For clarity, the above transformation is the return value of a test function.
Here int32_t x=(int32_t)f :
cvttss2si eax, xmm0 ret
Here uint32_t x=(uint32_t)f :
cvttss2si rax, xmm0 ret
Here int64_t x=(int64_t)f :
cvttss2si rax, xmm0 ret
Finally, here uint64_t x=(uint64_t)f; :
ucomiss xmm0, DWORD PTR .LC2[rip] jnb .L4 cvttss2si rax, xmm0 ret .L4: subss xmm0, DWORD PTR .LC2[rip] movabs rdx, -9223372036854775808 cvttss2si rax, xmm0 xor rax, rdx ret .LC2: .long 1593835520
This last one is much more complicated than the rest. Moreover, Clang and MSVC behave similarly. For your convenience, I translated it into pseudo-C:
float lc2 = (float)(); if (f<lc2) { return (uint64_t)f; } else { f -= lc2; uint64_t temp = (uint64_t)f; temp ^= ;
It looks like he is trying to correctly calculate the first overflow code 64. This seems like a fiction, since the documentation for cvttss2si tells me that if an overflow occurs (at 2 ^ 32, not 2 ^ 64), "an undefined integer value (80000000H) is returned."
My questions:
- What does it really do, and why?
- Why hasn’t something done the same for other integer types?
- How to change the transformation to create similar code (only output lines 3 and 4) (again, suppose the value is accurately represented)?
assembly floating-point
imallett
source share