Skip to content
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

[libc][NFC] Make FPRep more testable #80453

Merged
merged 4 commits into from
Feb 5, 2024
Merged

Conversation

gchatelet
Copy link
Contributor

No description provided.

@gchatelet gchatelet marked this pull request as ready for review February 2, 2024 16:40
@llvmbot llvmbot added the libc label Feb 2, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Feb 2, 2024

@llvm/pr-subscribers-libc

Author: Guillaume Chatelet (gchatelet)

Changes

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

2 Files Affected:

  • (modified) libc/src/__support/FPUtil/FPBits.h (+159-124)
  • (modified) libc/test/src/__support/FPUtil/fpbits_test.cpp (+34-34)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index d975638be348d..ef94bd3bb8f1f 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -75,27 +75,32 @@ LIBC_INLINE_VAR constexpr Sign Sign::POS = Sign(false);
 //          │                          │
 //          └────────────┬─────────────┘
 //                       │
-//                 ┌─────┴─────┐
-//                 │  FPRep<T> │
-//                 └───────────┘
+//               ┌───────┴───────┐
+//               │  FPRepImpl<T> │
+//               └───────▲───────┘
 //                       │
-//                 ┌─────┴─────┐
-//                 │ FPBits<T> │
-//                 └───────────┘
+//              ┌────────┴────────┐
+//        ┌─────┴─────┐     ┌─────┴─────┐
+//        │  FPRep<T> │     │ FPBits<T> │
+//        └───────────┘     └───────────┘
 //
 // - 'FPLayout' defines only a few constants, namely the 'StorageType' and
-// length of the sign, the exponent, fraction and significand parts.
+//   length of the sign, the exponent, fraction and significand parts.
 // - 'FPStorage' builds more constants on top of those from 'FPLayout' like
-// exponent bias and masks. It also holds the bit representation of the
-// floating point as a 'StorageType' type and defines tools to assemble or test
-// these parts.
+//   exponent bias and masks. It also holds the bit representation of the
+//   floating point as a 'StorageType' type and defines tools to assemble or
+//   test these parts.
 // - 'FPRepSem' defines functions to interact semantically with the floating
-// point representation. The default implementation is the one for 'IEEE754', a
-// specialization is provided for X86 Extended Precision.
-// - 'FPRep' derives from 'FPRepSem' and adds functions that are common to all
-// implementations.
-// - 'FPBits' exposes all functions from 'FPRep' but operates on the native C++
-// floating point type instead of 'FPType'.
+//   point representation. The default implementation is the one for 'IEEE754',
+//   a specialization is provided for X86 Extended Precision.
+// - 'FPRepImpl' derives from 'FPRepSem' and adds functions that are common to
+//   all implementations or build on the ones in 'FPRepSem'.
+// - 'FPRep' exposes all functions from 'FPRepImpl' and returns 'FPRep'
+//   instances when using Builders (static functions to create values).
+// - 'FPBits' exposes all the functions from 'FPRepImpl' but operates on the
+//   native C++ floating point type instead of 'FPType'. An additional 'get_val'
+//   function allows getting the C++ floating point type value back. Builders
+//   called from 'FPBits' return 'FPBits' instances.
 
 namespace internal {
 
@@ -197,12 +202,22 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
   static_assert((SIG_MASK | EXP_MASK | SIGN_MASK) == FP_MASK, "masks cover");
 
 protected:
+  // Merge bits from 'a' and 'b' values according to 'mask'.
+  // Use 'a' bits when corresponding 'mask' bits are zeroes and 'b' bits when
+  // corresponding bits are ones.
+  LIBC_INLINE static constexpr StorageType merge(StorageType a, StorageType b,
+                                                 StorageType mask) {
+    // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
+    return a ^ ((a ^ b) & mask);
+  }
+
   // A stongly typed integer that prevents mixing and matching integers with
   // different semantics.
   template <typename T> struct TypedInt {
     using value_type = T;
     LIBC_INLINE constexpr explicit TypedInt(T value) : value(value) {}
     LIBC_INLINE constexpr TypedInt(const TypedInt &value) = default;
+    LIBC_INLINE constexpr TypedInt &operator=(const TypedInt &value) = default;
 
     LIBC_INLINE constexpr explicit operator T() const { return value; }
 
@@ -210,7 +225,14 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
       return StorageType(value);
     }
 
-  private:
+    LIBC_INLINE friend constexpr bool operator==(TypedInt a, TypedInt b) {
+      return a.value == b.value;
+    }
+    LIBC_INLINE friend constexpr bool operator!=(TypedInt a, TypedInt b) {
+      return a.value != b.value;
+    }
+
+  protected:
     T value;
   };
 
@@ -220,10 +242,11 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
   struct Exponent : public TypedInt<int32_t> {
     using UP = TypedInt<int32_t>;
     using UP::UP;
-    LIBC_INLINE
-    static constexpr auto MIN() { return Exponent(1 - EXP_BIAS); }
+    LIBC_INLINE static constexpr auto SUB() { return Exponent(-EXP_BIAS); }
+    LIBC_INLINE static constexpr auto MIN() { return Exponent(1 - EXP_BIAS); }
     LIBC_INLINE static constexpr auto ZERO() { return Exponent(0); }
     LIBC_INLINE static constexpr auto MAX() { return Exponent(EXP_BIAS); }
+    LIBC_INLINE static constexpr auto INF() { return Exponent(EXP_BIAS + 1); }
   };
 
   // An opaque type to store a floating point biased exponent.
@@ -236,13 +259,10 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
 
     LIBC_INLINE constexpr BiasedExponent(Exponent exp)
         : UP(static_cast<int32_t>(exp) + EXP_BIAS) {}
-    // The exponent value for denormal numbers.
-    LIBC_INLINE static constexpr auto BITS_ALL_ZEROES() {
-      return BiasedExponent(uint32_t(0));
-    }
-    // The exponent value for infinity.
-    LIBC_INLINE static constexpr auto BITS_ALL_ONES() {
-      return BiasedExponent(uint32_t(2 * EXP_BIAS + 1));
+
+    // Cast operator to get convert from BiasedExponent to Exponent.
+    LIBC_INLINE constexpr operator Exponent() const {
+      return Exponent(UP::value - EXP_BIAS);
     }
   };
 
@@ -316,6 +336,23 @@ template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> {
   LIBC_INLINE constexpr StorageType exp_sig_bits() const {
     return bits & EXP_SIG_MASK;
   }
+
+  // Parts
+  LIBC_INLINE constexpr BiasedExponent biased_exponent() const {
+    return BiasedExponent(static_cast<uint32_t>(exp_bits() >> SIG_LEN));
+  }
+  LIBC_INLINE constexpr void set_biased_exponent(BiasedExponent biased) {
+    bits = merge(bits, encode(biased), EXP_MASK);
+  }
+
+public:
+  LIBC_INLINE constexpr Sign sign() const {
+    return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS;
+  }
+  LIBC_INLINE constexpr void set_sign(Sign signVal) {
+    if (sign() != signVal)
+      bits ^= SIGN_MASK;
+  }
 };
 
 // This layer defines all functions that are specific to how the the floating
@@ -329,9 +366,8 @@ struct FPRepSem : public FPStorage<fp_type> {
   using UP::FRACTION_MASK;
 
 protected:
-  using BiasedExp = typename UP::BiasedExponent;
-  using Exp = typename UP::Exponent;
-  using Sig = typename UP::Significand;
+  using typename UP::Exponent;
+  using typename UP::Significand;
   using UP::encode;
   using UP::exp_bits;
   using UP::exp_sig_bits;
@@ -340,61 +376,65 @@ struct FPRepSem : public FPStorage<fp_type> {
 
 public:
   // Builders
+  LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) {
+    return RetT(encode(sign, Exponent::SUB(), Significand::ZERO()));
+  }
   LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exp::ZERO(), Sig::ZERO()));
+    return RetT(encode(sign, Exponent::ZERO(), Significand::ZERO()));
   }
   LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ZEROES(), Sig::LSB()));
+    return RetT(encode(sign, Exponent::SUB(), Significand::LSB()));
   }
   LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) {
-    return RetT(
-        encode(sign, BiasedExp::BITS_ALL_ZEROES(), Sig::BITS_ALL_ONES()));
+    return RetT(encode(sign, Exponent::SUB(), Significand::BITS_ALL_ONES()));
   }
   LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exp::MIN(), Sig::ZERO()));
+    return RetT(encode(sign, Exponent::MIN(), Significand::ZERO()));
   }
   LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exp::MAX(), Sig::BITS_ALL_ONES()));
+    return RetT(encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES()));
   }
   LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(), Sig::ZERO()));
+    return RetT(encode(sign, Exponent::INF(), Significand::ZERO()));
   }
   LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS,
                                                   StorageType v = 0) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(),
-                       (v ? Sig(v) : (Sig::MSB() >> 1))));
+    return RetT(encode(sign, Exponent::INF(),
+                       (v ? Significand(v) : (Significand::MSB() >> 1))));
   }
   LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS,
                                               StorageType v = 0) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(), Sig::MSB() | Sig(v)));
+    return RetT(
+        encode(sign, Exponent::INF(), Significand::MSB() | Significand(v)));
   }
 
   // Observers
+  LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }
   LIBC_INLINE constexpr bool is_nan() const {
-    return exp_sig_bits() > encode(BiasedExp::BITS_ALL_ONES(), Sig::ZERO());
+    return exp_sig_bits() > encode(Exponent::INF(), Significand::ZERO());
   }
   LIBC_INLINE constexpr bool is_quiet_nan() const {
-    return exp_sig_bits() >= encode(BiasedExp::BITS_ALL_ONES(), Sig::MSB());
+    return exp_sig_bits() >= encode(Exponent::INF(), Significand::MSB());
   }
   LIBC_INLINE constexpr bool is_signaling_nan() const {
     return is_nan() && !is_quiet_nan();
   }
   LIBC_INLINE constexpr bool is_inf() const {
-    return exp_sig_bits() == encode(BiasedExp::BITS_ALL_ONES(), Sig::ZERO());
+    return exp_sig_bits() == encode(Exponent::INF(), Significand::ZERO());
   }
   LIBC_INLINE constexpr bool is_finite() const {
-    return exp_bits() != encode(BiasedExp::BITS_ALL_ONES());
+    return exp_bits() != encode(Exponent::INF());
   }
   LIBC_INLINE
   constexpr bool is_subnormal() const {
-    return exp_bits() == encode(BiasedExp::BITS_ALL_ZEROES());
+    return exp_bits() == encode(Exponent::SUB());
   }
   LIBC_INLINE constexpr bool is_normal() const {
     return is_finite() && !is_subnormal();
   }
   // Returns the mantissa with the implicit bit set iff the current
   // value is a valid normal number.
-  LIBC_INLINE constexpr StorageType get_explicit_mantissa() {
+  LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
     if (is_subnormal())
       return sig_bits();
     return (StorageType(1) << UP::SIG_LEN) | sig_bits();
@@ -422,44 +462,50 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
                 "whole significand");
 
 protected:
-  using BiasedExp = typename UP::BiasedExponent;
-  using Sig = typename UP::Significand;
+  using typename UP::Exponent;
+  using typename UP::Significand;
   using UP::encode;
   using UP::UP;
 
 public:
   // Builders
+  LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) {
+    return RetT(encode(sign, Exponent::SUB(), Significand::ZERO()));
+  }
   LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exponent::ZERO(), Sig::MSB()));
+    return RetT(encode(sign, Exponent::ZERO(), Significand::MSB()));
   }
   LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ZEROES(), Sig::LSB()));
+    return RetT(encode(sign, Exponent::SUB(), Significand::LSB()));
   }
   LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ZEROES(),
-                       Sig::BITS_ALL_ONES() ^ Sig::MSB()));
+    return RetT(encode(sign, Exponent::SUB(),
+                       Significand::BITS_ALL_ONES() ^ Significand::MSB()));
   }
   LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exponent::MIN(), Sig::MSB()));
+    return RetT(encode(sign, Exponent::MIN(), Significand::MSB()));
   }
   LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) {
-    return RetT(encode(sign, Exponent::MAX(), Sig::BITS_ALL_ONES()));
+    return RetT(encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES()));
   }
   LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(), Sig::MSB()));
+    return RetT(encode(sign, Exponent::INF(), Significand::MSB()));
   }
   LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS,
                                                   StorageType v = 0) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(),
-                       Sig::MSB() | (v ? Sig(v) : (Sig::MSB() >> 2))));
+    return RetT(encode(sign, Exponent::INF(),
+                       Significand::MSB() |
+                           (v ? Significand(v) : (Significand::MSB() >> 2))));
   }
   LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS,
                                               StorageType v = 0) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ONES(),
-                       Sig::MSB() | (Sig::MSB() >> 1) | Sig(v)));
+    return RetT(encode(sign, Exponent::INF(),
+                       Significand::MSB() | (Significand::MSB() >> 1) |
+                           Significand(v)));
   }
 
   // Observers
+  LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }
   LIBC_INLINE constexpr bool is_nan() const {
     // Most encoding forms from the table found in
     // https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
@@ -472,33 +518,33 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
     // - Quiet Not a Number
     // - Unnormal
     // This can be reduced to the following logic:
-    if (exp_bits() == encode(BiasedExp::BITS_ALL_ONES()))
+    if (exp_bits() == encode(Exponent::INF()))
       return !is_inf();
-    if (exp_bits() != encode(BiasedExp::BITS_ALL_ZEROES()))
-      return (sig_bits() & encode(Sig::MSB())) == 0;
+    if (exp_bits() != encode(Exponent::SUB()))
+      return (sig_bits() & encode(Significand::MSB())) == 0;
     return false;
   }
   LIBC_INLINE constexpr bool is_quiet_nan() const {
     return exp_sig_bits() >=
-           encode(BiasedExp::BITS_ALL_ONES(), Sig::MSB() | (Sig::MSB() >> 1));
+           encode(Exponent::INF(),
+                  Significand::MSB() | (Significand::MSB() >> 1));
   }
   LIBC_INLINE constexpr bool is_signaling_nan() const {
     return is_nan() && !is_quiet_nan();
   }
   LIBC_INLINE constexpr bool is_inf() const {
-    return exp_sig_bits() == encode(BiasedExp::BITS_ALL_ONES(), Sig::MSB());
+    return exp_sig_bits() == encode(Exponent::INF(), Significand::MSB());
   }
   LIBC_INLINE constexpr bool is_finite() const {
     return !is_inf() && !is_nan();
   }
   LIBC_INLINE
   constexpr bool is_subnormal() const {
-    return exp_bits() == encode(BiasedExp::BITS_ALL_ZEROES());
+    return exp_bits() == encode(Exponent::SUB());
   }
   LIBC_INLINE constexpr bool is_normal() const {
     const auto exp = exp_bits();
-    if (exp == encode(BiasedExp::BITS_ALL_ZEROES()) ||
-        exp == encode(BiasedExp::BITS_ALL_ONES()))
+    if (exp == encode(Exponent::SUB()) || exp == encode(Exponent::INF()))
       return false;
     return get_implicit_bit();
   }
@@ -520,21 +566,20 @@ struct FPRepSem<FPType::X86_Binary80, RetT>
   }
 };
 
-// 'FPRep' is the bottom of the class hierarchy that only deals with 'FPType'.
-// The operations dealing with specific float semantics are implemented by
-// 'FPRepSem' above and specialized when needed.
+// 'FPRepImpl' is the bottom of the class hierarchy that only deals with
+// 'FPType'. The operations dealing with specific float semantics are
+// implemented by 'FPRepSem' above and specialized when needed.
 //
 // The 'RetT' type is being propagated up to 'FPRepSem' so that the functions
 // creating new values (Builders) can return the appropriate type. That is, when
 // creating a value through 'FPBits' below the builder will return an 'FPBits'
 // value:
 // i.e., FPBits<float>::zero() // returns an FPBits<float>
-// When we don't care about specific C++ floating point type we can use 'FPRep'
-// directly and 'RetT' defaults to 'StorageType':
-// i.e., FPRep<FPType:IEEE754_Binary32:>::zero() // returns an 'uint32_t'
-template <FPType fp_type,
-          typename RetT = typename FPLayout<fp_type>::StorageType>
-struct FPRep : public FPRepSem<fp_type, RetT> {
+// When we don't care about specific C++ floating point type we can use
+// 'FPRepImpl' directly and 'RetT' defaults to 'StorageType': i.e.,
+// FPRepImpl<FPType:IEEE754_Binary32:>::zero() // returns an 'uint32_t'
+template <FPType fp_type, typename RetT>
+struct FPRepImpl : public FPRepSem<fp_type, RetT> {
   using UP = FPRepSem<fp_type, RetT>;
   using StorageType = typename UP::StorageType;
 
@@ -544,8 +589,9 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   using UP::exp_bits;
   using UP::exp_sig_bits;
 
-  using BiasedExp = typename UP::BiasedExponent;
-  using Sig = typename UP::Significand;
+  using typename UP::BiasedExponent;
+  using typename UP::Exponent;
+  using typename UP::Significand;
 
   using UP::FP_MASK;
   using UP::SIG_LEN;
@@ -559,14 +605,15 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
       (1 << UP::EXP_LEN) - 1;
 
-  LIBC_INLINE constexpr FPRep() = default;
-  LIBC_INLINE constexpr explicit FPRep(StorageType x) : UP(x) {}
+  // CTors
+  LIBC_INLINE constexpr FPRepImpl() = default;
+  LIBC_INLINE constexpr explicit FPRepImpl(StorageType x) : UP(x) {}
 
   // Comparison
-  LIBC_INLINE constexpr friend bool operator==(FPRep a, FPRep b) {
+  LIBC_INLINE constexpr friend bool operator==(FPRepImpl a, FPRepImpl b) {
     return a.uintval() == b.uintval();
   }
-  LIBC_INLINE constexpr friend bool operator!=(FPRep a, FPRep b) {
+  LIBC_INLINE constexpr friend bool operator!=(FPRepImpl a, FPRepImpl b) {
     return a.uintval() != b.uintval();
   }
 
@@ -577,9 +624,6 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   }
 
   // Builders
-  LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) {
-    return RetT(encode(sign, BiasedExp::BITS_ALL_ZEROES(), Sig::ZERO()));
-  }
   using UP::inf;
   using UP::max_normal;
   using UP::max_subnormal;
@@ -588,6 +632,7 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   using UP::one;
   using UP::quiet_nan;
   using UP::signaling_nan;
+  using UP::zero;
 
   // Modifiers
   LIBC_INLINE constexpr RetT abs() const {
@@ -596,8 +641,6 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
 
   // Observers
   using UP::get_explicit_mantissa;
-  LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; }
-  LIBC_INLINE constexpr bool is_inf_or_nan() const { return !is_finite(); }
   using UP::is_finite;
   using UP::is_inf;
   using UP::is_nan;
@@ -605,29 +648,22 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
   using UP::is_quiet_nan;
   using UP::is_signaling_nan;
   using UP::is_subnormal;
+  using UP::is_zero;
+  using UP::sign;
+  LIBC_INLINE constexpr bool is_inf_or_nan() const { return !is_finite(); }
   LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }
   LIBC_INLINE constexpr bool is_pos() const { return sign().is_pos(); }
 
-  // Parts
-  LIBC_INLINE constexpr Sign sign() const {
-    return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS;
-  }
-
-  LIBC_INLINE constexpr void set_sign(Sign signVal) {
-    if (sign() != signVal)
-      bits ^= SIGN_MASK;
-  }
-
   LIBC_INLINE constexpr uint16_t get_biased_exponent() const {
-    return uint16_t((bits & UP::EXP_MASK) >> UP::SIG_LEN);
+    return static_cast<uint16_t>(static_cast<uint32_t>(UP::biased_exponent()));
   }
 
   LIBC_INLINE constexpr void set_biased_exponent(StorageType biased) {
-    bits = merge(bits, biased << SIG_LEN, EXP_MASK);
+    UP::set_biased_exponent(BiasedExponent((int32_t)biased));
   }
 
   LIBC_INLINE constexpr int get_exponent() const {
-    return int(get_biased_exponent()) - EXP_BIAS;
+    return static_cast<int32_t>(Exponent(UP::biased_exponent()));
   }
 
   // If the number is subnormal, the exponent is treated as if it were the
@@ -637,14 +673,12 @@ struc...
[truncated]

libc/src/__support/FPUtil/FPBits.h Outdated Show resolved Hide resolved
@gchatelet gchatelet merged commit 25ab2fc into llvm:main Feb 5, 2024
5 checks passed
@gchatelet gchatelet deleted the refactor_fp_bits branch February 5, 2024 09:26
agozillon pushed a commit to agozillon/llvm-project that referenced this pull request Feb 5, 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.

None yet

3 participants