[libc-commits] [libc] [libc][NFC] Decouple FP properties from C++ types (PR #73517)

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Mon Nov 27 07:30:38 PST 2023


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/73517

>From a78272f01c60635ee037176055788e88667f112d Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 27 Nov 2023 15:13:12 +0000
Subject: [PATCH 1/4] [libc] Fix forward octal prefix

---
 libc/src/__support/macros/properties/float.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/macros/properties/float.h b/libc/src/__support/macros/properties/float.h
index 3bfd04156893699..b1d40ff7237f876 100644
--- a/libc/src/__support/macros/properties/float.h
+++ b/libc/src/__support/macros/properties/float.h
@@ -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
@@ -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

>From a09085a935a58028b54e6725d5e8f73dbc402c24 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 27 Nov 2023 15:18:27 +0000
Subject: [PATCH 2/4] fix format

---
 libc/src/__support/macros/properties/float.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/macros/properties/float.h b/libc/src/__support/macros/properties/float.h
index b1d40ff7237f876..7e00ddc8f0cd327 100644
--- a/libc/src/__support/macros/properties/float.h
+++ b/libc/src/__support/macros/properties/float.h
@@ -37,7 +37,7 @@
 #endif
 #endif
 #if defined(LIBC_TARGET_ARCH_IS_AARCH64)
-#if (defined(LIBC_COMPILER_CLANG_VER) && (LIBC_COMPILER_CLANG_VER >= 900)) || \
+#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
@@ -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 >= 500)) && \
+#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

>From a9066ded4b11f8bc5c440a8b593f30d414998540 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 27 Nov 2023 13:58:18 +0000
Subject: [PATCH 3/4] [libc][NFC] Decouple FP properties from C++ types

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.
---
 libc/src/__support/FPUtil/FloatProperties.h | 125 +++++++-------------
 libc/src/__support/FPUtil/dyadic_float.h    |   8 +-
 2 files changed, 48 insertions(+), 85 deletions(-)

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;

>From 4c2c55c1a31b528933b2bfbee61efb0aa0aa30bc Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Mon, 27 Nov 2023 15:30:17 +0000
Subject: [PATCH 4/4] Fix function case

---
 libc/src/__support/FPUtil/FloatProperties.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h
index b91e7ace5233f91..0e65a60ac654844 100644
--- a/libc/src/__support/FPUtil/FloatProperties.h
+++ b/libc/src/__support/FPUtil/FloatProperties.h
@@ -139,7 +139,7 @@ template <> struct FPProperties<FPType::IEEE754_Binary128> {
 };
 
 //-----------------------------------------------------------------------------
-template <typename FP> static constexpr FPType getFPType() {
+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)
@@ -169,7 +169,7 @@ template <typename FP> static constexpr FPType getFPType() {
 }
 
 template <typename FP>
-struct FloatProperties : public FPProperties<getFPType<FP>()> {};
+struct FloatProperties : public FPProperties<get_fp_type<FP>()> {};
 
 } // namespace fputil
 } // namespace LIBC_NAMESPACE



More information about the libc-commits mailing list