Skip to content

[libc][NFC] Decouple FP properties from C++ types #73517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 45 additions & 80 deletions libc/src/__support/FPUtil/FloatProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@
namespace LIBC_NAMESPACE {
namespace fputil {

template <typename T> struct FloatProperties {};
// The supported floating point types.
enum class FPType {
IEEE754_Binary16,
IEEE754_Binary32,
IEEE754_Binary64,
IEEE754_Binary128,
X86_Binary80,
};

template <> struct FloatProperties<float> {
template <FPType> struct FPProperties {};
template <> struct FPProperties<FPType::IEEE754_Binary32> {
typedef uint32_t BitsType;
static_assert(sizeof(BitsType) == sizeof(float),
"Unexpected size of 'float' type.");

static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;

Expand All @@ -46,10 +52,8 @@ template <> struct FloatProperties<float> {
static constexpr BitsType QUIET_NAN_MASK = 0x00400000U;
};

template <> struct FloatProperties<double> {
template <> struct FPProperties<FPType::IEEE754_Binary64> {
typedef uint64_t BitsType;
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");

static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;

Expand All @@ -72,47 +76,10 @@ template <> struct FloatProperties<double> {
static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL;
};

#if defined(LONG_DOUBLE_IS_DOUBLE)
// Properties for numbers represented in 64 bits long double on Windows
// platform.
template <> struct FloatProperties<long double> {
typedef uint64_t BitsType;
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");

static constexpr uint32_t BIT_WIDTH = FloatProperties<double>::BIT_WIDTH;

static constexpr uint32_t MANTISSA_WIDTH =
FloatProperties<double>::MANTISSA_WIDTH;
static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
static constexpr uint32_t EXPONENT_WIDTH =
FloatProperties<double>::EXPONENT_WIDTH;
static constexpr BitsType MANTISSA_MASK =
FloatProperties<double>::MANTISSA_MASK;
static constexpr BitsType SIGN_MASK = FloatProperties<double>::SIGN_MASK;
static constexpr BitsType EXPONENT_MASK =
FloatProperties<double>::EXPONENT_MASK;
static constexpr uint32_t EXPONENT_BIAS =
FloatProperties<double>::EXPONENT_BIAS;

static constexpr BitsType EXP_MANT_MASK =
FloatProperties<double>::EXP_MANT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");

// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK =
FloatProperties<double>::QUIET_NAN_MASK;
};
#elif defined(SPECIAL_X86_LONG_DOUBLE)
// Properties for numbers represented in 80 bits long double on non-Windows x86
// platforms.
template <> struct FloatProperties<long double> {
template <> struct FPProperties<FPType::X86_Binary80> {
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");

static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48;
static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1);
Expand Down Expand Up @@ -143,13 +110,11 @@ template <> struct FloatProperties<long double> {
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
<< (MANTISSA_WIDTH - 1);
};
#else

// Properties for numbers represented in 128 bits long double on non x86
// platform.
template <> struct FloatProperties<long double> {
template <> struct FPProperties<FPType::IEEE754_Binary128> {
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");

static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;

Expand All @@ -172,39 +137,39 @@ template <> struct FloatProperties<long double> {
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
<< (MANTISSA_WIDTH - 1);
};
#endif

#if (defined(LIBC_COMPILER_HAS_FLOAT128) && \
!defined(LIBC_FLOAT128_IS_LONG_DOUBLE))
// Properties for numbers represented in 128 bits long double on non x86
// platform.
template <> struct FloatProperties<float128> {
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(float128),
"Unexpected size of 'float128' type.");

static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;

static constexpr uint32_t MANTISSA_WIDTH = 112;
static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
static constexpr uint32_t EXPONENT_WIDTH = 15;
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
static constexpr BitsType SIGN_MASK = BitsType(1)
<< (EXPONENT_WIDTH + MANTISSA_WIDTH);
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 16383;

static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
//-----------------------------------------------------------------------------
template <typename FP> static constexpr FPType get_fp_type() {
if constexpr (cpp::is_same_v<FP, float> && __FLT_MANT_DIG__ == 24)
return FPType::IEEE754_Binary32;
else if constexpr (cpp::is_same_v<FP, double> && __DBL_MANT_DIG__ == 53)
return FPType::IEEE754_Binary64;
else if constexpr (cpp::is_same_v<FP, long double>) {
if constexpr (__LDBL_MANT_DIG__ == 53)
return FPType::IEEE754_Binary64;
else if constexpr (__LDBL_MANT_DIG__ == 64)
return FPType::X86_Binary80;
else if constexpr (__LDBL_MANT_DIG__ == 113)
return FPType::IEEE754_Binary128;
}
#if defined(LIBC_COMPILER_HAS_C23_FLOAT16)
else if constexpr (cpp::is_same_v<FP, _Float16>)
return FPType::IEEE754_Binary16;
#endif
#if defined(LIBC_COMPILER_HAS_C23_FLOAT128)
else if constexpr (cpp::is_same_v<FP, _Float128>)
return FPType::IEEE754_Binary128;
#endif
#if defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION)
else if constexpr (cpp::is_same_v<FP, __float128>)
return FPType::IEEE754_Binary128;
#endif
else
static_assert(cpp::always_false<FP>, "Unsupported type");
}

// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
<< (MANTISSA_WIDTH - 1);
};
#endif // LIBC_COMPILER_HAS_FLOAT128
template <typename FP>
struct FloatProperties : public FPProperties<get_fp_type<FP>()> {};

} // namespace fputil
} // namespace LIBC_NAMESPACE
Expand Down
8 changes: 3 additions & 5 deletions libc/src/__support/FPUtil/dyadic_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,11 @@ template <size_t Bits> struct DyadicFloat {
int exponent = 0;
MantissaType mantissa = MantissaType(0);

DyadicFloat() = default;
constexpr DyadicFloat() = default;

template <typename T,
cpp::enable_if_t<cpp::is_floating_point_v<T> &&
(FloatProperties<T>::MANTISSA_WIDTH < Bits),
int> = 0>
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
DyadicFloat(T x) {
static_assert(FloatProperties<T>::MANTISSA_WIDTH < Bits);
FPBits<T> x_bits(x);
sign = x_bits.get_sign();
exponent = x_bits.get_exponent() - FloatProperties<T>::MANTISSA_WIDTH;
Expand Down
4 changes: 2 additions & 2 deletions libc/src/__support/macros/properties/float.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#endif
#endif
#if defined(LIBC_TARGET_ARCH_IS_AARCH64)
#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 0900)) || \
#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 900)) || \
(defined(LIBC_COMPILER_GCC_VER) && (LIBC_COMPILER_GCC_VER >= 1301))
#define LIBC_COMPILER_HAS_C23_FLOAT16
#endif
Expand All @@ -61,7 +61,7 @@ using float16 = _Float16;
defined(LIBC_TARGET_ARCH_IS_X86_64))
#define LIBC_COMPILER_HAS_C23_FLOAT128
#endif
#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 0500)) && \
#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 500)) && \
(defined(LIBC_TARGET_ARCH_IS_X86_64))
#define LIBC_COMPILER_HAS_FLOAT128_EXTENSION
#endif
Expand Down