[libc-commits] [libc] [libc][NFC] Move functions from `FPBits` to `FPRep`, make `bits` member private (PR #79974)
Guillaume Chatelet via libc-commits
libc-commits at lists.llvm.org
Tue Jan 30 01:50:07 PST 2024
https://github.com/gchatelet created https://github.com/llvm/llvm-project/pull/79974
None
>From d8e4da02fc9afff9ef2fb47ab04f1f2382a9964c Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Tue, 30 Jan 2024 09:49:43 +0000
Subject: [PATCH] [libc][NFC] Move functions from `FPBits` to `FPRep`, make
`bits` member private
---
libc/src/__support/FPUtil/FPBits.h | 97 ++++++++++-----------
libc/src/math/generic/explogxf.h | 4 +-
libc/src/math/generic/hypotf.cpp | 4 +-
libc/src/math/generic/log1pf.cpp | 2 +-
libc/src/math/generic/range_reduction_fma.h | 6 +-
libc/test/src/math/atanhf_test.cpp | 2 +-
libc/test/src/math/smoke/atanhf_test.cpp | 2 +-
libc/test/src/math/smoke/nan_test.cpp | 2 +-
libc/test/src/math/smoke/nanf_test.cpp | 2 +-
9 files changed, 59 insertions(+), 62 deletions(-)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 5277892ac3bb2..4d441706509cf 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -551,10 +551,13 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
using UP::SIG_LEN;
public:
+ // Constants.
using UP::EXP_BIAS;
using UP::EXP_MASK;
using UP::FRACTION_MASK;
using UP::SIGN_MASK;
+ 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) {}
@@ -652,6 +655,44 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
bits = merge(bits, mantVal, FRACTION_MASK);
}
+ // TODO: Use an uint32_t for 'biased_exp'.
+ LIBC_INLINE static constexpr RetT
+ create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
+ static_assert(fp_type != FPType::X86_Binary80,
+ "This function is not tested for X86 Extended Precision");
+ return RetT(encode(sign, BiasedExp(static_cast<uint32_t>(biased_exp)),
+ Sig(mantissa)));
+ }
+
+ // The function convert integer number and unbiased exponent to proper float
+ // T type:
+ // Result = number * 2^(ep+1 - exponent_bias)
+ // Be careful!
+ // 1) "ep" is raw exponent value.
+ // 2) The function add to +1 to ep for seamless normalized to denormalized
+ // transition.
+ // 3) The function did not check exponent high limit.
+ // 4) "number" zero value is not processed correctly.
+ // 5) Number is unsigned, so the result can be only positive.
+ LIBC_INLINE static constexpr RetT make_value(StorageType number, int ep) {
+ static_assert(fp_type != FPType::X86_Binary80,
+ "This function is not tested for X86 Extended Precision");
+ FPRep result;
+ // offset: +1 for sign, but -1 for implicit first bit
+ int lz = cpp::countl_zero(number) - UP::EXP_LEN;
+ number <<= lz;
+ ep -= lz;
+
+ if (LIBC_LIKELY(ep >= 0)) {
+ // Implicit number bit will be removed by mask
+ result.set_mantissa(number);
+ result.set_biased_exponent(ep + 1);
+ } else {
+ result.set_mantissa(number >> -ep);
+ }
+ return RetT(result.uintval());
+ }
+
private:
// Merge bits from 'a' and 'b' values according to 'mask'.
// Use 'a' bits when corresponding 'mask' bits are zeroes and 'b' bits when
@@ -696,79 +737,33 @@ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
static_assert(cpp::always_false<UnqualT>, "Unsupported type");
}
-// A generic class to manipulate floating point formats.
+// A generic class to manipulate C++ floating point formats.
// It derives most of its functionality to FPRep above.
template <typename T>
struct FPBits final : public internal::FPRep<get_fp_type<T>(), FPBits<T>> {
static_assert(cpp::is_floating_point_v<T>,
"FPBits instantiated with invalid type.");
using UP = internal::FPRep<get_fp_type<T>(), FPBits<T>>;
- using Rep = UP;
using StorageType = typename UP::StorageType;
- using UP::bits;
-
- // Constants.
- LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT =
- (1 << UP::EXP_LEN) - 1;
-
// Constructors.
LIBC_INLINE constexpr FPBits() = default;
template <typename XType> LIBC_INLINE constexpr explicit FPBits(XType x) {
using Unqual = typename cpp::remove_cv_t<XType>;
if constexpr (cpp::is_same_v<Unqual, T>) {
- bits = cpp::bit_cast<StorageType>(x);
+ UP::bits = cpp::bit_cast<StorageType>(x);
} else if constexpr (cpp::is_same_v<Unqual, StorageType>) {
- bits = x;
+ UP::bits = x;
} else {
// We don't want accidental type promotions/conversions, so we require
// exact type match.
static_assert(cpp::always_false<XType>);
}
}
- // Floating-point conversions.
- LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(bits); }
-
- // TODO: Use an uint32_t for 'biased_exp'.
- LIBC_INLINE static constexpr FPBits<T>
- create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
- static_assert(get_fp_type<T>() != FPType::X86_Binary80,
- "This function is not tested for X86 Extended Precision");
- return FPBits(UP::encode(
- sign, typename UP::BiasedExponent(static_cast<uint32_t>(biased_exp)),
- typename UP::Significand(mantissa)));
- }
- // The function convert integer number and unbiased exponent to proper float
- // T type:
- // Result = number * 2^(ep+1 - exponent_bias)
- // Be careful!
- // 1) "ep" is raw exponent value.
- // 2) The function add to +1 to ep for seamless normalized to denormalized
- // transition.
- // 3) The function did not check exponent high limit.
- // 4) "number" zero value is not processed correctly.
- // 5) Number is unsigned, so the result can be only positive.
- LIBC_INLINE static constexpr FPBits<T> make_value(StorageType number,
- int ep) {
- static_assert(get_fp_type<T>() != FPType::X86_Binary80,
- "This function is not tested for X86 Extended Precision");
- FPBits<T> result;
- // offset: +1 for sign, but -1 for implicit first bit
- int lz = cpp::countl_zero(number) - UP::EXP_LEN;
- number <<= lz;
- ep -= lz;
-
- if (LIBC_LIKELY(ep >= 0)) {
- // Implicit number bit will be removed by mask
- result.set_mantissa(number);
- result.set_biased_exponent(ep + 1);
- } else {
- result.set_mantissa(number >> -ep);
- }
- return result;
- }
+ // Floating-point conversions.
+ LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(UP::bits); }
};
} // namespace fputil
diff --git a/libc/src/math/generic/explogxf.h b/libc/src/math/generic/explogxf.h
index c5e35663acbe1..8817ba1011a8c 100644
--- a/libc/src/math/generic/explogxf.h
+++ b/libc/src/math/generic/explogxf.h
@@ -283,7 +283,7 @@ LIBC_INLINE static double log2_eval(double x) {
int p1 = (bs.get_mantissa() >> (FPB::FRACTION_LEN - LOG_P1_BITS)) &
(LOG_P1_SIZE - 1);
- bs.bits &= FPB::FRACTION_MASK >> LOG_P1_BITS;
+ bs.set_uintval(bs.uintval() & (FPB::FRACTION_MASK >> LOG_P1_BITS));
bs.set_biased_exponent(FPB::EXP_BIAS);
double dx = (bs.get_val() - 1.0) * LOG_P1_1_OVER[p1];
@@ -313,7 +313,7 @@ LIBC_INLINE static double log_eval(double x) {
int p1 = static_cast<int>(bs.get_mantissa() >> (FPB::FRACTION_LEN - 7));
// Set bs to (1 + (mx - p1*2^(-7))
- bs.bits &= FPB::FRACTION_MASK >> 7;
+ bs.set_uintval(bs.uintval() & (FPB::FRACTION_MASK >> 7));
bs.set_biased_exponent(FPB::EXP_BIAS);
// dx = (mx - p1*2^(-7)) / (1 + p1*2^(-7)).
double dx = (bs.get_val() - 1.0) * ONE_OVER_F[p1];
diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp
index 4c94b3eb7b988..614aa399fcc21 100644
--- a/libc/src/math/generic/hypotf.cpp
+++ b/libc/src/math/generic/hypotf.cpp
@@ -52,9 +52,9 @@ LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) {
uint64_t lrs = result.uintval() & mask;
if (lrs == 0x0000'0000'1000'0000ULL && err < diff) {
- result.bits |= 1ULL;
+ result.set_uintval(result.uintval() | 1ULL);
} else if (lrs == 0x0000'0000'3000'0000ULL && err > diff) {
- result.bits -= 1ULL;
+ result.set_uintval(result.uintval() - 1ULL);
}
} else {
FPBits bits_x(x), bits_y(y);
diff --git a/libc/src/math/generic/log1pf.cpp b/libc/src/math/generic/log1pf.cpp
index 8de4a2067f9d3..a8ed28f8484b4 100644
--- a/libc/src/math/generic/log1pf.cpp
+++ b/libc/src/math/generic/log1pf.cpp
@@ -64,7 +64,7 @@ LIBC_INLINE float log(double x) {
FPBits f = xbits;
// Clear the lowest 45 bits.
- f.bits &= ~0x0000'1FFF'FFFF'FFFFULL;
+ f.set_uintval(f.uintval() & ~0x0000'1FFF'FFFF'FFFFULL);
double d = xbits.get_val() - f.get_val();
d *= ONE_OVER_F[f_index];
diff --git a/libc/src/math/generic/range_reduction_fma.h b/libc/src/math/generic/range_reduction_fma.h
index d2ca5d348aadd..aee8cbb1332a6 100644
--- a/libc/src/math/generic/range_reduction_fma.h
+++ b/libc/src/math/generic/range_reduction_fma.h
@@ -51,7 +51,8 @@ LIBC_INLINE int64_t large_range_reduction(double x, int x_exp, double &y) {
// - When |x| >= 2^55, the LSB of double(x * THIRTYTWO_OVER_PI[0]) is at
// least 2^6.
fputil::FPBits<double> prod_hi(x * THIRTYTWO_OVER_PI[0]);
- prod_hi.bits &= (x_exp < 55) ? (~0xfffULL) : (~0ULL); // |x| < 2^55
+ prod_hi.set_uintval(prod_hi.uintval() &
+ ((x_exp < 55) ? (~0xfffULL) : (~0ULL))); // |x| < 2^55
double k_hi = fputil::nearest_integer(prod_hi.get_val());
double truncated_prod = fputil::fma(x, THIRTYTWO_OVER_PI[0], -k_hi);
double prod_lo = fputil::fma(x, THIRTYTWO_OVER_PI[1], truncated_prod);
@@ -70,7 +71,8 @@ LIBC_INLINE int64_t large_range_reduction(double x, int x_exp, double &y) {
// - When |x| >= 2^110, the LSB of double(x * THIRTYTWO_OVER_PI[1]) is at
// least 64.
fputil::FPBits<double> prod_hi(x * THIRTYTWO_OVER_PI[1]);
- prod_hi.bits &= (x_exp < 110) ? (~0xfffULL) : (~0ULL); // |x| < 2^110
+ prod_hi.set_uintval(prod_hi.uintval() &
+ ((x_exp < 110) ? (~0xfffULL) : (~0ULL))); // |x| < 2^110
double k_hi = fputil::nearest_integer(prod_hi.get_val());
double truncated_prod = fputil::fma(x, THIRTYTWO_OVER_PI[1], -k_hi);
double prod_lo = fputil::fma(x, THIRTYTWO_OVER_PI[2], truncated_prod);
diff --git a/libc/test/src/math/atanhf_test.cpp b/libc/test/src/math/atanhf_test.cpp
index 0080a328fbea6..9dea65dccd8fd 100644
--- a/libc/test/src/math/atanhf_test.cpp
+++ b/libc/test/src/math/atanhf_test.cpp
@@ -50,7 +50,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
EXPECT_MATH_ERRNO(ERANGE);
auto bt = FPBits(1.0f);
- bt.bits += 1;
+ bt.set_uintval(bt.uintval() + 1);
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val()));
diff --git a/libc/test/src/math/smoke/atanhf_test.cpp b/libc/test/src/math/smoke/atanhf_test.cpp
index f27b8e130fc91..c613f9bdf35f3 100644
--- a/libc/test/src/math/smoke/atanhf_test.cpp
+++ b/libc/test/src/math/smoke/atanhf_test.cpp
@@ -45,7 +45,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
EXPECT_MATH_ERRNO(ERANGE);
auto bt = FPBits(1.0f);
- bt.bits += 1;
+ bt.set_uintval(bt.uintval() + 1);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf(bt.get_val()),
FE_INVALID);
diff --git a/libc/test/src/math/smoke/nan_test.cpp b/libc/test/src/math/smoke/nan_test.cpp
index 81e1400f0bb6b..56c1e9164df41 100644
--- a/libc/test/src/math/smoke/nan_test.cpp
+++ b/libc/test/src/math/smoke/nan_test.cpp
@@ -20,7 +20,7 @@ class LlvmLibcNanTest : public LIBC_NAMESPACE::testing::Test {
double result = LIBC_NAMESPACE::nan(input_str);
auto actual_fp = LIBC_NAMESPACE::fputil::FPBits<double>(result);
auto expected_fp = LIBC_NAMESPACE::fputil::FPBits<double>(bits);
- EXPECT_EQ(actual_fp.bits, expected_fp.bits);
+ EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval());
};
};
diff --git a/libc/test/src/math/smoke/nanf_test.cpp b/libc/test/src/math/smoke/nanf_test.cpp
index 1d337ecf1dcd0..bce495f1a9738 100644
--- a/libc/test/src/math/smoke/nanf_test.cpp
+++ b/libc/test/src/math/smoke/nanf_test.cpp
@@ -20,7 +20,7 @@ class LlvmLibcNanfTest : public LIBC_NAMESPACE::testing::Test {
float result = LIBC_NAMESPACE::nanf(input_str);
auto actual_fp = LIBC_NAMESPACE::fputil::FPBits<float>(result);
auto expected_fp = LIBC_NAMESPACE::fputil::FPBits<float>(bits);
- EXPECT_EQ(actual_fp.bits, expected_fp.bits);
+ EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval());
};
};
More information about the libc-commits
mailing list