[libc-commits] [libc] [libc][NFC] Decouple FP properties from C++ types (PR #73517)
via libc-commits
libc-commits at lists.llvm.org
Mon Nov 27 06:00:25 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: Guillaume Chatelet (gchatelet)
<details>
<summary>Changes</summary>
We simplify the floating point properties by splitting concerns:
- We define all distinct floating point formats in the `FPType` enum.
- We map them to properties via the `FPProperties` trait.
- We map from C++ type to `FPType` in the `getFPType` function so logic is easier to understand and extend.
---
Full diff: https://github.com/llvm/llvm-project/pull/73517.diff
3 Files Affected:
- (modified) libc/src/__support/FPUtil/FloatProperties.h (+45-80)
- (modified) libc/src/__support/FPUtil/dyadic_float.h (+3-5)
- (modified) libc/src/__support/macros/properties/float.h (+56-18)
``````````diff
diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h
index 9d91688e023e923..b91e7ace5233f91 100644
--- a/libc/src/__support/FPUtil/FloatProperties.h
+++ b/libc/src/__support/FPUtil/FloatProperties.h
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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 getFPType() {
+ 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<getFPType<FP>()> {};
} // namespace fputil
} // namespace LIBC_NAMESPACE
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 2ee97b4ac7f7836..b7920943804e610 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -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;
diff --git a/libc/src/__support/macros/properties/float.h b/libc/src/__support/macros/properties/float.h
index c40ca6120e4753e..3bfd04156893699 100644
--- a/libc/src/__support/macros/properties/float.h
+++ b/libc/src/__support/macros/properties/float.h
@@ -15,32 +15,70 @@
#include "src/__support/macros/properties/compiler.h"
#include "src/__support/macros/properties/os.h"
-// https://developer.arm.com/documentation/dui0491/i/C-and-C---Implementation-Details/Basic-data-types
-// https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms
-// https://docs.amd.com/bundle/HIP-Programming-Guide-v5.1/page/Programming_with_HIP.html
-#if defined(LIBC_TARGET_OS_IS_WINDOWS) || \
- (defined(LIBC_TARGET_OS_IS_MACOS) && \
- defined(LIBC_TARGET_ARCH_IS_AARCH64)) || \
- defined(LIBC_TARGET_ARCH_IS_ARM) || defined(LIBC_TARGET_ARCH_IS_NVPTX) || \
- defined(LIBC_TARGET_ARCH_IS_AMDGPU)
+#include <float.h> // LDBL_MANT_DIG
+
+// 'long double' properties.
+#if (LDBL_MANT_DIG == DBL_MANT_DIG)
+// TODO: Replace with LIBC_LONG_DOUBLE_IS_DOUBLE
#define LONG_DOUBLE_IS_DOUBLE
#endif
-
-#if !defined(LONG_DOUBLE_IS_DOUBLE) && defined(LIBC_TARGET_ARCH_IS_X86)
+#if (LDBL_MANT_DIG == 64)
+// TODO: Replace with LIBC_LONG_DOUBLE_IS_X86_BIN80
#define SPECIAL_X86_LONG_DOUBLE
+#elif (LDBL_MANT_DIG == 113)
+#define LIBC_LONG_DOUBLE_IS_IEEE754_BIN128
#endif
-// Check compiler features
-#if defined(FLT128_MANT_DIG)
-#define LIBC_COMPILER_HAS_FLOAT128
+// float16 support.
+#if defined(LIBC_TARGET_ARCH_IS_X86_64)
+#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 1500)) || \
+ (defined(LIBC_COMPILER_GCC_VER) && (LIBC_COMPILER_GCC_VER >= 1201))
+#define LIBC_COMPILER_HAS_C23_FLOAT16
+#endif
+#endif
+#if defined(LIBC_TARGET_ARCH_IS_AARCH64)
+#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 0900)) || \
+ (defined(LIBC_COMPILER_GCC_VER) && (LIBC_COMPILER_GCC_VER >= 1301))
+#define LIBC_COMPILER_HAS_C23_FLOAT16
+#endif
+#endif
+#if defined(LIBC_TARGET_ARCH_IS_ANY_RISCV)
+#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 1300)) || \
+ (defined(LIBC_COMPILER_GCC_VER) && (LIBC_COMPILER_GCC_VER >= 1301))
+#define LIBC_COMPILER_HAS_C23_FLOAT16
+#endif
+#endif
+
+#if defined(LIBC_COMPILER_HAS_C23_FLOAT16)
+using float16 = _Float16;
+#define LIBC_HAS_FLOAT16
+#endif
+
+// float128 support.
+#if (defined(LIBC_COMPILER_GCC_VER) && (LIBC_COMPILER_GCC_VER >= 1301)) && \
+ (defined(LIBC_TARGET_ARCH_IS_AARCH64) || \
+ defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) || \
+ 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)) && \
+ (defined(LIBC_TARGET_ARCH_IS_X86_64))
+#define LIBC_COMPILER_HAS_FLOAT128_EXTENSION
+#endif
+
+#if defined(LIBC_COMPILER_HAS_C23_FLOAT128)
using float128 = _Float128;
-#elif defined(__SIZEOF_FLOAT128__)
-#define LIBC_COMPILER_HAS_FLOAT128
+#elif defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION)
using float128 = __float128;
-#elif (defined(__linux__) && defined(__aarch64__))
-#define LIBC_COMPILER_HAS_FLOAT128
-#define LIBC_FLOAT128_IS_LONG_DOUBLE
+#elif defined(LIBC_LONG_DOUBLE_IS_IEEE754_BIN128)
using float128 = long double;
#endif
+#if defined(LIBC_COMPILER_HAS_C23_FLOAT128) || \
+ defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION) || \
+ defined(LIBC_LONG_DOUBLE_IS_IEEE754_BIN128)
+// TODO: Replace with LIBC_HAS_FLOAT128
+#define LIBC_COMPILER_HAS_FLOAT128
+#endif
+
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_FLOAT_H
``````````
</details>
https://github.com/llvm/llvm-project/pull/73517
More information about the libc-commits
mailing list