[libc] [llvm] [libc][NFC] Split str_to_float tests and reduce type clutter (PR #75471)
Guillaume Chatelet via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 14 05:28:38 PST 2023
https://github.com/gchatelet created https://github.com/llvm/llvm-project/pull/75471
None
>From 6f75f4d24b05852d91d9ca57cc8e17074aa1cf05 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 14 Dec 2023 13:28:13 +0000
Subject: [PATCH] [libc][NFC] Split str_to_float tests and reduce type clutter
---
libc/test/src/__support/CMakeLists.txt | 2 +
.../test/src/__support/str_to_double_test.cpp | 105 ++++++
libc/test/src/__support/str_to_float_test.cpp | 310 ++----------------
libc/test/src/__support/str_to_fp_test.h | 81 +++++
.../src/__support/str_to_long_double_test.cpp | 88 +++++
.../libc/test/src/__support/BUILD.bazel | 9 +-
6 files changed, 307 insertions(+), 288 deletions(-)
create mode 100644 libc/test/src/__support/str_to_double_test.cpp
create mode 100644 libc/test/src/__support/str_to_fp_test.h
create mode 100644 libc/test/src/__support/str_to_long_double_test.cpp
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
index 740209bc83d75e..fe8b3c4c84c388 100644
--- a/libc/test/src/__support/CMakeLists.txt
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -50,6 +50,8 @@ add_libc_test(
libc-support-tests
SRCS
str_to_float_test.cpp
+ str_to_double_test.cpp
+ str_to_long_double_test.cpp
DEPENDS
libc.src.__support.str_to_float
libc.src.__support.uint128
diff --git a/libc/test/src/__support/str_to_double_test.cpp b/libc/test/src/__support/str_to_double_test.cpp
new file mode 100644
index 00000000000000..b66935f0988e05
--- /dev/null
+++ b/libc/test/src/__support/str_to_double_test.cpp
@@ -0,0 +1,105 @@
+#include "str_to_fp_test.h"
+
+namespace LIBC_NAMESPACE {
+using LlvmLibcStrToDblTest = LlvmLibcStrToFloatTest<double>;
+
+TEST_F(LlvmLibcStrToDblTest, ClingerFastPathFloat64Simple) {
+ clinger_fast_path_test(123, 0, 0xEC00000000000, 1029);
+ clinger_fast_path_test(1234567890123456, 1, 0x5ee2a2eb5a5c0, 1076);
+ clinger_fast_path_test(1234567890, -10, 0xf9add3739635f, 1019);
+}
+
+TEST_F(LlvmLibcStrToDblTest, ClingerFastPathFloat64ExtendedExp) {
+ clinger_fast_path_test(1, 30, 0x93e5939a08cea, 1122);
+ clinger_fast_path_test(1, 37, 0xe17b84357691b, 1145);
+ clinger_fast_path_fails_test(10, 37);
+ clinger_fast_path_fails_test(1, 100);
+}
+
+TEST_F(LlvmLibcStrToDblTest, ClingerFastPathFloat64NegativeExp) {
+ clinger_fast_path_test(1, -10, 0xb7cdfd9d7bdbb, 989);
+ clinger_fast_path_test(1, -20, 0x79ca10c924223, 956);
+ clinger_fast_path_fails_test(1, -25);
+}
+
+TEST_F(LlvmLibcStrToDblTest, EiselLemireFloat64Simple) {
+ eisel_lemire_test(12345678901234567890u, 1, 0x1AC53A7E04BCDA, 1089);
+ eisel_lemire_test(123, 0, 0x1EC00000000000, 1029);
+ eisel_lemire_test(12345678901234568192u, 0, 0x156A95319D63E2, 1086);
+}
+
+TEST_F(LlvmLibcStrToDblTest, EiselLemireFloat64SpecificFailures) {
+ // These test cases have caused failures in the past.
+ eisel_lemire_test(358416272, -33, 0x1BBB2A68C9D0B9, 941);
+ eisel_lemire_test(2166568064000000238u, -9, 0x10246690000000, 1054);
+ eisel_lemire_test(2794967654709307187u, 1, 0x183e132bc608c8, 1087);
+ eisel_lemire_test(2794967654709307188u, 1, 0x183e132bc608c9, 1087);
+}
+
+// Check the fallback states for the algorithm:
+TEST_F(LlvmLibcStrToDblTest, EiselLemireFallbackStates) {
+ // This number can't be evaluated by Eisel-Lemire since it's exactly 1024 away
+ // from both of its closest floating point approximations
+ // (12345678901234548736 and 12345678901234550784)
+ ASSERT_FALSE(
+ internal::eisel_lemire<double>({12345678901234549760u, 0}).has_value());
+}
+
+TEST_F(LlvmLibcStrToDblTest, SimpleDecimalConversion64BasicWholeNumbers) {
+ simple_decimal_conversion_test("123456789012345678900", 0x1AC53A7E04BCDA,
+ 1089);
+ simple_decimal_conversion_test("123", 0x1EC00000000000, 1029);
+ simple_decimal_conversion_test("12345678901234549760", 0x156A95319D63D8,
+ 1086);
+}
+
+TEST_F(LlvmLibcStrToDblTest, SimpleDecimalConversion64BasicDecimals) {
+ simple_decimal_conversion_test("1.2345", 0x13c083126e978d, 1023);
+ simple_decimal_conversion_test(".2345", 0x1e04189374bc6a, 1020);
+ simple_decimal_conversion_test(".299792458", 0x132fccb4aca314, 1021);
+}
+
+TEST_F(LlvmLibcStrToDblTest, SimpleDecimalConversion64BasicExponents) {
+ simple_decimal_conversion_test("1e10", 0x12a05f20000000, 1056);
+ simple_decimal_conversion_test("1e-10", 0x1b7cdfd9d7bdbb, 989);
+ simple_decimal_conversion_test("1e300", 0x17e43c8800759c, 2019);
+ simple_decimal_conversion_test("1e-300", 0x156e1fc2f8f359, 26);
+}
+
+TEST_F(LlvmLibcStrToDblTest, SimpleDecimalConversion64BasicSubnormals) {
+ simple_decimal_conversion_test("1e-320", 0x7e8, 0, ERANGE);
+ simple_decimal_conversion_test("1e-308", 0x730d67819e8d2, 0, ERANGE);
+ simple_decimal_conversion_test("2.9e-308", 0x14da6df5e4bcc8, 1);
+}
+
+TEST_F(LlvmLibcStrToDblTest, SimpleDecimalConversion64SubnormalRounding) {
+
+ // Technically you can keep adding digits until you hit the truncation limit,
+ // but this is the shortest string that results in the maximum subnormal that
+ // I found.
+ simple_decimal_conversion_test("2.225073858507201e-308", 0xfffffffffffff, 0,
+ ERANGE);
+
+ // Same here, if you were to extend the max subnormal out for another 800
+ // digits, incrementing any one of those digits would create a normal number.
+ simple_decimal_conversion_test("2.2250738585072012e-308", 0x10000000000000,
+ 1);
+}
+
+TEST(LlvmLibcStrToDblTest, SimpleDecimalConversionExtraTypes) {
+ uint64_t double_output_mantissa = 0;
+ uint32_t output_exp2 = 0;
+
+ libc_errno = 0;
+ auto double_result =
+ internal::simple_decimal_conversion<double>("123456789012345678900");
+
+ double_output_mantissa = double_result.num.mantissa;
+ output_exp2 = double_result.num.exponent;
+
+ EXPECT_EQ(double_output_mantissa, uint64_t(0x1AC53A7E04BCDA));
+ EXPECT_EQ(output_exp2, uint32_t(1089));
+ EXPECT_EQ(double_result.error, 0);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/__support/str_to_float_test.cpp b/libc/test/src/__support/str_to_float_test.cpp
index 35f7318fb9c78d..3102fa7aa91ec1 100644
--- a/libc/test/src/__support/str_to_float_test.cpp
+++ b/libc/test/src/__support/str_to_float_test.cpp
@@ -1,321 +1,59 @@
-//===-- Unittests for str_to_float ----------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
+#include "str_to_fp_test.h"
-#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/UInt128.h"
-#include "src/__support/str_to_float.h"
-#include "src/errno/libc_errno.h"
+namespace LIBC_NAMESPACE {
-#include "test/UnitTest/Test.h"
+using LlvmLibcStrToFltTest = LlvmLibcStrToFloatTest<float>;
-class LlvmLibcStrToFloatTest : public LIBC_NAMESPACE::testing::Test {
-public:
- template <class T>
- void clinger_fast_path_test(
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType inputMantissa,
- const int32_t inputExp10,
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- expectedOutputMantissa,
- const uint32_t expectedOutputExp2) {
- typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- actual_output_mantissa = 0;
- uint32_t actual_output_exp2 = 0;
-
- auto result = LIBC_NAMESPACE::internal::clinger_fast_path<T>(
- {inputMantissa, inputExp10});
-
- ASSERT_TRUE(result.has_value());
-
- actual_output_mantissa = result->mantissa;
- actual_output_exp2 = result->exponent;
-
- EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
- EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
- }
-
- template <class T>
- void clinger_fast_path_fails_test(
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType inputMantissa,
- const int32_t inputExp10) {
- ASSERT_FALSE(LIBC_NAMESPACE::internal::clinger_fast_path<T>(
- {inputMantissa, inputExp10})
- .has_value());
- }
-
- template <class T>
- void eisel_lemire_test(
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType inputMantissa,
- const int32_t inputExp10,
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- expectedOutputMantissa,
- const uint32_t expectedOutputExp2) {
- typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- actual_output_mantissa = 0;
- uint32_t actual_output_exp2 = 0;
-
- auto result =
- LIBC_NAMESPACE::internal::eisel_lemire<T>({inputMantissa, inputExp10});
-
- ASSERT_TRUE(result.has_value());
-
- actual_output_mantissa = result->mantissa;
- actual_output_exp2 = result->exponent;
-
- EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
- EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
- }
-
- template <class T>
- void simple_decimal_conversion_test(
- const char *__restrict numStart,
- const typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- expectedOutputMantissa,
- const uint32_t expectedOutputExp2, const int expectedErrno = 0) {
- typename LIBC_NAMESPACE::fputil::FPBits<T>::UIntType
- actual_output_mantissa = 0;
- uint32_t actual_output_exp2 = 0;
- libc_errno = 0;
-
- auto result =
- LIBC_NAMESPACE::internal::simple_decimal_conversion<T>(numStart);
-
- actual_output_mantissa = result.num.mantissa;
- actual_output_exp2 = result.num.exponent;
-
- EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
- EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
- EXPECT_EQ(result.error, expectedErrno);
- }
-};
-
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64Simple) {
- clinger_fast_path_test<double>(123, 0, 0xEC00000000000, 1029);
- clinger_fast_path_test<double>(1234567890123456, 1, 0x5ee2a2eb5a5c0, 1076);
- clinger_fast_path_test<double>(1234567890, -10, 0xf9add3739635f, 1019);
+TEST_F(LlvmLibcStrToFltTest, ClingerFastPathFloat32Simple) {
+ clinger_fast_path_test(123, 0, 0x760000, 133);
+ clinger_fast_path_test(1234567, 1, 0x3c6146, 150);
+ clinger_fast_path_test(12345, -5, 0x7cd35b, 123);
}
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64ExtendedExp) {
- clinger_fast_path_test<double>(1, 30, 0x93e5939a08cea, 1122);
- clinger_fast_path_test<double>(1, 37, 0xe17b84357691b, 1145);
- clinger_fast_path_fails_test<double>(10, 37);
- clinger_fast_path_fails_test<double>(1, 100);
+TEST_F(LlvmLibcStrToFltTest, ClingerFastPathFloat32ExtendedExp) {
+ clinger_fast_path_test(1, 15, 0x635fa9, 176);
+ clinger_fast_path_test(1, 17, 0x31a2bc, 183);
+ clinger_fast_path_fails_test(10, 17);
+ clinger_fast_path_fails_test(1, 50);
}
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64NegativeExp) {
- clinger_fast_path_test<double>(1, -10, 0xb7cdfd9d7bdbb, 989);
- clinger_fast_path_test<double>(1, -20, 0x79ca10c924223, 956);
- clinger_fast_path_fails_test<double>(1, -25);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32Simple) {
- clinger_fast_path_test<float>(123, 0, 0x760000, 133);
- clinger_fast_path_test<float>(1234567, 1, 0x3c6146, 150);
- clinger_fast_path_test<float>(12345, -5, 0x7cd35b, 123);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32ExtendedExp) {
- clinger_fast_path_test<float>(1, 15, 0x635fa9, 176);
- clinger_fast_path_test<float>(1, 17, 0x31a2bc, 183);
- clinger_fast_path_fails_test<float>(10, 17);
- clinger_fast_path_fails_test<float>(1, 50);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32NegativeExp) {
- clinger_fast_path_test<float>(1, -5, 0x27c5ac, 110);
- clinger_fast_path_test<float>(1, -10, 0x5be6ff, 93);
- clinger_fast_path_fails_test<float>(1, -15);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat64Simple) {
- eisel_lemire_test<double>(12345678901234567890u, 1, 0x1AC53A7E04BCDA, 1089);
- eisel_lemire_test<double>(123, 0, 0x1EC00000000000, 1029);
- eisel_lemire_test<double>(12345678901234568192u, 0, 0x156A95319D63E2, 1086);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat64SpecificFailures) {
- // These test cases have caused failures in the past.
- eisel_lemire_test<double>(358416272, -33, 0x1BBB2A68C9D0B9, 941);
- eisel_lemire_test<double>(2166568064000000238u, -9, 0x10246690000000, 1054);
- eisel_lemire_test<double>(2794967654709307187u, 1, 0x183e132bc608c8, 1087);
- eisel_lemire_test<double>(2794967654709307188u, 1, 0x183e132bc608c9, 1087);
+TEST_F(LlvmLibcStrToFltTest, ClingerFastPathFloat32NegativeExp) {
+ clinger_fast_path_test(1, -5, 0x27c5ac, 110);
+ clinger_fast_path_test(1, -10, 0x5be6ff, 93);
+ clinger_fast_path_fails_test(1, -15);
}
// Check the fallback states for the algorithm:
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFallbackStates) {
+TEST_F(LlvmLibcStrToFltTest, EiselLemireFallbackStates) {
// This number can't be evaluated by Eisel-Lemire since it's exactly 1024 away
// from both of its closest floating point approximations
// (12345678901234548736 and 12345678901234550784)
- ASSERT_FALSE(
- LIBC_NAMESPACE::internal::eisel_lemire<double>({12345678901234549760u, 0})
- .has_value());
-
- ASSERT_FALSE(
- LIBC_NAMESPACE::internal::eisel_lemire<float>({20040229, 0}).has_value());
+ ASSERT_FALSE(internal::eisel_lemire<float>({20040229, 0}).has_value());
}
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicWholeNumbers) {
- simple_decimal_conversion_test<double>("123456789012345678900",
- 0x1AC53A7E04BCDA, 1089);
- simple_decimal_conversion_test<double>("123", 0x1EC00000000000, 1029);
- simple_decimal_conversion_test<double>("12345678901234549760",
- 0x156A95319D63D8, 1086);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicDecimals) {
- simple_decimal_conversion_test<double>("1.2345", 0x13c083126e978d, 1023);
- simple_decimal_conversion_test<double>(".2345", 0x1e04189374bc6a, 1020);
- simple_decimal_conversion_test<double>(".299792458", 0x132fccb4aca314, 1021);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicExponents) {
- simple_decimal_conversion_test<double>("1e10", 0x12a05f20000000, 1056);
- simple_decimal_conversion_test<double>("1e-10", 0x1b7cdfd9d7bdbb, 989);
- simple_decimal_conversion_test<double>("1e300", 0x17e43c8800759c, 2019);
- simple_decimal_conversion_test<double>("1e-300", 0x156e1fc2f8f359, 26);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicSubnormals) {
- simple_decimal_conversion_test<double>("1e-320", 0x7e8, 0, ERANGE);
- simple_decimal_conversion_test<double>("1e-308", 0x730d67819e8d2, 0, ERANGE);
- simple_decimal_conversion_test<double>("2.9e-308", 0x14da6df5e4bcc8, 1);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64SubnormalRounding) {
-
- // Technically you can keep adding digits until you hit the truncation limit,
- // but this is the shortest string that results in the maximum subnormal that
- // I found.
- simple_decimal_conversion_test<double>("2.225073858507201e-308",
- 0xfffffffffffff, 0, ERANGE);
-
- // Same here, if you were to extend the max subnormal out for another 800
- // digits, incrementing any one of those digits would create a normal number.
- simple_decimal_conversion_test<double>("2.2250738585072012e-308",
- 0x10000000000000, 1);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion32SpecificFailures) {
- simple_decimal_conversion_test<float>(
+TEST_F(LlvmLibcStrToFltTest, SimpleDecimalConversion32SpecificFailures) {
+ simple_decimal_conversion_test(
"1.4012984643248170709237295832899161312802619418765e-45", 0x1, 0,
ERANGE);
- simple_decimal_conversion_test<float>(
+ simple_decimal_conversion_test(
"7."
"006492321624085354618647916449580656401309709382578858785341419448955413"
"42930300743319094181060791015625e-46",
0x0, 0, ERANGE);
}
-TEST(LlvmLibcStrToFloatTest, SimpleDecimalConversionExtraTypes) {
+TEST(LlvmLibcStrToFltTest, SimpleDecimalConversionExtraTypes) {
uint32_t float_output_mantissa = 0;
uint32_t output_exp2 = 0;
libc_errno = 0;
auto float_result =
- LIBC_NAMESPACE::internal::simple_decimal_conversion<float>(
- "123456789012345678900");
+ internal::simple_decimal_conversion<float>("123456789012345678900");
float_output_mantissa = float_result.num.mantissa;
output_exp2 = float_result.num.exponent;
EXPECT_EQ(float_output_mantissa, uint32_t(0xd629d4));
EXPECT_EQ(output_exp2, uint32_t(193));
EXPECT_EQ(float_result.error, 0);
-
- uint64_t double_output_mantissa = 0;
- output_exp2 = 0;
-
- libc_errno = 0;
- auto double_result =
- LIBC_NAMESPACE::internal::simple_decimal_conversion<double>(
- "123456789012345678900");
-
- double_output_mantissa = double_result.num.mantissa;
- output_exp2 = double_result.num.exponent;
-
- EXPECT_EQ(double_output_mantissa, uint64_t(0x1AC53A7E04BCDA));
- EXPECT_EQ(output_exp2, uint32_t(1089));
- EXPECT_EQ(double_result.error, 0);
}
-#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat64AsLongDouble) {
- eisel_lemire_test<long double>(123, 0, 0x1EC00000000000, 1029);
-}
-#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80Simple) {
- eisel_lemire_test<long double>(123, 0, 0xf600000000000000, 16389);
- eisel_lemire_test<long double>(12345678901234568192u, 0, 0xab54a98ceb1f0c00,
- 16446);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80LongerMantissa) {
- eisel_lemire_test<long double>((UInt128(0x1234567812345678) << 64) +
- UInt128(0x1234567812345678),
- 0, 0x91a2b3c091a2b3c1, 16507);
- eisel_lemire_test<long double>((UInt128(0x1234567812345678) << 64) +
- UInt128(0x1234567812345678),
- 300, 0xd97757de56adb65c, 17503);
- eisel_lemire_test<long double>((UInt128(0x1234567812345678) << 64) +
- UInt128(0x1234567812345678),
- -300, 0xc30feb9a7618457d, 15510);
-}
-
-// These tests check numbers at the edge of the DETAILED_POWERS_OF_TEN table.
-// This doesn't reach very far into the range for long doubles, since it's sized
-// for doubles and their 11 exponent bits, and not for long doubles and their
-// 15 exponent bits. This is a known tradeoff, and was made because a proper
-// long double table would be approximately 16 times longer (specifically the
-// maximum exponent would need to be about 5000, leading to a 10,000 entry
-// table). This would have significant memory and storage costs all the time to
-// speed up a relatively uncommon path.
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80TableLimits) {
- eisel_lemire_test<long double>(1, 347, 0xd13eb46469447567, 17535);
- eisel_lemire_test<long double>(1, -348, 0xfa8fd5a0081c0288, 15226);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat80Fallback) {
- // This number is halfway between two possible results, and the algorithm
- // can't determine which is correct.
- ASSERT_FALSE(LIBC_NAMESPACE::internal::eisel_lemire<long double>(
- {12345678901234567890u, 1})
- .has_value());
-
- // These numbers' exponents are out of range for the current powers of ten
- // table.
- ASSERT_FALSE(LIBC_NAMESPACE::internal::eisel_lemire<long double>({1, 1000})
- .has_value());
- ASSERT_FALSE(LIBC_NAMESPACE::internal::eisel_lemire<long double>({1, -1000})
- .has_value());
-}
-#else // Quad precision long double
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128Simple) {
- eisel_lemire_test<long double>(123, 0, (UInt128(0x1ec0000000000) << 64),
- 16389);
- eisel_lemire_test<long double>(
- 12345678901234568192u, 0,
- (UInt128(0x156a95319d63e) << 64) + UInt128(0x1800000000000000), 16446);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128LongerMantissa) {
- eisel_lemire_test<long double>(
- (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 0,
- (UInt128(0x1234567812345) << 64) + UInt128(0x6781234567812345), 16507);
- eisel_lemire_test<long double>(
- (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 300,
- (UInt128(0x1b2eeafbcad5b) << 64) + UInt128(0x6cb8b4451dfcde19), 17503);
- eisel_lemire_test<long double>(
- (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), -300,
- (UInt128(0x1861fd734ec30) << 64) + UInt128(0x8afa7189f0f7595f), 15510);
-}
-
-TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat128Fallback) {
- ASSERT_FALSE(
- LIBC_NAMESPACE::internal::eisel_lemire<long double>(
- {(UInt128(0x5ce0e9a56015fec5) << 64) + UInt128(0xaadfa328ae39b333),
- 1})
- .has_value());
-}
-#endif
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/__support/str_to_fp_test.h b/libc/test/src/__support/str_to_fp_test.h
new file mode 100644
index 00000000000000..3b891fcddd3c60
--- /dev/null
+++ b/libc/test/src/__support/str_to_fp_test.h
@@ -0,0 +1,81 @@
+//===-- Unittests for str_to_float ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/FPUtil/FloatProperties.h"
+#include "src/__support/UInt128.h"
+#include "src/__support/str_to_float.h"
+#include "src/errno/libc_errno.h"
+
+#include "test/UnitTest/Test.h"
+
+namespace LIBC_NAMESPACE {
+
+template <typename T> struct LlvmLibcStrToFloatTest : public testing::Test {
+ using UIntType = typename fputil::FloatProperties<T>::UIntType;
+
+ void clinger_fast_path_test(const UIntType inputMantissa,
+ const int32_t inputExp10,
+ const UIntType expectedOutputMantissa,
+ const uint32_t expectedOutputExp2) {
+ UIntType actual_output_mantissa = 0;
+ uint32_t actual_output_exp2 = 0;
+
+ auto result = internal::clinger_fast_path<T>({inputMantissa, inputExp10});
+
+ ASSERT_TRUE(result.has_value());
+
+ actual_output_mantissa = result->mantissa;
+ actual_output_exp2 = result->exponent;
+
+ EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
+ EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
+ }
+
+ void clinger_fast_path_fails_test(const UIntType inputMantissa,
+ const int32_t inputExp10) {
+ ASSERT_FALSE(internal::clinger_fast_path<T>({inputMantissa, inputExp10})
+ .has_value());
+ }
+
+ void eisel_lemire_test(const UIntType inputMantissa, const int32_t inputExp10,
+ const UIntType expectedOutputMantissa,
+ const uint32_t expectedOutputExp2) {
+ UIntType actual_output_mantissa = 0;
+ uint32_t actual_output_exp2 = 0;
+
+ auto result = internal::eisel_lemire<T>({inputMantissa, inputExp10});
+
+ ASSERT_TRUE(result.has_value());
+
+ actual_output_mantissa = result->mantissa;
+ actual_output_exp2 = result->exponent;
+
+ EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
+ EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
+ }
+
+ void simple_decimal_conversion_test(const char *__restrict numStart,
+ const UIntType expectedOutputMantissa,
+ const uint32_t expectedOutputExp2,
+ const int expectedErrno = 0) {
+ UIntType actual_output_mantissa = 0;
+ uint32_t actual_output_exp2 = 0;
+ libc_errno = 0;
+
+ auto result = internal::simple_decimal_conversion<T>(numStart);
+
+ actual_output_mantissa = result.num.mantissa;
+ actual_output_exp2 = result.num.exponent;
+
+ EXPECT_EQ(actual_output_mantissa, expectedOutputMantissa);
+ EXPECT_EQ(actual_output_exp2, expectedOutputExp2);
+ EXPECT_EQ(result.error, expectedErrno);
+ }
+};
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/__support/str_to_long_double_test.cpp b/libc/test/src/__support/str_to_long_double_test.cpp
new file mode 100644
index 00000000000000..6fefc89ac3a945
--- /dev/null
+++ b/libc/test/src/__support/str_to_long_double_test.cpp
@@ -0,0 +1,88 @@
+#include "str_to_fp_test.h"
+
+namespace LIBC_NAMESPACE {
+
+using LlvmLibcStrToLongDblTest = LlvmLibcStrToFloatTest<long double>;
+
+#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64)
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat64AsLongDouble) {
+ eisel_lemire_test(123, 0, 0x1EC00000000000, 1029);
+}
+
+#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80)
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Simple) {
+ eisel_lemire_test(123, 0, 0xf600000000000000, 16389);
+ eisel_lemire_test(12345678901234568192u, 0, 0xab54a98ceb1f0c00, 16446);
+}
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80LongerMantissa) {
+ eisel_lemire_test((UInt128(0x1234567812345678) << 64) +
+ UInt128(0x1234567812345678),
+ 0, 0x91a2b3c091a2b3c1, 16507);
+ eisel_lemire_test((UInt128(0x1234567812345678) << 64) +
+ UInt128(0x1234567812345678),
+ 300, 0xd97757de56adb65c, 17503);
+ eisel_lemire_test((UInt128(0x1234567812345678) << 64) +
+ UInt128(0x1234567812345678),
+ -300, 0xc30feb9a7618457d, 15510);
+}
+
+// These tests check numbers at the edge of the DETAILED_POWERS_OF_TEN table.
+// This doesn't reach very far into the range for long doubles, since it's sized
+// for doubles and their 11 exponent bits, and not for long doubles and their
+// 15 exponent bits. This is a known tradeoff, and was made because a proper
+// long double table would be approximately 16 times longer (specifically the
+// maximum exponent would need to be about 5000, leading to a 10,000 entry
+// table). This would have significant memory and storage costs all the time to
+// speed up a relatively uncommon path.
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80TableLimits) {
+ eisel_lemire_test(1, 347, 0xd13eb46469447567, 17535);
+ eisel_lemire_test(1, -348, 0xfa8fd5a0081c0288, 15226);
+}
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Fallback) {
+ // This number is halfway between two possible results, and the algorithm
+ // can't determine which is correct.
+ ASSERT_FALSE(internal::eisel_lemire<long double>({12345678901234567890u, 1})
+ .has_value());
+
+ // These numbers' exponents are out of range for the current powers of ten
+ // table.
+ ASSERT_FALSE(internal::eisel_lemire<long double>({1, 1000}).has_value());
+ ASSERT_FALSE(internal::eisel_lemire<long double>({1, -1000}).has_value());
+}
+
+#else // Quad precision long double
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Simple) {
+ eisel_lemire_test(123, 0, (UInt128(0x1ec0000000000) << 64), 16389);
+ eisel_lemire_test(
+ 12345678901234568192u, 0,
+ (UInt128(0x156a95319d63e) << 64) + UInt128(0x1800000000000000), 16446);
+}
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128LongerMantissa) {
+ eisel_lemire_test(
+ (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 0,
+ (UInt128(0x1234567812345) << 64) + UInt128(0x6781234567812345), 16507);
+ eisel_lemire_test(
+ (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), 300,
+ (UInt128(0x1b2eeafbcad5b) << 64) + UInt128(0x6cb8b4451dfcde19), 17503);
+ eisel_lemire_test(
+ (UInt128(0x1234567812345678) << 64) + UInt128(0x1234567812345678), -300,
+ (UInt128(0x1861fd734ec30) << 64) + UInt128(0x8afa7189f0f7595f), 15510);
+}
+
+TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat128Fallback) {
+ ASSERT_FALSE(
+ internal::eisel_lemire<long double>(
+ {(UInt128(0x5ce0e9a56015fec5) << 64) + UInt128(0xaadfa328ae39b333),
+ 1})
+ .has_value());
+}
+
+#endif
+
+} // namespace LIBC_NAMESPACE
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
index a973e6541da015..11a7b3b7404ff7 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
@@ -42,9 +42,14 @@ libc_test(
libc_test(
name = "str_to_float_test",
- srcs = ["str_to_float_test.cpp"],
+ srcs = [
+ "str_to_double_test.cpp",
+ "str_to_float_test.cpp",
+ "str_to_fp_test.h",
+ "str_to_long_double_test.cpp",
+ ],
deps = [
- "//libc:__support_fputil_fp_bits",
+ "//libc:__support_fputil_float_properties",
"//libc:__support_str_to_float",
"//libc:__support_uint128",
],
More information about the llvm-commits
mailing list