Skip to content

[libc] Fix for adding macro I #111872

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 6 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libc/src/__support/CPP/string_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class string_view {

LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs,
size_t Length) {
for (size_t I = 0; I < Length; ++I)
if (int Diff = (int)Lhs[I] - (int)Rhs[I])
for (size_t i = 0; i < Length; ++i)
if (int Diff = (int)Lhs[i] - (int)Rhs[i])
return Diff;
return 0;
}
Expand Down
6 changes: 3 additions & 3 deletions libc/src/__support/CPP/utility/in_place.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ template <class T> struct in_place_type_t {
};
template <class T> LIBC_INLINE_VAR constexpr in_place_type_t<T> in_place_type{};

template <size_t I> struct in_place_index_t {
template <size_t IDX> struct in_place_index_t {
LIBC_INLINE explicit in_place_index_t() = default;
};
template <size_t I>
LIBC_INLINE_VAR constexpr in_place_index_t<I> in_place_index{};
template <size_t IDX>
LIBC_INLINE_VAR constexpr in_place_index_t<IDX> in_place_index{};

} // namespace cpp
} // namespace LIBC_NAMESPACE_DECL
Expand Down
41 changes: 23 additions & 18 deletions libc/src/__support/FPUtil/NearestIntegerOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,13 +346,14 @@ fromfpx(T x, int rnd, unsigned int width) {

namespace internal {

template <typename F, typename I,
cpp::enable_if_t<cpp::is_floating_point_v<F> && cpp::is_integral_v<I>,
template <typename FloatType, typename IntType,
cpp::enable_if_t<cpp::is_floating_point_v<FloatType> &&
cpp::is_integral_v<IntType>,
int> = 0>
LIBC_INLINE I rounded_float_to_signed_integer(F x) {
constexpr I INTEGER_MIN = (I(1) << (sizeof(I) * 8 - 1));
constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
FPBits<F> bits(x);
LIBC_INLINE IntType rounded_float_to_signed_integer(FloatType x) {
constexpr IntType INTEGER_MIN = (IntType(1) << (sizeof(IntType) * 8 - 1));
constexpr IntType INTEGER_MAX = -(INTEGER_MIN + 1);
FPBits<FloatType> bits(x);
auto set_domain_error_and_raise_invalid = []() {
set_errno_if_required(EDOM);
raise_except_if_required(FE_INVALID);
Expand All @@ -364,7 +365,7 @@ LIBC_INLINE I rounded_float_to_signed_integer(F x) {
}

int exponent = bits.get_exponent();
constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
constexpr int EXPONENT_LIMIT = sizeof(IntType) * 8 - 1;
if (exponent > EXPONENT_LIMIT) {
set_domain_error_and_raise_invalid();
return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
Expand All @@ -374,29 +375,33 @@ LIBC_INLINE I rounded_float_to_signed_integer(F x) {
return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
}
// If the control reaches here, then it means that the rounded
// value is the most negative number for the signed integer type I.
// value is the most negative number for the signed integer type IntType.
}

// For all other cases, if `x` can fit in the integer type `I`,
// For all other cases, if `x` can fit in the integer type `IntType`,
// we just return `x`. static_cast will convert the floating
// point value to the exact integer value.
return static_cast<I>(x);
return static_cast<IntType>(x);
}

} // namespace internal

template <typename F, typename I,
cpp::enable_if_t<cpp::is_floating_point_v<F> && cpp::is_integral_v<I>,
template <typename FloatType, typename IntType,
cpp::enable_if_t<cpp::is_floating_point_v<FloatType> &&
cpp::is_integral_v<IntType>,
int> = 0>
LIBC_INLINE I round_to_signed_integer(F x) {
return internal::rounded_float_to_signed_integer<F, I>(round(x));
LIBC_INLINE IntType round_to_signed_integer(FloatType x) {
return internal::rounded_float_to_signed_integer<FloatType, IntType>(
round(x));
}

template <typename F, typename I,
cpp::enable_if_t<cpp::is_floating_point_v<F> && cpp::is_integral_v<I>,
template <typename FloatType, typename IntType,
cpp::enable_if_t<cpp::is_floating_point_v<FloatType> &&
cpp::is_integral_v<IntType>,
int> = 0>
LIBC_INLINE I round_to_signed_integer_using_current_rounding_mode(F x) {
return internal::rounded_float_to_signed_integer<F, I>(
LIBC_INLINE IntType
round_to_signed_integer_using_current_rounding_mode(FloatType x) {
return internal::rounded_float_to_signed_integer<FloatType, IntType>(
round_using_current_rounding_mode(x));
}

Expand Down
119 changes: 61 additions & 58 deletions libc/test/src/math/RoundToIntegerTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ using LIBC_NAMESPACE::Sign;
static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
FE_TONEAREST};

template <typename F, typename I, bool TestModes = false>
template <typename FloatType, typename IntType, bool TestModes = false>
class RoundToIntegerTestTemplate
: public LIBC_NAMESPACE::testing::FEnvSafeTest {
public:
typedef I (*RoundToIntegerFunc)(F);
typedef IntType (*RoundToIntegerFunc)(FloatType);

private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<F>;
using FPBits = LIBC_NAMESPACE::fputil::FPBits<FloatType>;
using StorageType = typename FPBits::StorageType;

const F zero = FPBits::zero().get_val();
const F neg_zero = FPBits::zero(Sign::NEG).get_val();
const F inf = FPBits::inf().get_val();
const F neg_inf = FPBits::inf(Sign::NEG).get_val();
const F nan = FPBits::quiet_nan().get_val();
const FloatType zero = FPBits::zero().get_val();
const FloatType neg_zero = FPBits::zero(Sign::NEG).get_val();
const FloatType inf = FPBits::inf().get_val();
const FloatType neg_inf = FPBits::inf(Sign::NEG).get_val();
const FloatType nan = FPBits::quiet_nan().get_val();

static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();
static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();
Expand All @@ -49,11 +49,12 @@ class RoundToIntegerTestTemplate
static constexpr StorageType MIN_SUBNORMAL =
FPBits::min_subnormal().uintval();

static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
static constexpr IntType INTEGER_MIN = IntType(1)
<< (sizeof(IntType) * 8 - 1);
static constexpr IntType INTEGER_MAX = -(INTEGER_MIN + 1);

void test_one_input(RoundToIntegerFunc func, F input, I expected,
bool expectError) {
void test_one_input(RoundToIntegerFunc func, FloatType input,
IntType expected, bool expectError) {
LIBC_NAMESPACE::libc_errno = 0;
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);

Expand Down Expand Up @@ -120,35 +121,35 @@ class RoundToIntegerTestTemplate
}

void do_round_numbers_test(RoundToIntegerFunc func) {
test_one_input(func, zero, I(0), false);
test_one_input(func, neg_zero, I(0), false);
test_one_input(func, F(1.0), I(1), false);
test_one_input(func, F(-1.0), I(-1), false);
test_one_input(func, F(10.0), I(10), false);
test_one_input(func, F(-10.0), I(-10), false);
test_one_input(func, F(1234.0), I(1234), false);
test_one_input(func, F(-1234.0), I(-1234), false);
test_one_input(func, zero, IntType(0), false);
test_one_input(func, neg_zero, IntType(0), false);
test_one_input(func, FloatType(1.0), IntType(1), false);
test_one_input(func, FloatType(-1.0), IntType(-1), false);
test_one_input(func, FloatType(10.0), IntType(10), false);
test_one_input(func, FloatType(-10.0), IntType(-10), false);
test_one_input(func, FloatType(1234.0), IntType(1234), false);
test_one_input(func, FloatType(-1234.0), IntType(-1234), false);

// The rest of this function compares with an equivalent MPFR function
// which rounds floating point numbers to long values. There is no MPFR
// function to round to long long or wider integer values. So, we will
// the remaining tests only if the width of I less than equal to that of
// long.
if (sizeof(I) > sizeof(long))
// the remaining tests only if the width of IntType less than equal to that
// of long.
if (sizeof(IntType) > sizeof(long))
return;

constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
constexpr int EXPONENT_LIMIT = sizeof(IntType) * 8 - 1;
constexpr int BIASED_EXPONENT_LIMIT = EXPONENT_LIMIT + FPBits::EXP_BIAS;
if (BIASED_EXPONENT_LIMIT > FPBits::MAX_BIASED_EXPONENT)
return;
// We start with 1.0 so that the implicit bit for x86 long doubles
// is set.
FPBits bits(F(1.0));
FPBits bits(FloatType(1.0));
bits.set_biased_exponent(BIASED_EXPONENT_LIMIT);
bits.set_sign(Sign::NEG);
bits.set_mantissa(0);

F x = bits.get_val();
FloatType x = bits.get_val();
long mpfr_result;
bool erangeflag = mpfr::round_to_long(x, mpfr_result);
ASSERT_FALSE(erangeflag);
Expand All @@ -167,10 +168,11 @@ class RoundToIntegerTestTemplate
}

void do_fractions_test(RoundToIntegerFunc func, int mode) {
constexpr F FRACTIONS[] = {
F(0.5), F(-0.5), F(0.115), F(-0.115), F(0.715), F(-0.715),
constexpr FloatType FRACTIONS[] = {
FloatType(0.5), FloatType(-0.5), FloatType(0.115),
FloatType(-0.115), FloatType(0.715), FloatType(-0.715),
};
for (F x : FRACTIONS) {
for (FloatType x : FRACTIONS) {
long mpfr_long_result;
bool erangeflag;
if (TestModes)
Expand All @@ -179,7 +181,7 @@ class RoundToIntegerTestTemplate
else
erangeflag = mpfr::round_to_long(x, mpfr_long_result);
ASSERT_FALSE(erangeflag);
I mpfr_result = mpfr_long_result;
IntType mpfr_result = mpfr_long_result;
test_one_input(func, x, mpfr_result, false);
}
}
Expand All @@ -201,23 +203,23 @@ class RoundToIntegerTestTemplate
// This function compares with an equivalent MPFR function which rounds
// floating point numbers to long values. There is no MPFR function to
// round to long long or wider integer values. So, we will peform the
// comparisons in this function only if the width of I less than equal to
// that of long.
if (sizeof(I) > sizeof(long))
// comparisons in this function only if the width of IntType less than equal
// to that of long.
if (sizeof(IntType) > sizeof(long))
return;

constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
constexpr int EXPONENT_LIMIT = sizeof(IntType) * 8 - 1;
constexpr int BIASED_EXPONENT_LIMIT = EXPONENT_LIMIT + FPBits::EXP_BIAS;
if (BIASED_EXPONENT_LIMIT > FPBits::MAX_BIASED_EXPONENT)
return;
// We start with 1.0 so that the implicit bit for x86 long doubles
// is set.
FPBits bits(F(1.0));
FPBits bits(FloatType(1.0));
bits.set_biased_exponent(BIASED_EXPONENT_LIMIT);
bits.set_sign(Sign::NEG);
bits.set_mantissa(FPBits::FRACTION_MASK);

F x = bits.get_val();
FloatType x = bits.get_val();
if (TestModes) {
for (int m : ROUNDING_MODES) {
LIBC_NAMESPACE::fputil::set_round(m);
Expand All @@ -241,29 +243,29 @@ class RoundToIntegerTestTemplate
static_cast<StorageType>((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT),
StorageType(1));
for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {
F x = FPBits(i).get_val();
if (x == F(0.0))
FloatType x = FPBits(i).get_val();
if (x == FloatType(0.0))
continue;
// All subnormal numbers should round to zero.
if (TestModes) {
if (x > 0) {
LIBC_NAMESPACE::fputil::set_round(FE_UPWARD);
test_one_input(func, x, I(1), false);
test_one_input(func, x, IntType(1), false);
LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
} else {
LIBC_NAMESPACE::fputil::set_round(FE_UPWARD);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
LIBC_NAMESPACE::fputil::set_round(FE_DOWNWARD);
test_one_input(func, x, I(-1), false);
test_one_input(func, x, IntType(-1), false);
LIBC_NAMESPACE::fputil::set_round(FE_TOWARDZERO);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
LIBC_NAMESPACE::fputil::set_round(FE_TONEAREST);
test_one_input(func, x, I(0), false);
test_one_input(func, x, IntType(0), false);
}
} else {
test_one_input(func, x, 0L, false);
Expand All @@ -275,9 +277,9 @@ class RoundToIntegerTestTemplate
// This function compares with an equivalent MPFR function which rounds
// floating point numbers to long values. There is no MPFR function to
// round to long long or wider integer values. So, we will peform the
// comparisons in this function only if the width of I less than equal to
// that of long.
if (sizeof(I) > sizeof(long))
// comparisons in this function only if the width of IntType less than equal
// to that of long.
if (sizeof(IntType) > sizeof(long))
return;

constexpr int COUNT = 1'000'001;
Expand All @@ -286,7 +288,7 @@ class RoundToIntegerTestTemplate
StorageType(1));
for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {
FPBits xbits(i);
F x = xbits.get_val();
FloatType x = xbits.get_val();
// In normal range on x86 platforms, the long double implicit 1 bit can be
// zero making the numbers NaN. We will skip them.
if (xbits.is_nan())
Expand All @@ -297,7 +299,7 @@ class RoundToIntegerTestTemplate
long mpfr_long_result;
bool erangeflag = mpfr::round_to_long(x, to_mpfr_rounding_mode(m),
mpfr_long_result);
I mpfr_result = mpfr_long_result;
IntType mpfr_result = mpfr_long_result;
LIBC_NAMESPACE::fputil::set_round(m);
if (erangeflag)
test_one_input(func, x, x > 0 ? INTEGER_MAX : INTEGER_MIN, true);
Expand All @@ -307,7 +309,7 @@ class RoundToIntegerTestTemplate
} else {
long mpfr_long_result;
bool erangeflag = mpfr::round_to_long(x, mpfr_long_result);
I mpfr_result = mpfr_long_result;
IntType mpfr_result = mpfr_long_result;
if (erangeflag)
test_one_input(func, x, x > 0 ? INTEGER_MAX : INTEGER_MIN, true);
else
Expand All @@ -317,9 +319,10 @@ class RoundToIntegerTestTemplate
}
};

#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes) \
#define LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, \
TestModes) \
using LlvmLibcRoundToIntegerTest = \
RoundToIntegerTestTemplate<F, I, TestModes>; \
RoundToIntegerTestTemplate<FloatType, IntType, TestModes>; \
TEST_F(LlvmLibcRoundToIntegerTest, InfinityAndNaN) { \
testInfinityAndNaN(&func); \
} \
Expand All @@ -335,10 +338,10 @@ class RoundToIntegerTestTemplate
} \
TEST_F(LlvmLibcRoundToIntegerTest, NormalRange) { testNormalRange(&func); }

#define LIST_ROUND_TO_INTEGER_TESTS(F, I, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false)
#define LIST_ROUND_TO_INTEGER_TESTS(FloatType, IntType, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, false)

#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true)
#define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(FloatType, IntType, func) \
LIST_ROUND_TO_INTEGER_TESTS_HELPER(FloatType, IntType, func, true)

#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
Loading