aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/config/arm/_fixunsdfdi.c
blob: 98fcc8f53b7633a43d44e63df57c6c64169b0d65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* 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;
}