xref: /netbsd-src/sys/external/bsd/compiler_rt/dist/lib/builtins/floatdidf.c (revision d31434597b255f3fd7646698e04170d148f1de49)
1156cd587Sjoerg /*===-- floatdidf.c - Implement __floatdidf -------------------------------===
2156cd587Sjoerg  *
3156cd587Sjoerg  *                     The LLVM Compiler Infrastructure
4156cd587Sjoerg  *
5156cd587Sjoerg  * This file is dual licensed under the MIT and the University of Illinois Open
6156cd587Sjoerg  * Source Licenses. See LICENSE.TXT for details.
7156cd587Sjoerg  *
8156cd587Sjoerg  *===----------------------------------------------------------------------===
9156cd587Sjoerg  *
10156cd587Sjoerg  * This file implements __floatdidf for the compiler_rt library.
11156cd587Sjoerg  *
12156cd587Sjoerg  *===----------------------------------------------------------------------===
13156cd587Sjoerg  */
14156cd587Sjoerg 
15156cd587Sjoerg #include "int_lib.h"
16156cd587Sjoerg 
17156cd587Sjoerg /* Returns: convert a to a double, rounding toward even. */
18156cd587Sjoerg 
19156cd587Sjoerg /* Assumption: double is a IEEE 64 bit floating point type
20156cd587Sjoerg  *             di_int is a 64 bit integral type
21156cd587Sjoerg  */
22156cd587Sjoerg 
23156cd587Sjoerg /* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
24156cd587Sjoerg 
25156cd587Sjoerg #ifndef __SOFT_FP__
26156cd587Sjoerg /* Support for systems that have hardware floating-point; we'll set the inexact flag
27156cd587Sjoerg  * as a side-effect of this computation.
28156cd587Sjoerg  */
29156cd587Sjoerg 
30156cd587Sjoerg COMPILER_RT_ABI double
__floatdidf(di_int a)31156cd587Sjoerg __floatdidf(di_int a)
32156cd587Sjoerg {
33ef84fd3bSjoerg 	static const double twop52 = 4503599627370496.0; // 0x1.0p52
34ef84fd3bSjoerg 	static const double twop32 = 4294967296.0; // 0x1.0p32
35156cd587Sjoerg 
36156cd587Sjoerg 	union { int64_t x; double d; } low = { .d = twop52 };
37156cd587Sjoerg 
38156cd587Sjoerg 	const double high = (int32_t)(a >> 32) * twop32;
39156cd587Sjoerg 	low.x |= a & INT64_C(0x00000000ffffffff);
40156cd587Sjoerg 
41156cd587Sjoerg 	const double result = (high - twop52) + low.d;
42156cd587Sjoerg 	return result;
43156cd587Sjoerg }
44156cd587Sjoerg 
45156cd587Sjoerg #else
46156cd587Sjoerg /* Support for systems that don't have hardware floating-point; there are no flags to
47156cd587Sjoerg  * set, and we don't want to code-gen to an unknown soft-float implementation.
48156cd587Sjoerg  */
49156cd587Sjoerg 
50156cd587Sjoerg COMPILER_RT_ABI double
__floatdidf(di_int a)51156cd587Sjoerg __floatdidf(di_int a)
52156cd587Sjoerg {
53156cd587Sjoerg     if (a == 0)
54156cd587Sjoerg         return 0.0;
55156cd587Sjoerg     const unsigned N = sizeof(di_int) * CHAR_BIT;
56156cd587Sjoerg     const di_int s = a >> (N-1);
57156cd587Sjoerg     a = (a ^ s) - s;
58156cd587Sjoerg     int sd = N - __builtin_clzll(a);  /* number of significant digits */
59156cd587Sjoerg     int e = sd - 1;             /* exponent */
60156cd587Sjoerg     if (sd > DBL_MANT_DIG)
61156cd587Sjoerg     {
62156cd587Sjoerg         /*  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
63156cd587Sjoerg          *  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
64156cd587Sjoerg          *                                                12345678901234567890123456
65156cd587Sjoerg          *  1 = msb 1 bit
66156cd587Sjoerg          *  P = bit DBL_MANT_DIG-1 bits to the right of 1
67156cd587Sjoerg          * Q = bit DBL_MANT_DIG bits to the right of 1
68156cd587Sjoerg          *  R = "or" of all bits to the right of Q
69156cd587Sjoerg         */
70156cd587Sjoerg         switch (sd)
71156cd587Sjoerg         {
72156cd587Sjoerg         case DBL_MANT_DIG + 1:
73156cd587Sjoerg             a <<= 1;
74156cd587Sjoerg             break;
75156cd587Sjoerg         case DBL_MANT_DIG + 2:
76156cd587Sjoerg             break;
77156cd587Sjoerg         default:
78156cd587Sjoerg             a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) |
79156cd587Sjoerg                 ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
80156cd587Sjoerg         };
81156cd587Sjoerg         /* finish: */
82156cd587Sjoerg         a |= (a & 4) != 0;  /* Or P into R */
83156cd587Sjoerg         ++a;  /* round - this step may add a significant bit */
84156cd587Sjoerg         a >>= 2;  /* dump Q and R */
85156cd587Sjoerg         /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
86156cd587Sjoerg         if (a & ((du_int)1 << DBL_MANT_DIG))
87156cd587Sjoerg         {
88156cd587Sjoerg             a >>= 1;
89156cd587Sjoerg             ++e;
90156cd587Sjoerg         }
91156cd587Sjoerg         /* a is now rounded to DBL_MANT_DIG bits */
92156cd587Sjoerg     }
93156cd587Sjoerg     else
94156cd587Sjoerg     {
95156cd587Sjoerg         a <<= (DBL_MANT_DIG - sd);
96156cd587Sjoerg         /* a is now rounded to DBL_MANT_DIG bits */
97156cd587Sjoerg     }
98156cd587Sjoerg     double_bits fb;
9968f0e74dSmartin     fb.u.s.high = ((su_int)s & 0x80000000) |        /* sign */
100156cd587Sjoerg                 ((e + 1023) << 20)      |        /* exponent */
101156cd587Sjoerg                 ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
10268f0e74dSmartin     fb.u.s.low = (su_int)a;                         /* mantissa-low */
103156cd587Sjoerg     return fb.f;
104156cd587Sjoerg }
105156cd587Sjoerg #endif
1063044ee7eSrin 
107559b00edSrin #if defined(__ARM_EABI__)
108*d3143459Srin #if defined(COMPILER_RT_ARMHF_TARGET)
__aeabi_l2d(di_int a)1093044ee7eSrin AEABI_RTABI double __aeabi_l2d(di_int a) {
1103044ee7eSrin   return __floatdidf(a);
1113044ee7eSrin }
112*d3143459Srin #else
113*d3143459Srin AEABI_RTABI double __aeabi_l2d(di_int a) COMPILER_RT_ALIAS(__floatdidf);
1143044ee7eSrin #endif
115*d3143459Srin #endif
116