diff options
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/config/arm/_fixsfdi.c')
-rw-r--r-- | gcc-4.2.1-5666.3/gcc/config/arm/_fixsfdi.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/config/arm/_fixsfdi.c b/gcc-4.2.1-5666.3/gcc/config/arm/_fixsfdi.c new file mode 100644 index 000000000..f248c95a4 --- /dev/null +++ b/gcc-4.2.1-5666.3/gcc/config/arm/_fixsfdi.c @@ -0,0 +1,54 @@ +/* APPLE LOCAL file 5316398 improved float/double -> int64 functions */ +#include <stdint.h> + +int64_t +__fixsfdi (float x) +{ + union { float f; uint32_t u; } u = {x}; + uint32_t fabsx = u.u & 0x7fffffffU; + uint32_t exp = fabsx >> 23; + int64_t result = 0; + + /* for small ints, overflow and NaN, the int32_t converter works fine + if( |x| < 0x1.0p31f || |x| >= 1.0p64f || isnan(x) ) unsigned + compare */ + if (exp - (127U + 31U) >= (63U - 31U)) + { + if (exp > (127 + 31)) + { + if (x == -0x1.0p63f) + return 0x8000000000000000LL; + + uint32_t r = (int32_t) x; + result = (int64_t) r << 32; + r = (r << 1) | (r & 1); + result |= r; + return result; + } + + /* small number. Regular int32_t conversion will work fine here. */ + result = (int32_t) x; + return result; + } + + /* 0x1.0p31 <= |x| <0x1.0p64, x is always an integer in this range */ + + /* convert float to fixed */ + result = (fabsx & 0x007fffffU) | 0x00800000; + + /* signMask = x < 0.0f ? -1LL : 0 */ + int64_t signMask = (int64_t) u.u << 32; + signMask >>= 63; + + /* Calculate shift value to move fixed point to right place */ + int32_t leftShift = exp - (127 + 23); + + /* move the fixed point into place */ + result <<= leftShift; + + /* Fix sign */ + result ^= signMask; + result -= signMask; + + return result; +} |