//===-- 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/FPBits.h" #include "src/__support/str_to_float.h" #include "utils/UnitTest/Test.h" class LlvmLibcStrToFloatTest : public __llvm_libc::testing::Test { public: template void ClingerFastPathTest( const typename __llvm_libc::fputil::FPBits::UIntType inputMantissa, const int32_t inputExp10, const typename __llvm_libc::fputil::FPBits::UIntType expectedOutputMantissa, const uint32_t expectedOutputExp2) { typename __llvm_libc::fputil::FPBits::UIntType actualOutputMantissa = 0; uint32_t actualOutputExp2 = 0; ASSERT_TRUE(__llvm_libc::internal::clingerFastPath( inputMantissa, inputExp10, &actualOutputMantissa, &actualOutputExp2)); EXPECT_EQ(actualOutputMantissa, expectedOutputMantissa); EXPECT_EQ(actualOutputExp2, expectedOutputExp2); } template void ClingerFastPathFailsTest( const typename __llvm_libc::fputil::FPBits::UIntType inputMantissa, const int32_t inputExp10) { typename __llvm_libc::fputil::FPBits::UIntType actualOutputMantissa = 0; uint32_t actualOutputExp2 = 0; ASSERT_FALSE(__llvm_libc::internal::clingerFastPath( inputMantissa, inputExp10, &actualOutputMantissa, &actualOutputExp2)); } template void EiselLemireTest( const typename __llvm_libc::fputil::FPBits::UIntType inputMantissa, const int32_t inputExp10, const typename __llvm_libc::fputil::FPBits::UIntType expectedOutputMantissa, const uint32_t expectedOutputExp2) { typename __llvm_libc::fputil::FPBits::UIntType actualOutputMantissa = 0; uint32_t actualOutputExp2 = 0; ASSERT_TRUE(__llvm_libc::internal::eiselLemire( inputMantissa, inputExp10, &actualOutputMantissa, &actualOutputExp2)); EXPECT_EQ(actualOutputMantissa, expectedOutputMantissa); EXPECT_EQ(actualOutputExp2, expectedOutputExp2); } template void SimpleDecimalConversionTest( const char *__restrict numStart, const typename __llvm_libc::fputil::FPBits::UIntType expectedOutputMantissa, const uint32_t expectedOutputExp2, const int expectedErrno = 0) { typename __llvm_libc::fputil::FPBits::UIntType actualOutputMantissa = 0; uint32_t actualOutputExp2 = 0; errno = 0; __llvm_libc::internal::simpleDecimalConversion( numStart, &actualOutputMantissa, &actualOutputExp2); EXPECT_EQ(actualOutputMantissa, expectedOutputMantissa); EXPECT_EQ(actualOutputExp2, expectedOutputExp2); EXPECT_EQ(errno, expectedErrno); } }; TEST(LlvmLibcStrToFloatTest, LeadingZeroes) { uint64_t testNum64 = 1; uint32_t numOfZeroes = 63; EXPECT_EQ(__llvm_libc::internal::leadingZeroes(0), 64u); for (; numOfZeroes < 64; testNum64 <<= 1, numOfZeroes--) { EXPECT_EQ(__llvm_libc::internal::leadingZeroes(testNum64), numOfZeroes); } testNum64 = 3; numOfZeroes = 62; for (; numOfZeroes > 63; testNum64 <<= 1, numOfZeroes--) { EXPECT_EQ(__llvm_libc::internal::leadingZeroes(testNum64), numOfZeroes); } EXPECT_EQ(__llvm_libc::internal::leadingZeroes(0xffffffffffffffff), 0u); testNum64 = 1; numOfZeroes = 63; for (; numOfZeroes > 63; testNum64 = (testNum64 << 1) + 1, numOfZeroes--) { EXPECT_EQ(__llvm_libc::internal::leadingZeroes(testNum64), numOfZeroes); } uint64_t testNum32 = 1; numOfZeroes = 31; EXPECT_EQ(__llvm_libc::internal::leadingZeroes(0), 32u); for (; numOfZeroes < 32; testNum32 <<= 1, numOfZeroes--) { EXPECT_EQ(__llvm_libc::internal::leadingZeroes(testNum32), numOfZeroes); } EXPECT_EQ(__llvm_libc::internal::leadingZeroes(0xffffffff), 0u); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64Simple) { ClingerFastPathTest(123, 0, 0xEC00000000000, 1029); ClingerFastPathTest(1234567890123456, 1, 0x5ee2a2eb5a5c0, 1076); ClingerFastPathTest(1234567890, -10, 0xf9add3739635f, 1019); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64ExtendedExp) { ClingerFastPathTest(1, 30, 0x93e5939a08cea, 1122); ClingerFastPathTest(1, 37, 0xe17b84357691b, 1145); ClingerFastPathFailsTest(10, 37); ClingerFastPathFailsTest(1, 100); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat64NegativeExp) { ClingerFastPathTest(1, -10, 0xb7cdfd9d7bdbb, 989); ClingerFastPathTest(1, -20, 0x79ca10c924223, 956); ClingerFastPathFailsTest(1, -25); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32Simple) { ClingerFastPathTest(123, 0, 0x760000, 133); ClingerFastPathTest(1234567, 1, 0x3c6146, 150); ClingerFastPathTest(12345, -5, 0x7cd35b, 123); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32ExtendedExp) { ClingerFastPathTest(1, 15, 0x635fa9, 176); ClingerFastPathTest(1, 17, 0x31a2bc, 183); ClingerFastPathFailsTest(10, 17); ClingerFastPathFailsTest(1, 50); } TEST_F(LlvmLibcStrToFloatTest, ClingerFastPathFloat32NegativeExp) { ClingerFastPathTest(1, -5, 0x27c5ac, 110); ClingerFastPathTest(1, -10, 0x5be6ff, 93); ClingerFastPathFailsTest(1, -15); } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat64Simple) { EiselLemireTest(12345678901234567890u, 1, 0x1AC53A7E04BCDA, 1089); EiselLemireTest(123, 0, 0x1EC00000000000, 1029); EiselLemireTest(12345678901234568192u, 0, 0x156A95319D63E2, 1086); } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFloat64SpecificFailures) { // These test cases have caused failures in the past. EiselLemireTest(358416272, -33, 0x1BBB2A68C9D0B9, 941); EiselLemireTest(2166568064000000238u, -9, 0x10246690000000, 1054); EiselLemireTest(2794967654709307187u, 1, 0x183e132bc608c8, 1087); EiselLemireTest(2794967654709307188u, 1, 0x183e132bc608c9, 1087); } TEST_F(LlvmLibcStrToFloatTest, EiselLemireFallbackStates) { // Check the fallback states for the algorithm: uint32_t floatOutputMantissa = 0; uint64_t doubleOutputMantissa = 0; __uint128_t tooLongMantissa = 0; uint32_t outputExp2 = 0; // This Eisel-Lemire implementation doesn't support long doubles yet. ASSERT_FALSE(__llvm_libc::internal::eiselLemire( tooLongMantissa, 0, &tooLongMantissa, &outputExp2)); // 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(__llvm_libc::internal::eiselLemire( 12345678901234549760u, 0, &doubleOutputMantissa, &outputExp2)); ASSERT_FALSE(__llvm_libc::internal::eiselLemire( 20040229, 0, &floatOutputMantissa, &outputExp2)); } TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicWholeNumbers) { SimpleDecimalConversionTest("123456789012345678900", 0x1AC53A7E04BCDA, 1089); SimpleDecimalConversionTest("123", 0x1EC00000000000, 1029); SimpleDecimalConversionTest("12345678901234549760", 0x156A95319D63D8, 1086); } TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicDecimals) { SimpleDecimalConversionTest("1.2345", 0x13c083126e978d, 1023); SimpleDecimalConversionTest(".2345", 0x1e04189374bc6a, 1020); SimpleDecimalConversionTest(".299792458", 0x132fccb4aca314, 1021); } TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicExponents) { SimpleDecimalConversionTest("1e10", 0x12a05f20000000, 1056); SimpleDecimalConversionTest("1e-10", 0x1b7cdfd9d7bdbb, 989); SimpleDecimalConversionTest("1e300", 0x17e43c8800759c, 2019); SimpleDecimalConversionTest("1e-300", 0x156e1fc2f8f359, 26); } TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion64BasicSubnormals) { SimpleDecimalConversionTest("1e-320", 0x7e8, 0); SimpleDecimalConversionTest("1e-308", 0x730d67819e8d2, 0); SimpleDecimalConversionTest("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. SimpleDecimalConversionTest("2.225073858507201e-308", 0xfffffffffffff, 0); // 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. SimpleDecimalConversionTest("2.2250738585072012e-308", 0x10000000000000, 1); } TEST_F(LlvmLibcStrToFloatTest, SimpleDecimalConversion32SpecificFailures) { SimpleDecimalConversionTest( "1.4012984643248170709237295832899161312802619418765e-45", 0x1, 0); } TEST(LlvmLibcStrToFloatTest, SimpleDecimalConversionExtraTypes) { uint32_t floatOutputMantissa = 0; uint32_t outputExp2 = 0; errno = 0; __llvm_libc::internal::simpleDecimalConversion( "123456789012345678900", &floatOutputMantissa, &outputExp2); EXPECT_EQ(floatOutputMantissa, uint32_t(0xd629d4)); EXPECT_EQ(outputExp2, uint32_t(193)); EXPECT_EQ(errno, 0); uint64_t doubleOutputMantissa = 0; outputExp2 = 0; errno = 0; __llvm_libc::internal::simpleDecimalConversion( "123456789012345678900", &doubleOutputMantissa, &outputExp2); EXPECT_EQ(doubleOutputMantissa, uint64_t(0x1AC53A7E04BCDA)); EXPECT_EQ(outputExp2, uint32_t(1089)); EXPECT_EQ(errno, 0); // TODO(michaelrj): Get long double support working. // __uint128_t longDoubleOutputMantissa = 0; // outputExp2 = 0; // errno = 0; // __llvm_libc::internal::simpleDecimalConversion( // "123456789012345678900", &longDoubleOutputMantissa, &outputExp2); // EXPECT_EQ(longDoubleOutputMantissa, __uint128_t(0x1AC53A7E04BCDA)); // EXPECT_EQ(outputExp2, uint32_t(1089)); // EXPECT_EQ(errno, 0); }