xref: /freebsd/contrib/llvm-project/compiler-rt/lib/builtins/ppc/floattitf.c (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- lib/builtins/ppc/floattitf.c - Convert int128->long double -*-C -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements converting a signed 128 bit integer to a 128bit IBM /
10*0b57cec5SDimitry Andric // PowerPC long double (double-double) value.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include <stdint.h>
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric // Conversions from signed and unsigned 64-bit int to long double.
17*0b57cec5SDimitry Andric long double __floatditf(int64_t);
18*0b57cec5SDimitry Andric long double __floatunditf(uint64_t);
19*0b57cec5SDimitry Andric 
20*0b57cec5SDimitry Andric // Convert a signed 128-bit integer to long double.
21*0b57cec5SDimitry Andric // This uses the following property:  Let hi and lo be 64-bits each,
22*0b57cec5SDimitry Andric // and let signed_val_k() and unsigned_val_k() be the value of the
23*0b57cec5SDimitry Andric // argument interpreted as a signed or unsigned k-bit integer. Then,
24*0b57cec5SDimitry Andric //
25*0b57cec5SDimitry Andric // signed_val_128(hi,lo) = signed_val_64(hi) * 2^64 + unsigned_val_64(lo)
26*0b57cec5SDimitry Andric // = (long double)hi * 2^64 + (long double)lo,
27*0b57cec5SDimitry Andric //
28*0b57cec5SDimitry Andric // where (long double)hi and (long double)lo are signed and
29*0b57cec5SDimitry Andric // unsigned 64-bit integer to long double conversions, respectively.
__floattitf(__int128_t arg)30*0b57cec5SDimitry Andric long double __floattitf(__int128_t arg) {
31*0b57cec5SDimitry Andric   // Split the int128 argument into 64-bit high and low int64 parts.
32*0b57cec5SDimitry Andric   int64_t ArgHiPart = (int64_t)(arg >> 64);
33*0b57cec5SDimitry Andric   uint64_t ArgLoPart = (uint64_t)arg;
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric   // Convert each 64-bit part into long double. The high part
36*0b57cec5SDimitry Andric   // must be a signed conversion and the low part an unsigned conversion
37*0b57cec5SDimitry Andric   // to ensure the correct result.
38*0b57cec5SDimitry Andric   long double ConvertedHiPart = __floatditf(ArgHiPart);
39*0b57cec5SDimitry Andric   long double ConvertedLoPart = __floatunditf(ArgLoPart);
40*0b57cec5SDimitry Andric 
41*0b57cec5SDimitry Andric   // The low bit of ArgHiPart corresponds to the 2^64 bit in arg.
42*0b57cec5SDimitry Andric   // Multiply the high part by 2^64 to undo the right shift by 64-bits
43*0b57cec5SDimitry Andric   // done in the splitting. Then, add to the low part to obtain the
44*0b57cec5SDimitry Andric   // final result.
45*0b57cec5SDimitry Andric   return ((ConvertedHiPart * 0x1.0p64) + ConvertedLoPart);
46*0b57cec5SDimitry Andric }
47