_fixsfdi.c   [plain text]


/* 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;
}