• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Bit representation of x86 long double numbers -----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H
10 #define LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H
11 
12 #include "FPBits.h"
13 
14 #include <stdint.h>
15 
16 namespace __llvm_libc {
17 namespace fputil {
18 
19 template <> struct MantissaWidth<long double> {
20   static constexpr unsigned value = 63;
21 };
22 
23 template <unsigned Width> struct Padding;
24 
25 // i386 padding.
26 template <> struct Padding<4> { static constexpr unsigned value = 16; };
27 
28 // x86_64 padding.
29 template <> struct Padding<8> { static constexpr unsigned value = 48; };
30 
31 template <> struct __attribute__((packed)) FPBits<long double> {
32   using UIntType = __uint128_t;
33 
34   static constexpr int exponentBias = 0x3FFF;
35   static constexpr int maxExponent = 0x7FFF;
36   static constexpr UIntType minSubnormal = UIntType(1);
37   // Subnormal numbers include the implicit bit in x86 long double formats.
38   static constexpr UIntType maxSubnormal =
39       (UIntType(1) << (MantissaWidth<long double>::value + 1)) - 1;
40   static constexpr UIntType minNormal =
41       (UIntType(3) << MantissaWidth<long double>::value);
42   static constexpr UIntType maxNormal =
43       ((UIntType(maxExponent) - 1) << (MantissaWidth<long double>::value + 1)) |
44       (UIntType(1) << MantissaWidth<long double>::value) | maxSubnormal;
45 
46   UIntType mantissa : MantissaWidth<long double>::value;
47   uint8_t implicitBit : 1;
48   uint16_t exponent : ExponentWidth<long double>::value;
49   uint8_t sign : 1;
50   uint64_t padding : Padding<sizeof(uintptr_t)>::value;
51 
52   template <typename XType,
53             cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
54   explicit FPBits<long double>(XType x) {
55     *this = *reinterpret_cast<FPBits<long double> *>(&x);
56   }
57 
58   operator long double() { return *reinterpret_cast<long double *>(this); }
59 
60   int getExponent() const {
61     if (exponent == 0)
62       return int(1) - exponentBias;
63     return int(exponent) - exponentBias;
64   }
65 
66   bool isZero() const {
67     return exponent == 0 && mantissa == 0 && implicitBit == 0;
68   }
69 
70   bool isInf() const {
71     return exponent == maxExponent && mantissa == 0 && implicitBit == 1;
72   }
73 
74   bool isNaN() const {
75     if (exponent == maxExponent) {
76       return (implicitBit == 0) || mantissa != 0;
77     } else if (exponent != 0) {
78       return implicitBit == 0;
79     }
80     return false;
81   }
82 
83   bool isInfOrNaN() const {
84     return (exponent == maxExponent) || (exponent != 0 && implicitBit == 0);
85   }
86 
87   // Methods below this are used by tests.
88 
89   template <typename XType,
90             cpp::EnableIfType<cpp::IsSame<UIntType, XType>::Value, int> = 0>
91   explicit FPBits<long double>(XType x) {
92     // The last 4 bytes of v are ignored in case of i386.
93     *this = *reinterpret_cast<FPBits<long double> *>(&x);
94   }
95 
96   UIntType bitsAsUInt() const {
97     // We cannot just return the bits as is as it will lead to reading
98     // out of bounds in case of i386. So, we first copy the wider value
99     // before returning the value. This makes the last 4 bytes are always
100     // zero in case i386.
101     UIntType result = UIntType(0);
102     *reinterpret_cast<FPBits<long double> *>(&result) = *this;
103 
104     // Even though we zero out |result| before copying the long double value,
105     // there can be garbage bits in the padding. So, we zero the padding bits
106     // in |result|.
107     static constexpr UIntType mask =
108         (UIntType(1) << (sizeof(long double) * 8 -
109                          Padding<sizeof(uintptr_t)>::value)) -
110         1;
111     return result & mask;
112   }
113 
114   static FPBits<long double> zero() { return FPBits<long double>(0.0l); }
115 
116   static FPBits<long double> negZero() {
117     FPBits<long double> bits(0.0l);
118     bits.sign = 1;
119     return bits;
120   }
121 
122   static FPBits<long double> inf() {
123     FPBits<long double> bits(0.0l);
124     bits.exponent = maxExponent;
125     bits.implicitBit = 1;
126     return bits;
127   }
128 
129   static FPBits<long double> negInf() {
130     FPBits<long double> bits(0.0l);
131     bits.exponent = maxExponent;
132     bits.implicitBit = 1;
133     bits.sign = 1;
134     return bits;
135   }
136 
137   static long double buildNaN(UIntType v) {
138     FPBits<long double> bits(0.0l);
139     bits.exponent = maxExponent;
140     bits.implicitBit = 1;
141     bits.mantissa = v;
142     return bits;
143   }
144 };
145 
146 static_assert(
147     sizeof(FPBits<long double>) == sizeof(long double),
148     "Internal long double representation does not match the machine format.");
149 
150 } // namespace fputil
151 } // namespace __llvm_libc
152 
153 #endif // LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H
154