_fixunsdfdi.c   [plain text]


/* APPLE LOCAL file 5316398 improved float/double -> int64 functions */
#include <stdint.h>

uint64_t
__fixunsdfdi (double x)
{
  union { double d; uint64_t u; uint32_t u32[2]; } u = {x};
  uint32_t hi = u.u >> 32;
  uint32_t lo;

  /* Early out for the common case: +0 <= x < 0x1.0p32 */
  if (__builtin_expect (hi < 0x41f00000U, 1))
    return (uint64_t) ((uint32_t) x);

  /* 0x1.0p32 <= x < 0x1.0p64 */
  if (__builtin_expect (hi < 0x43f00000U, 1))
    {
      /* if x < 0x1.0p52 */
      if (__builtin_expect (hi < 0x43400000U, 1))
	{
	  if (__builtin_expect (hi < 0x43300000U, 1))
	    {
	      uint32_t shift = (1023 + 52) - (hi >> 20);
	      uint32_t unitBit = 1U << shift;
	      uint32_t fractMask = unitBit - 1;
	      u.u32[0] = lo = (uint32_t) u.u & ~fractMask;
	      x -= u.d;
	      hi &= 0x000FFFFFU;
	      hi |= 0x00100000U;
	      lo = (lo >> shift) | (hi << (32 - shift));
	      /* (int32_t) x is always zero here. This sets the inexact 
	         flag. */
	      hi = (hi >> shift) + (int32_t) x;
	    }
	  else
	    {
	      u.u &= 0x000FFFFFFFFFFFFFULL;
	      u.u |= 0x0010000000000000ULL;
	      return u.u;
	    }
	}
      else
	{
	  uint32_t shift = (hi >> 20) - (1023 + 52);
	  hi &= 0x000FFFFFU;
	  lo = u.u;
	  hi |= 0x00100000U;

	  hi = (hi << shift) | (lo >> (32 - shift));
	  lo = lo << shift;
	}

      /* return the result; */
      return ((uint64_t) hi << 32) | lo;
    }

  /* x <= -0 or x >= 0x1.0p64 or x is NaN. set invalid as necessary.
     Pin according to ARM rules. */
  hi = x;

  /* promote to 64-bits */
  lo = (hi << 1) | (hi & 1);
  return ((uint64_t) hi << 32) | lo;
}