-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[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
gchatelet
merged 4 commits into
llvm:main
from
gchatelet:decouple_properties_from_types
Nov 27, 2023
Merged
[libc][NFC] Decouple FP properties from C++ types #73517
gchatelet
merged 4 commits into
llvm:main
from
gchatelet:decouple_properties_from_types
Nov 27, 2023
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-libc Author: Guillaume Chatelet (gchatelet) ChangesWe simplify the floating point properties by splitting concerns:
Full diff: https://github.com/llvm/llvm-project/pull/73517.diff 3 Files Affected:
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
|
This is a follow up on #73372. Changes to |
lntue
reviewed
Nov 27, 2023
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.
027c6c3
to
4c2c55c
Compare
lntue
approved these changes
Nov 27, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
We simplify the floating point properties by splitting concerns:
FPType
enum.FPProperties
trait.FPType
in thegetFPType
function so logic is easier to understand and extend.