blob: 7fd025a2f590759f2f0b572b5e255b05f36a8336 [file] [log] [blame]
//===-- Bit representation of x86 long double numbers -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H
#define LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H
#include "FPBits.h"
#include <stdint.h>
namespace __llvm_libc {
namespace fputil {
template <> struct MantissaWidth<long double> {
static constexpr unsigned value = 63;
};
template <unsigned Width> struct Padding;
// i386 padding.
template <> struct Padding<4> { static constexpr unsigned value = 16; };
// x86_64 padding.
template <> struct Padding<8> { static constexpr unsigned value = 48; };
template <> union FPBits<long double> {
using UIntType = __uint128_t;
static constexpr int exponentBias = 0x3FFF;
static constexpr int maxExponent = 0x7FFF;
static constexpr UIntType minSubnormal = UIntType(1);
// Subnormal numbers include the implicit bit in x86 long double formats.
static constexpr UIntType maxSubnormal =
(UIntType(1) << (MantissaWidth<long double>::value)) - 1;
static constexpr UIntType minNormal =
(UIntType(3) << MantissaWidth<long double>::value);
static constexpr UIntType maxNormal =
((UIntType(maxExponent) - 1) << (MantissaWidth<long double>::value + 1)) |
(UIntType(1) << MantissaWidth<long double>::value) | maxSubnormal;
struct __attribute__((packed)) {
UIntType mantissa : MantissaWidth<long double>::value;
uint8_t implicitBit : 1;
uint16_t exponent : ExponentWidth<long double>::value;
uint8_t sign : 1;
uint64_t padding : Padding<sizeof(uintptr_t)>::value;
} encoding;
UIntType integer;
long double val;
FPBits() : integer(0) {}
template <typename XType,
cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0>
explicit FPBits<long double>(XType x) : val(x) {}
template <typename XType,
cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
explicit FPBits(XType x) : integer(x) {}
operator long double() { return val; }
UIntType uintval() {
// We zero the padding bits as they can contain garbage.
static constexpr UIntType mask =
(UIntType(1) << (sizeof(long double) * 8 -
Padding<sizeof(uintptr_t)>::value)) -
1;
return integer & mask;
}
int getExponent() const {
if (encoding.exponent == 0)
return int(1) - exponentBias;
return int(encoding.exponent) - exponentBias;
}
bool isZero() const {
return encoding.exponent == 0 && encoding.mantissa == 0 &&
encoding.implicitBit == 0;
}
bool isInf() const {
return encoding.exponent == maxExponent && encoding.mantissa == 0 &&
encoding.implicitBit == 1;
}
bool isNaN() const {
if (encoding.exponent == maxExponent) {
return (encoding.implicitBit == 0) || encoding.mantissa != 0;
} else if (encoding.exponent != 0) {
return encoding.implicitBit == 0;
}
return false;
}
bool isInfOrNaN() const {
return (encoding.exponent == maxExponent) ||
(encoding.exponent != 0 && encoding.implicitBit == 0);
}
// Methods below this are used by tests.
static FPBits<long double> zero() { return FPBits<long double>(0.0l); }
static FPBits<long double> negZero() {
FPBits<long double> bits(0.0l);
bits.encoding.sign = 1;
return bits;
}
static FPBits<long double> inf() {
FPBits<long double> bits(0.0l);
bits.encoding.exponent = maxExponent;
bits.encoding.implicitBit = 1;
return bits;
}
static FPBits<long double> negInf() {
FPBits<long double> bits(0.0l);
bits.encoding.exponent = maxExponent;
bits.encoding.implicitBit = 1;
bits.encoding.sign = 1;
return bits;
}
static long double buildNaN(UIntType v) {
FPBits<long double> bits(0.0l);
bits.encoding.exponent = maxExponent;
bits.encoding.implicitBit = 1;
bits.encoding.mantissa = v;
return bits;
}
};
static_assert(
sizeof(FPBits<long double>) == sizeof(long double),
"Internal long double representation does not match the machine format.");
} // namespace fputil
} // namespace __llvm_libc
#endif // LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H