3 ms·
`nextafterf` does not in fact return 0. FTZ flushes denormals to zero when they are the result of an FP calculation, but `nextafter` is implemented using intege
by ridiculous_fish 4y ago
`nextafterf` does not in fact return 0. FTZ flushes denormals to zero when they are the result of an FP calculation, but `nextafter` is implemented using integer arithmetic, because it is much easier: simply add 1 as an integer, with special handling for Inf/NaN/-0.
It's only later that it gets treated as zero by DAZ: in the FP comparison, and then the call to ceil(), both of which use the FPU.
edit: confirmed, you can see it in action on this gist. When compiled with -ffast-math then the denormal does not compare greater than zero (it is flushed to zero by the comparison), but its bit pattern is integer value 1, which is nextafter(0).
https://gist.github.com/ridiculousfish/bfa7ed6b1d76c114e19b379e1b9be16f https://gist.github.com/ridiculousfish/bfa7ed6b1d76c114e19b3...
- moyix 4y agoI don't think this is correct. The return value of nextafterf is a float, and the ABI requires those to be returned in xmm0. So although nextafterf is using integers internally, the flush to zero happens inside of nextafterf when it moves eax into xmm0; even though eax is 1, xmm0 becomes 0.0. You can see that by stepping through it in gdb: https://gist.github.com/moyix/846afb7fcec7c618a6ef52d93b4ca7b9 https://gist.github.com/moyix/846afb7fcec7c618a6ef52d93b4ca7...
- ridiculous_fish 4y agoDenormals are not flushed to zero merely by `mov xmm,rax` - they can't be, since xmm is also used for integer arithmetic, and the CPU doesn't "know" whether it's an FP or integer value at the point of the mov. Your gist demonstrates this: notice in the bottom right that xmm0 contains `v2_int64 = {0x1, 0x0}` so the bottom half containing the result is nonzero. (The top half is zero as it's unused). The "info" command rounds the value to 0 for compactness, but if you run `p $xmm0.v2_double` you will also see it is nonzero when interpreted as a double (I get 4.94e-324). A fun aside: that `mulss` instruction you stopped at is just there to raise an underflow FP exception; its result is discarded. https://github.com/bminor/glibc/blob/595c22ecd8e87a27fd19270ed30fdbae9ad25426/math/s_nextafter.c#L81 https://github.com/bminor/glibc/blob/595c22ecd8e87a27fd19270...
- moyix 4y agoAh you're right! I was misled by the `v4_float = {0x0, 0x0, 0x0, 0x0}` portion.