]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/ppc/floattitf.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / ppc / floattitf.c
1 //===-- lib/builtins/ppc/floattitf.c - Convert int128->long double -*-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 a signed 128 bit integer to a 128bit IBM /
11 // PowerPC long double (double-double) value.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include <stdint.h>
16
17 /* Conversions from signed and unsigned 64-bit int to long double. */
18 long double __floatditf(int64_t);
19 long double __floatunditf(uint64_t);
20
21 /* Convert a signed 128-bit integer to long double.
22  * This uses the following property:  Let hi and lo be 64-bits each,
23  * and let signed_val_k() and unsigned_val_k() be the value of the
24  * argument interpreted as a signed or unsigned k-bit integer. Then,
25  *
26  * signed_val_128(hi,lo) = signed_val_64(hi) * 2^64 + unsigned_val_64(lo)
27  * = (long double)hi * 2^64 + (long double)lo,
28  *
29  * where (long double)hi and (long double)lo are signed and
30  * unsigned 64-bit integer to long double conversions, respectively.
31  */
32 long double __floattitf(__int128_t arg) {
33   /* Split the int128 argument into 64-bit high and low int64 parts. */
34   int64_t ArgHiPart = (int64_t)(arg >> 64);
35   uint64_t ArgLoPart = (uint64_t)arg;
36
37   /* Convert each 64-bit part into long double. The high part
38    * must be a signed conversion and the low part an unsigned conversion
39    * to ensure the correct result. */
40   long double ConvertedHiPart = __floatditf(ArgHiPart);
41   long double ConvertedLoPart = __floatunditf(ArgLoPart);
42
43   /* The low bit of ArgHiPart corresponds to the 2^64 bit in arg.
44    * Multiply the high part by 2^64 to undo the right shift by 64-bits
45    * done in the splitting. Then, add to the low part to obtain the
46    * final result. */
47   return ((ConvertedHiPart * 0x1.0p64) + ConvertedLoPart);
48 }