[libc-commits] [libc] [libc] Fix is_subnormal for Intel Extended Precision (PR #78592)

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Thu Jan 18 11:18:33 PST 2024


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

>From 0ce391137b360970401761aa9ea9ce9e1294cfbc Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 14:57:42 +0000
Subject: [PATCH 1/2] [libc] Fix is_subnormal for Intel Extended Precision

Also turn a set of `get_biased_exponent() == 0` into `is_subnormal()` which is clearer.
---
 libc/src/__support/FPUtil/FPBits.h                        | 3 +--
 libc/src/__support/FPUtil/NormalFloat.h                   | 4 ++--
 libc/src/__support/FPUtil/generic/FMA.h                   | 6 +++---
 libc/src/__support/FPUtil/generic/sqrt.h                  | 2 +-
 .../__support/FPUtil/generic/sqrt_80_bit_long_double.h    | 2 +-
 libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h    | 2 +-
 libc/utils/MPFRWrapper/MPFRUtils.cpp                      | 8 ++++----
 7 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 3ee6289b749648..e6c0f91c878f75 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -559,8 +559,7 @@ struct FPRep<FPType::X86_Binary80> : public FPRepBase<FPType::X86_Binary80> {
   }
   LIBC_INLINE
   constexpr bool is_subnormal() const {
-    return exp_sig_bits() >
-           encode(BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
+    return exp_bits() == encode(BiasedExponent::BITS_ALL_ZEROES());
   }
   LIBC_INLINE constexpr bool is_normal() const {
     const auto exp = exp_bits();
diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index 8b1612e1b47c61..e7abc53ce6129c 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -153,7 +153,7 @@ template <typename T> struct NormalFloat {
     }
 
     // Normalize subnormal numbers.
-    if (bits.get_biased_exponent() == 0) {
+    if (bits.is_subnormal()) {
       unsigned shift = evaluate_normalization_shift(bits.get_mantissa());
       mantissa = StorageType(bits.get_mantissa()) << shift;
       exponent = 1 - FPBits<T>::EXP_BIAS - shift;
@@ -186,7 +186,7 @@ NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {
     return;
   }
 
-  if (bits.get_biased_exponent() == 0) {
+  if (bits.is_subnormal()) {
     if (bits.get_implicit_bit() == 0) {
       // Since we ignore zero value, the mantissa in this case is non-zero.
       int normalization_shift =
diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index 9c67c645d5243d..6285cac1983d1e 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -104,15 +104,15 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
   int z_exp = 0;
 
   // Normalize denormal inputs.
-  if (LIBC_UNLIKELY(FPBits(x).get_biased_exponent() == 0)) {
+  if (LIBC_UNLIKELY(FPBits(x).is_subnormal())) {
     x_exp -= 52;
     x *= 0x1.0p+52;
   }
-  if (LIBC_UNLIKELY(FPBits(y).get_biased_exponent() == 0)) {
+  if (LIBC_UNLIKELY(FPBits(y).is_subnormal())) {
     y_exp -= 52;
     y *= 0x1.0p+52;
   }
-  if (LIBC_UNLIKELY(FPBits(z).get_biased_exponent() == 0)) {
+  if (LIBC_UNLIKELY(FPBits(z).is_subnormal())) {
     z_exp -= 52;
     z *= 0x1.0p+52;
   }
diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h
index f273b678edf527..21ae9d081d3f12 100644
--- a/libc/src/__support/FPUtil/generic/sqrt.h
+++ b/libc/src/__support/FPUtil/generic/sqrt.h
@@ -97,7 +97,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
       StorageType x_mant = bits.get_mantissa();
 
       // Step 1a: Normalize denormal input and append hidden bit to the mantissa
-      if (bits.get_biased_exponent() == 0) {
+      if (bits.is_subnormal()) {
         ++x_exp; // let x_exp be the correct exponent of ONE bit.
         internal::normalize<T>(x_exp, x_mant);
       } else {
diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
index 4fe9b49ff41cf0..4f8d136938f56e 100644
--- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
+++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -65,7 +65,7 @@ LIBC_INLINE long double sqrt(long double x) {
     // Step 1a: Normalize denormal input
     if (bits.get_implicit_bit()) {
       x_mant |= ONE;
-    } else if (bits.get_biased_exponent() == 0) {
+    } else if (bits.is_subnormal()) {
       normalize(x_exp, x_mant);
     }
 
diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
index 5f15bac5df77f8..6e3cc1d1834d79 100644
--- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
@@ -39,7 +39,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
 
   // Convert pseudo subnormal number to normal number.
   if (from_bits.get_implicit_bit() == 1 &&
-      from_bits.get_biased_exponent() == 0) {
+      from_bits.is_subnormal()) {
     from_bits.set_biased_exponent(1);
   }
 
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index fca83c4cdc52f1..b6ca525db6cf74 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -457,9 +457,9 @@ class MPFRNumber {
     int thisExponent = FPBits<T>(thisAsT).get_exponent();
     int inputExponent = FPBits<T>(input).get_exponent();
     // Adjust the exponents for denormal numbers.
-    if (FPBits<T>(thisAsT).get_biased_exponent() == 0)
+    if (FPBits<T>(thisAsT).is_subnormal())
       ++thisExponent;
-    if (FPBits<T>(input).get_biased_exponent() == 0)
+    if (FPBits<T>(input).is_subnormal())
       ++inputExponent;
 
     if (thisAsT * input < 0 || thisExponent == inputExponent) {
@@ -481,9 +481,9 @@ class MPFRNumber {
     int minExponent = FPBits<T>(min).get_exponent();
     int maxExponent = FPBits<T>(max).get_exponent();
     // Adjust the exponents for denormal numbers.
-    if (FPBits<T>(min).get_biased_exponent() == 0)
+    if (FPBits<T>(min).is_subnormal())
       ++minExponent;
-    if (FPBits<T>(max).get_biased_exponent() == 0)
+    if (FPBits<T>(max).is_subnormal())
       ++maxExponent;
 
     MPFRNumber minMPFR(min);

>From c0996f7f2ec53017feade1a40d910850d6f59544 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 19:18:16 +0000
Subject: [PATCH 2/2] Fix formatting, move `is_subnormal` and `is_zero` in
 `FPRepBase`

---
 libc/src/__support/FPUtil/FPBits.h            | 27 +++++--------------
 .../FPUtil/x86_64/NextAfterLongDouble.h       |  3 +--
 2 files changed, 8 insertions(+), 22 deletions(-)

diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index e6c0f91c878f75..be700285de8285 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -386,8 +386,11 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
     bits = (value & FP_MASK);
   }
 
-  LIBC_INLINE constexpr bool is_zero() const {
-    return (bits & EXP_SIG_MASK) == 0;
+  LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }
+
+  LIBC_INLINE
+  constexpr bool is_subnormal() const {
+    return exp_bits() == encode(BiasedExponent::BITS_ALL_ZEROES());
   }
 
   LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }
@@ -435,19 +438,11 @@ template <FPType fp_type> struct FPRep : public FPRepBase<fp_type> {
     return exp_sig_bits() ==
            encode(BiasedExponent::BITS_ALL_ONES(), Significand::ZERO());
   }
-  LIBC_INLINE constexpr bool is_zero() const {
-    return exp_sig_bits() ==
-           encode(BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
-  }
   LIBC_INLINE constexpr bool is_finite() const {
     return exp_bits() != encode(BiasedExponent::BITS_ALL_ONES());
   }
-  LIBC_INLINE
-  constexpr bool is_subnormal() const {
-    return exp_bits() == encode(BiasedExponent::BITS_ALL_ZEROES());
-  }
   LIBC_INLINE constexpr bool is_normal() const {
-    return is_finite() && !is_subnormal();
+    return is_finite() && !UP::is_subnormal();
   }
 
   LIBC_INLINE static constexpr StorageType zero(Sign sign = Sign::POS) {
@@ -488,7 +483,7 @@ template <FPType fp_type> struct FPRep : public FPRepBase<fp_type> {
   // The function return mantissa with the implicit bit set iff the current
   // value is a valid normal number.
   LIBC_INLINE constexpr StorageType get_explicit_mantissa() {
-    if (is_subnormal())
+    if (UP::is_subnormal())
       return sig_bits();
     return (StorageType(1) << UP::SIG_LEN) | sig_bits();
   }
@@ -550,17 +545,9 @@ struct FPRep<FPType::X86_Binary80> : public FPRepBase<FPType::X86_Binary80> {
     return exp_sig_bits() ==
            encode(BiasedExponent::BITS_ALL_ONES(), Significand::MSB());
   }
-  LIBC_INLINE constexpr bool is_zero() const {
-    return exp_sig_bits() ==
-           encode(BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
-  }
   LIBC_INLINE constexpr bool is_finite() const {
     return !is_inf() && !is_nan();
   }
-  LIBC_INLINE
-  constexpr bool is_subnormal() const {
-    return exp_bits() == encode(BiasedExponent::BITS_ALL_ZEROES());
-  }
   LIBC_INLINE constexpr bool is_normal() const {
     const auto exp = exp_bits();
     if (exp == encode(BiasedExponent::BITS_ALL_ZEROES()) ||
diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
index 6e3cc1d1834d79..512f5de4e7931a 100644
--- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
@@ -38,8 +38,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
     return to;
 
   // Convert pseudo subnormal number to normal number.
-  if (from_bits.get_implicit_bit() == 1 &&
-      from_bits.is_subnormal()) {
+  if (from_bits.get_implicit_bit() == 1 && from_bits.is_subnormal()) {
     from_bits.set_biased_exponent(1);
   }
 



More information about the libc-commits mailing list