]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/ppc/fixunstfti.c
Merge LLVM libunwind trunk r351319, from just before upstream's
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / ppc / fixunstfti.c
1 //===-- lib/builtins/ppc/fixunstfti.c - Convert long double->int128 *-C -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements converting the 128bit IBM/PowerPC long double (double-
11 // double) data type to an unsigned 128 bit integer.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "../int_math.h"
16 #define BIAS 1023
17
18 /* Convert long double into an unsigned 128-bit integer. */
19 __uint128_t __fixunstfti(long double input) {
20
21   /* If we are trying to convert a NaN, return the NaN bit pattern. */
22   if (crt_isnan(input)) {
23     return ((__uint128_t)0x7FF8000000000000ll) << 64 |
24            (__uint128_t)0x0000000000000000ll;
25   }
26
27   __uint128_t result, hiResult, loResult;
28   int hiExponent, loExponent, shift;
29   /* The long double representation, with the high and low portions of
30    * the long double, and the corresponding bit patterns of each double. */
31   union {
32     long double ld;
33     double d[2]; /* [0] is the high double, [1] is the low double. */
34     unsigned long long ull[2]; /* High and low doubles as 64-bit integers. */
35   } ldUnion;
36
37   /* If the long double is less than 1.0 or negative,
38    * return 0.0. */
39   if (input < 1.0)
40     return 0.0;
41
42   /* Retrieve the 64-bit patterns of high and low doubles.
43    * Compute the unbiased exponent of both high and low doubles by
44    * removing the signs, isolating the exponent, and subtracting
45    * the bias from it. */
46   ldUnion.ld = input;
47   hiExponent = ((ldUnion.ull[0] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
48   loExponent = ((ldUnion.ull[1] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
49
50   /* Convert each double into int64; they will be added to the int128 result.
51    * CASE 1: High or low double fits in int64
52    *      - Convert the each double normally into int64.
53    *
54    * CASE 2: High or low double does not fit in int64
55    *      - Scale the double to fit within a 64-bit integer
56    *      - Calculate the shift (amount to scale the double by in the int128)
57    *      - Clear all the bits of the exponent (with 0x800FFFFFFFFFFFFF)
58    *      - Add BIAS+53 (0x4350000000000000) to exponent to correct the value
59    *      - Scale (move) the double to the correct place in the int128
60    *        (Move it by 2^53 places)
61    *
62    * Note: If the high double is assumed to be positive, an unsigned conversion
63    * from long double to 64-bit integer is needed. The low double can be either
64    * positive or negative, so a signed conversion is needed to retain the result
65    * of the low double and to ensure it does not simply get converted to 0. */
66
67   /* CASE 1 - High double fits in int64. */
68   if (hiExponent < 63) {
69     hiResult = (unsigned long long)ldUnion.d[0];
70   } else if (hiExponent < 128) {
71     /* CASE 2 - High double does not fit in int64, scale and convert it. */
72     shift = hiExponent - 54;
73     ldUnion.ull[0] &= 0x800FFFFFFFFFFFFFll;
74     ldUnion.ull[0] |= 0x4350000000000000ll;
75     hiResult = (unsigned long long)ldUnion.d[0];
76     hiResult <<= shift;
77   } else {
78     /* Detect cases for overflow. When the exponent of the high
79      * double is greater than 128 bits and when the long double
80      * input is positive, return the max 128-bit integer.
81      * For negative inputs with exponents > 128, return 1, like gcc. */
82     if (ldUnion.d[0] > 0) {
83       return ((__uint128_t)0xFFFFFFFFFFFFFFFFll) << 64 |
84              (__uint128_t)0xFFFFFFFFFFFFFFFFll;
85     } else {
86       return ((__uint128_t)0x0000000000000000ll) << 64 |
87              (__uint128_t)0x0000000000000001ll;
88     }
89   }
90
91   /* CASE 1 - Low double fits in int64. */
92   if (loExponent < 63) {
93     loResult = (long long)ldUnion.d[1];
94   } else {
95     /* CASE 2 - Low double does not fit in int64, scale and convert it. */
96     shift = loExponent - 54;
97     ldUnion.ull[1] &= 0x800FFFFFFFFFFFFFll;
98     ldUnion.ull[1] |= 0x4350000000000000ll;
99     loResult = (long long)ldUnion.d[1];
100     loResult <<= shift;
101   }
102
103   /* Add the high and low doublewords together to form a 128 bit integer. */
104   result = loResult + hiResult;
105   return result;
106 }