Skip to content

[libc] Remove unnecessary FPBits functions and properties #79113

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 2 commits into from
Jan 23, 2024

Conversation

gchatelet
Copy link
Contributor

This patch reduces the surface of FPBits.

This patch reduces the surface of `FPBits`.
@llvmbot
Copy link
Member

llvmbot commented Jan 23, 2024

@llvm/pr-subscribers-libc

Author: Guillaume Chatelet (gchatelet)

Changes

This patch reduces the surface of FPBits.


Patch is 99.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/79113.diff

68 Files Affected:

  • (modified) libc/fuzzing/stdlib/strtofloat_fuzz.cpp (+1-1)
  • (modified) libc/src/__support/FPUtil/DivisionAndRemainderOperations.h (+1-1)
  • (modified) libc/src/__support/FPUtil/FPBits.h (+9-42)
  • (modified) libc/src/__support/FPUtil/Hypot.h (+2-2)
  • (modified) libc/src/__support/FPUtil/ManipulationFunctions.h (+10-14)
  • (modified) libc/src/__support/FPUtil/NormalFloat.h (+1-1)
  • (modified) libc/src/__support/FPUtil/dyadic_float.h (+1-1)
  • (modified) libc/src/__support/FPUtil/except_value_utils.h (+2-4)
  • (modified) libc/src/__support/FPUtil/generic/FMA.h (+4-6)
  • (modified) libc/src/__support/FPUtil/generic/FMod.h (+1-1)
  • (modified) libc/src/__support/FPUtil/generic/sqrt.h (+11-7)
  • (modified) libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h (+5-3)
  • (modified) libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h (+27-31)
  • (modified) libc/src/__support/common.h (-1)
  • (modified) libc/src/__support/str_to_float.h (+2-2)
  • (modified) libc/src/math/generic/acosf.cpp (+1-1)
  • (modified) libc/src/math/generic/acoshf.cpp (+1-1)
  • (modified) libc/src/math/generic/asinf.cpp (+1-1)
  • (modified) libc/src/math/generic/atanhf.cpp (+2-2)
  • (modified) libc/src/math/generic/cosf.cpp (+1-1)
  • (modified) libc/src/math/generic/coshf.cpp (+3-3)
  • (modified) libc/src/math/generic/exp.cpp (+2-2)
  • (modified) libc/src/math/generic/exp10.cpp (+2-2)
  • (modified) libc/src/math/generic/exp10f_impl.h (+3-3)
  • (modified) libc/src/math/generic/exp2.cpp (+2-2)
  • (modified) libc/src/math/generic/exp2f_impl.h (+3-3)
  • (modified) libc/src/math/generic/expf.cpp (+2-2)
  • (modified) libc/src/math/generic/expm1.cpp (+2-2)
  • (modified) libc/src/math/generic/expm1f.cpp (+2-2)
  • (modified) libc/src/math/generic/log.cpp (+6-5)
  • (modified) libc/src/math/generic/log10.cpp (+6-5)
  • (modified) libc/src/math/generic/log10f.cpp (+5-3)
  • (modified) libc/src/math/generic/log1p.cpp (+4-3)
  • (modified) libc/src/math/generic/log1pf.cpp (+2-2)
  • (modified) libc/src/math/generic/log2.cpp (+6-5)
  • (modified) libc/src/math/generic/log2f.cpp (+5-3)
  • (modified) libc/src/math/generic/logf.cpp (+5-4)
  • (modified) libc/src/math/generic/powf.cpp (+7-6)
  • (modified) libc/src/math/generic/sincosf.cpp (+3-1)
  • (modified) libc/src/math/generic/sinf.cpp (+1-1)
  • (modified) libc/src/math/generic/sinhf.cpp (+3-3)
  • (modified) libc/src/math/generic/tanf.cpp (+1-1)
  • (modified) libc/test/UnitTest/FPMatcher.h (+20-20)
  • (modified) libc/test/src/__support/FPUtil/fpbits_test.cpp (+33-48)
  • (modified) libc/test/src/math/FDimTest.h (+1-1)
  • (modified) libc/test/src/math/FmaTest.h (+21-16)
  • (modified) libc/test/src/math/HypotTest.h (+23-20)
  • (modified) libc/test/src/math/ILogbTest.h (+11-11)
  • (modified) libc/test/src/math/LdExpTest.h (+1-1)
  • (modified) libc/test/src/math/NextAfterTest.h (+5-5)
  • (modified) libc/test/src/math/RIntTest.h (+12-9)
  • (modified) libc/test/src/math/RemQuoTest.h (+14-11)
  • (modified) libc/test/src/math/RoundToIntegerTest.h (+13-9)
  • (modified) libc/test/src/math/differential_testing/BinaryOpSingleOutputDiff.h (+10-6)
  • (modified) libc/test/src/math/differential_testing/SingleInputSingleOutputDiff.h (+4-3)
  • (modified) libc/test/src/math/smoke/FDimTest.h (+1-1)
  • (modified) libc/test/src/math/smoke/FmaTest.h (+9-7)
  • (modified) libc/test/src/math/smoke/HypotTest.h (+10-10)
  • (modified) libc/test/src/math/smoke/ILogbTest.h (+9-9)
  • (modified) libc/test/src/math/smoke/LdExpTest.h (+1-1)
  • (modified) libc/test/src/math/smoke/NextAfterTest.h (+8-6)
  • (modified) libc/test/src/math/smoke/NextTowardTest.h (+8-8)
  • (modified) libc/test/src/math/smoke/RIntTest.h (+1-1)
  • (modified) libc/test/src/math/smoke/RemQuoTest.h (+1-1)
  • (modified) libc/test/src/math/smoke/RoundToIntegerTest.h (+13-9)
  • (modified) libc/test/src/stdio/sprintf_test.cpp (+21-11)
  • (modified) libc/test/src/stdio/sscanf_test.cpp (+13-8)
  • (modified) libc/utils/MPFRWrapper/MPFRUtils.cpp (+1-1)
diff --git a/libc/fuzzing/stdlib/strtofloat_fuzz.cpp b/libc/fuzzing/stdlib/strtofloat_fuzz.cpp
index affef6fcf549e0..b773043bda67d8 100644
--- a/libc/fuzzing/stdlib/strtofloat_fuzz.cpp
+++ b/libc/fuzzing/stdlib/strtofloat_fuzz.cpp
@@ -28,7 +28,7 @@ using LIBC_NAMESPACE::fputil::FPBits;
 // exponent. Subnormals have a lower effective precision since they don't
 // necessarily use all of the bits of the mantissa.
 template <typename F> inline constexpr int effective_precision(int exponent) {
-  const int full_precision = FPBits<F>::MANTISSA_PRECISION;
+  const int full_precision = FPBits<F>::FRACTION_LEN + 1;
 
   // This is intended to be 0 when the exponent is the lowest normal and
   // increase as the exponent's magnitude increases.
diff --git a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
index 1798310c3e31e3..ef9593a42b0055 100644
--- a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
+++ b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
@@ -31,7 +31,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
   if (ybits.is_nan())
     return y;
   if (xbits.is_inf() || ybits.is_zero())
-    return FPBits<T>::build_quiet_nan(1);
+    return FPBits<T>::build_quiet_nan(fputil::Sign::POS, 1).get_val();
 
   if (xbits.is_zero()) {
     q = 0;
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 2465158bb2cdfc..0a79b505ecbe1c 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -390,7 +390,7 @@ struct FPRepSem : public FPStorage<fp_type> {
     return exp_bits() == encode(BiasedExp::BITS_ALL_ZEROES());
   }
   LIBC_INLINE constexpr bool is_normal() const {
-    return is_finite() && !UP::is_subnormal();
+    return is_finite() && !is_subnormal();
   }
   // Returns the mantissa with the implicit bit set iff the current
   // value is a valid normal number.
@@ -556,6 +556,14 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   using UP::FRACTION_MASK;
   using UP::SIGN_MASK;
 
+  // Comparison
+  LIBC_INLINE constexpr friend bool operator==(FPRep a, FPRep b) {
+    return a.uintval() == b.uintval();
+  }
+  LIBC_INLINE constexpr friend bool operator!=(FPRep a, FPRep b) {
+    return a.uintval() != b.uintval();
+  }
+
   // Representation
   LIBC_INLINE constexpr StorageType uintval() const { return bits & FP_MASK; }
   LIBC_INLINE constexpr void set_uintval(StorageType value) {
@@ -698,16 +706,6 @@ struct FPBits final : public internal::FPRep<get_fp_type<T>(), FPBits<T>> {
   using UP::bits;
 
   // Constants.
-  LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION =
-      UP::FRACTION_LEN + 1;
-  LIBC_INLINE_VAR static constexpr StorageType MIN_NORMAL =
-      UP::min_normal(Sign::POS).uintval();
-  LIBC_INLINE_VAR static constexpr StorageType MAX_NORMAL =
-      UP::max_normal(Sign::POS).uintval();
-  LIBC_INLINE_VAR static constexpr StorageType MIN_SUBNORMAL =
-      UP::min_subnormal(Sign::POS).uintval();
-  LIBC_INLINE_VAR static constexpr StorageType MAX_SUBNORMAL =
-      UP::max_subnormal(Sign::POS).uintval();
   LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
       (1 << UP::EXP_LEN) - 1;
 
@@ -731,37 +729,6 @@ struct FPBits final : public internal::FPRep<get_fp_type<T>(), FPBits<T>> {
 
   LIBC_INLINE constexpr explicit operator T() const { return get_val(); }
 
-  // Methods below this are used by tests.
-  // TODO: inline and remove.
-  LIBC_INLINE static constexpr T one(Sign sign = Sign::POS) {
-    return T(UP::one(sign));
-  }
-  LIBC_INLINE static constexpr T zero(Sign sign = Sign::POS) {
-    return T(UP::zero(sign));
-  }
-  LIBC_INLINE static constexpr T inf(Sign sign = Sign::POS) {
-    return T(UP::inf(sign));
-  }
-  LIBC_INLINE static constexpr T min_normal() {
-    return T(UP::min_normal(Sign::POS));
-  }
-  LIBC_INLINE static constexpr T max_normal() {
-    return T(UP::max_normal(Sign::POS));
-  }
-  LIBC_INLINE static constexpr T min_denormal() {
-    return T(UP::min_subnormal(Sign::POS));
-  }
-  LIBC_INLINE static constexpr T max_denormal() {
-    return T(UP::max_subnormal(Sign::POS));
-  }
-  LIBC_INLINE static constexpr T build_nan(StorageType v) {
-    return T(UP::build_nan(Sign::POS, v));
-  }
-  LIBC_INLINE static constexpr T build_quiet_nan(StorageType v,
-                                                 Sign sign = Sign::POS) {
-    return T(UP::build_quiet_nan(sign, v));
-  }
-
   // TODO: Use an uint32_t for 'biased_exp'.
   LIBC_INLINE static constexpr FPBits<T>
   create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
diff --git a/libc/src/__support/FPUtil/Hypot.h b/libc/src/__support/FPUtil/Hypot.h
index c38a40dfb08984..82237dec09e42e 100644
--- a/libc/src/__support/FPUtil/Hypot.h
+++ b/libc/src/__support/FPUtil/Hypot.h
@@ -197,7 +197,7 @@ LIBC_INLINE T hypot(T x, T y) {
         if (int round_mode = quick_get_round();
             round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
           return T(FPBits_t::inf());
-        return T(FPBits_t(FPBits_t::MAX_NORMAL));
+        return T(FPBits_t::max_normal());
       }
     } else {
       // For denormal result, we simply move the leading bit of the result to
@@ -254,7 +254,7 @@ LIBC_INLINE T hypot(T x, T y) {
     if (out_exp >= FPBits_t::MAX_BIASED_EXPONENT) {
       if (round_mode == FE_TONEAREST || round_mode == FE_UPWARD)
         return T(FPBits_t::inf());
-      return T(FPBits_t(FPBits_t::MAX_NORMAL));
+      return T(FPBits_t::max_normal());
     }
   }
 
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 81c8281f3c7bbe..d7114625a9b314 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -108,7 +108,7 @@ LIBC_INLINE T logb(T x) {
     return x;
   } else if (bits.is_inf()) {
     // Return positive infinity.
-    return T(FPBits<T>::inf(Sign::POS));
+    return T(FPBits<T>::inf());
   }
 
   NormalFloat<T> normal(bits);
@@ -127,7 +127,7 @@ LIBC_INLINE T ldexp(T x, int exp) {
   // that adding |exp| to it does not lead to integer rollover. But, if |exp|
   // value is larger the exponent range for type T, then we can return infinity
   // early. Because the result of the ldexp operation can be a subnormal number,
-  // we need to accommodate the (mantissaWidht + 1) worth of shift in
+  // we need to accommodate the (mantissaWidth + 1) worth of shift in
   // calculating the limit.
   int exp_limit = FPBits<T>::MAX_BIASED_EXPONENT + FPBits<T>::FRACTION_LEN + 1;
   if (exp > exp_limit)
@@ -164,26 +164,22 @@ LIBC_INLINE T nextafter(T from, U to) {
     return static_cast<T>(to);
 
   using StorageType = typename FPBits<T>::StorageType;
-  StorageType int_val = from_bits.uintval();
-  if (from != FPBits<T>::zero()) {
-    if ((static_cast<U>(from) < to) == (from > FPBits<T>::zero())) {
-      ++int_val;
+  if (from != T(0)) {
+    if ((static_cast<U>(from) < to) == (from > T(0))) {
+      from_bits = FPBits<T>(StorageType(from_bits.uintval() + 1));
     } else {
-      --int_val;
+      from_bits = FPBits<T>(StorageType(from_bits.uintval() - 1));
     }
   } else {
-    int_val = FPBits<T>::MIN_SUBNORMAL;
-    if (to_bits.is_neg())
-      int_val |= FPBits<T>::SIGN_MASK;
+    from_bits = FPBits<T>::min_subnormal(to_bits.sign());
   }
 
-  StorageType exponent_bits = int_val & FPBits<T>::EXP_MASK;
-  if (exponent_bits == StorageType(0))
+  if (from_bits.is_subnormal())
     raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
-  else if (exponent_bits == FPBits<T>::EXP_MASK)
+  else if (from_bits.is_inf())
     raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
 
-  return cpp::bit_cast<T>(int_val);
+  return from_bits.get_val();
 }
 
 } // namespace fputil
diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index cfa9e141751055..fa4da33b5b17fa 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -215,7 +215,7 @@ template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
   // Max exponent is of the form 0xFF...E. That is why -2 and not -1.
   constexpr int MAX_EXPONENT_VALUE = (1 << LDBits::EXP_LEN) - 2;
   if (biased_exponent > MAX_EXPONENT_VALUE) {
-    return LDBits::inf(sign);
+    return LDBits::inf(sign).get_val();
   }
 
   FPBits<long double> result(0.0l);
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 5449f5561d5696..888d7ffec241ea 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -93,7 +93,7 @@ template <size_t Bits> struct DyadicFloat {
       return 0.0;
 
     // Assume that it is normalized, and output is also normal.
-    constexpr uint32_t PRECISION = FPBits<T>::MANTISSA_PRECISION;
+    constexpr uint32_t PRECISION = FPBits<T>::FRACTION_LEN + 1;
     using output_bits_t = typename FPBits<T>::StorageType;
 
     int exp_hi = exponent + static_cast<int>((Bits - 1) + FPBits<T>::EXP_BIAS);
diff --git a/libc/src/__support/FPUtil/except_value_utils.h b/libc/src/__support/FPUtil/except_value_utils.h
index 89849540315f64..1e0381194009d5 100644
--- a/libc/src/__support/FPUtil/except_value_utils.h
+++ b/libc/src/__support/FPUtil/except_value_utils.h
@@ -102,15 +102,13 @@ template <typename T, size_t N> struct ExceptValues {
 // Helper functions to set results for exceptional cases.
 template <typename T> LIBC_INLINE T round_result_slightly_down(T value_rn) {
   volatile T tmp = value_rn;
-  const T MIN_NORMAL = FPBits<T>::min_normal();
-  tmp = tmp - MIN_NORMAL;
+  tmp -= FPBits<T>::min_normal().get_val();
   return tmp;
 }
 
 template <typename T> LIBC_INLINE T round_result_slightly_up(T value_rn) {
   volatile T tmp = value_rn;
-  const T MIN_NORMAL = FPBits<T>::min_normal();
-  tmp = tmp + MIN_NORMAL;
+  tmp += FPBits<T>::min_normal().get_val();
   return tmp;
 }
 
diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index 6285cac1983d1e..5c36463ea50213 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -130,9 +130,9 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
     return x * y + z;
 
   // Extract mantissa and append hidden leading bits.
-  UInt128 x_mant = x_bits.get_mantissa() | FPBits::MIN_NORMAL;
-  UInt128 y_mant = y_bits.get_mantissa() | FPBits::MIN_NORMAL;
-  UInt128 z_mant = z_bits.get_mantissa() | FPBits::MIN_NORMAL;
+  UInt128 x_mant = x_bits.get_explicit_mantissa();
+  UInt128 y_mant = y_bits.get_explicit_mantissa();
+  UInt128 z_mant = z_bits.get_explicit_mantissa();
 
   // If the exponent of the product x*y > the exponent of z, then no extra
   // precision beside the entire product x*y is needed.  On the other hand, when
@@ -255,9 +255,7 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
     if ((round_mode == FE_TOWARDZERO) ||
         (round_mode == FE_UPWARD && prod_sign.is_neg()) ||
         (round_mode == FE_DOWNWARD && prod_sign.is_pos())) {
-      result = FPBits::MAX_NORMAL;
-      return prod_sign.is_neg() ? -cpp::bit_cast<double>(result)
-                                : cpp::bit_cast<double>(result);
+      return FPBits::max_normal(prod_sign).get_val();
     }
     return static_cast<double>(FPBits::inf(prod_sign));
   }
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index f4000b97751efc..18355b801dbc7c 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -124,7 +124,7 @@ template <typename T> struct FModExceptionalInputHandler {
 
   LIBC_INLINE static bool pre_check(T x, T y, T &out) {
     using FPB = fputil::FPBits<T>;
-    const T quiet_nan = FPB::build_quiet_nan(0);
+    const T quiet_nan = FPB::build_quiet_nan().get_val();
     FPB sx(x), sy(y);
     if (LIBC_LIKELY(!sy.is_zero() && !sy.is_inf_or_nan() &&
                     !sx.is_inf_or_nan())) {
diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h
index 21ae9d081d3f12..0a0690ec1463b9 100644
--- a/libc/src/__support/FPUtil/generic/sqrt.h
+++ b/libc/src/__support/FPUtil/generic/sqrt.h
@@ -71,15 +71,19 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
     return x86::sqrt(x);
   } else {
     // IEEE floating points formats.
-    using StorageType = typename FPBits<T>::StorageType;
-    constexpr StorageType ONE = StorageType(1) << FPBits<T>::FRACTION_LEN;
+    using Sign = fputil::Sign;
+    using FPBits_t = typename fputil::FPBits<T>;
+    using StorageType = typename FPBits_t::StorageType;
+    constexpr StorageType ONE = StorageType(1) << FPBits_t::FRACTION_LEN;
+    constexpr auto FLT_NAN =
+        FPBits_t::build_quiet_nan(Sign::POS, ONE >> 1).get_val();
 
-    FPBits<T> bits(x);
+    FPBits_t bits(x);
 
     if (bits.is_inf_or_nan()) {
       if (bits.is_neg() && (bits.get_mantissa() == 0)) {
         // sqrt(-Inf) = NaN
-        return FPBits<T>::build_quiet_nan(ONE >> 1);
+        return FLT_NAN;
       } else {
         // sqrt(NaN) = NaN
         // sqrt(+Inf) = +Inf
@@ -91,7 +95,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
       return x;
     } else if (bits.is_neg()) {
       // sqrt( negative numbers ) = NaN
-      return FPBits<T>::build_quiet_nan(ONE >> 1);
+      return FLT_NAN;
     } else {
       int x_exp = bits.get_exponent();
       StorageType x_mant = bits.get_mantissa();
@@ -145,10 +149,10 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
       }
 
       // Remove hidden bit and append the exponent field.
-      x_exp = ((x_exp >> 1) + FPBits<T>::EXP_BIAS);
+      x_exp = ((x_exp >> 1) + FPBits_t::EXP_BIAS);
 
       y = (y - ONE) |
-          (static_cast<StorageType>(x_exp) << FPBits<T>::FRACTION_LEN);
+          (static_cast<StorageType>(x_exp) << FPBits_t::FRACTION_LEN);
 
       switch (quick_get_round()) {
       case FE_TONEAREST:
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 4f8d136938f56e..b0a3776029ca78 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
@@ -38,14 +38,16 @@ LIBC_INLINE long double sqrt(long double x);
 LIBC_INLINE long double sqrt(long double x) {
   using LDBits = FPBits<long double>;
   using StorageType = typename LDBits::StorageType;
+  using Sign = fputil::Sign;
   constexpr StorageType ONE = StorageType(1) << int(LDBits::FRACTION_LEN);
+  constexpr auto LDNAN = LDBits::build_quiet_nan(Sign::POS, ONE >> 1).get_val();
 
-  FPBits<long double> bits(x);
+  LDBits bits(x);
 
   if (bits.is_inf_or_nan()) {
     if (bits.is_neg() && (bits.get_mantissa() == 0)) {
       // sqrt(-Inf) = NaN
-      return LDBits::build_quiet_nan(ONE >> 1);
+      return LDNAN;
     } else {
       // sqrt(NaN) = NaN
       // sqrt(+Inf) = +Inf
@@ -57,7 +59,7 @@ LIBC_INLINE long double sqrt(long double x) {
     return x;
   } else if (bits.is_neg()) {
     // sqrt( negative numbers ) = NaN
-    return LDBits::build_quiet_nan(ONE >> 1);
+    return LDNAN;
   } else {
     int x_exp = bits.get_explicit_exponent();
     StorageType x_mant = bits.get_mantissa();
diff --git a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
index 512f5de4e7931a..d1c76ba954b930 100644
--- a/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
+++ b/libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
@@ -43,16 +43,18 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
   }
 
   using StorageType = FPBits::StorageType;
-  constexpr StorageType SIGN_VAL = (StorageType(1) << 79);
+
   constexpr StorageType FRACTION_MASK = FPBits::FRACTION_MASK;
-  StorageType int_val = from_bits.uintval();
-  if (from < 0.0l) {
-    if (from > to) {
-      if (int_val == (SIGN_VAL + FPBits::MAX_SUBNORMAL)) {
+  // StorageType int_val = from_bits.uintval();
+  if (from == 0.0l) { // +0.0 / -0.0
+    from_bits = FPBits::min_subnormal(from > to ? Sign::NEG : Sign::POS);
+  } else if (from < 0.0l) {
+    if (to < from) { // toward -inf
+      if (from_bits == FPBits::max_subnormal(Sign::NEG)) {
         // We deal with normal/subnormal boundary separately to avoid
         // dealing with the implicit bit.
-        int_val = SIGN_VAL + FPBits::MIN_NORMAL;
-      } else if ((int_val & FRACTION_MASK) == FRACTION_MASK) {
+        from_bits = FPBits::min_normal(Sign::NEG);
+      } else if (from_bits.get_mantissa() == FRACTION_MASK) {
         from_bits.set_mantissa(0);
         // Incrementing exponent might overflow the value to infinity,
         // which is what is expected. Since NaNs are handling separately,
@@ -62,45 +64,40 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
           raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
         return from_bits.get_val();
       } else {
-        ++int_val;
+        from_bits = FPBits(StorageType(from_bits.uintval() + 1));
       }
-    } else {
-      if (int_val == (SIGN_VAL + FPBits::MIN_NORMAL)) {
+    } else { // toward +inf
+      if (from_bits == FPBits::min_normal(Sign::NEG)) {
         // We deal with normal/subnormal boundary separately to avoid
         // dealing with the implicit bit.
-        int_val = SIGN_VAL + FPBits::MAX_SUBNORMAL;
-      } else if ((int_val & FRACTION_MASK) == 0) {
+        from_bits = FPBits::max_subnormal(Sign::NEG);
+      } else if (from_bits.get_mantissa() == 0) {
         from_bits.set_mantissa(FRACTION_MASK);
         // from == 0 is handled separately so decrementing the exponent will not
         // lead to underflow.
         from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
         return from_bits.get_val();
       } else {
-        --int_val;
+        from_bits = FPBits(StorageType(from_bits.uintval() - 1));
       }
     }
-  } else if (from == 0.0l) {
-    if (from > to)
-      int_val = SIGN_VAL + 1;
-    else
-      int_val = 1;
   } else {
-    if (from > to) {
-      if (int_val == FPBits::MIN_NORMAL) {
-        int_val = FPBits::MAX_SUBNORMAL;
-      } else if ((int_val & FRACTION_MASK) == 0) {
+    if (to < from) { // toward -inf
+      if (from_bits == FPBits::min_normal(Sign::POS)) {
+        from_bits = FPBits::max_subnormal(Sign::POS);
+      } else if (from_bits.get_mantissa() == 0) {
         from_bits.set_mantissa(FRACTION_MASK);
         // from == 0 is handled separately so decrementing the exponent will not
         // lead to underflow.
         from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
         return from_bits.get_val();
       } else {
-        --int_val;
+        from_bits = FPBits(StorageType(from_bits.uintval() - 1));
       }
-    } else {
-      if (int_val == FPBits::MAX_SUBNORMAL) {
-        int_val = FPBits::MIN_NORMAL;
-      } else if ((int_val & FRACTION_MASK) == FRACTION_MASK) {
+    } else { // toward +inf
+      if (from_bits == FPBits::max_subnormal(Sign::POS)) {
+        from_bits = FPBits::min_normal(Sign::POS);
+      } else if (from_bits.get_mantissa() == FRACTION_MASK) {
         from_bits.set_mantissa(0);
         // Incrementing exponent might overflow the value to infinity,
         // which is what is expected. Since NaNs are handling separately,
@@ -110,16 +107,15 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
           raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
         return from_bits.get_val();
       } else {
-        ++int_val;
+        from_bits = FPBits(StorageType(from_bits.uintval() + 1));
       }
     }
   }
 
-  StorageType implicit_bit = int_val & (StorageType(1) << FPBits::FRACTION_LEN);
-  if (implicit_bit == StorageType(0))
+  if (!from_bits.get_implicit_bit())
     raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
 
-  return cpp::bit_cast<long double>(int_val);
+  return from_bits.get_val();
 }
 
 } // namespace fputil
diff --git a/libc/src/__support/common.h b/libc/src/__support/common.h
index 53951dc131c28b..a153dfc363d737 100644
--- a/libc/src/__support/common.h
+++ b/libc/src/__support/common.h
@@ -25,7 +25,6 @@
 #define LLVM_L...
[truncated]

Copy link

github-actions bot commented Jan 23, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@@ -596,7 +581,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"0xBFFF2000000000000000000000000000 = "
"(S: 1, E: 0x3FFF, M: 0x00002000000000000000000000000000)");

Float128Bits quiet_nan = Float128Bits(Float128Bits::build_quiet_nan(1));
Float128Bits quiet_nan = Float128Bits::build_quiet_nan(Sign::POS, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nans are created with 1, some with 1<<shift. Let's maybe harmonize those (in a separate patch)

@gchatelet gchatelet merged commit 3bc86bf into llvm:main Jan 23, 2024
@gchatelet gchatelet deleted the remove_some_fpbit_properties branch January 23, 2024 10:48
gchatelet added a commit that referenced this pull request Jan 23, 2024
gchatelet added a commit that referenced this pull request Jan 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants