Skip to content

Commit

Permalink
[libc][NFC] Move functions from FPBits to FPRep, make bits memb…
Browse files Browse the repository at this point in the history
…er private (llvm#79974)
  • Loading branch information
gchatelet authored Jan 30, 2024
1 parent 0f9ab7b commit 24a903c
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 62 deletions.
100 changes: 49 additions & 51 deletions libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand Down Expand Up @@ -652,6 +655,47 @@ struct FPRep : public FPRepSem<fp_type, RetT> {
bits = merge(bits, mantVal, FRACTION_MASK);
}

// Unsafe function to create a floating point representation.
// It simply packs the sign, biased exponent and mantissa values without
// checking bound nor normalization.
// FIXME: 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 converts integer number and unbiased exponent to proper float
// T type:
// Result = number * 2^(ep+1 - exponent_bias)
// Be careful!
// 1) "ep" is the raw exponent value.
// 2) The function adds +1 to ep for seamless normalized to denormalized
// transition.
// 3) The function does 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
Expand Down Expand Up @@ -696,79 +740,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
Expand Down
4 changes: 2 additions & 2 deletions libc/src/math/generic/explogxf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -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];
Expand Down
4 changes: 2 additions & 2 deletions libc/src/math/generic/hypotf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libc/src/math/generic/log1pf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
6 changes: 4 additions & 2 deletions libc/src/math/generic/range_reduction_fma.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/atanhf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/atanhf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/nan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
};
};

Expand Down
2 changes: 1 addition & 1 deletion libc/test/src/math/smoke/nanf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
};
};

Expand Down

0 comments on commit 24a903c

Please sign in to comment.