[libc-commits] [libc] aa1902f - [libc] add basic strtold implementation

Michael Jones via libc-commits libc-commits at lists.llvm.org
Mon Dec 13 10:40:49 PST 2021


Author: Michael Jones
Date: 2021-12-13T10:40:44-08:00
New Revision: aa1902f917fa3e9b31036d4ae347e74929d15fa7

URL: https://github.com/llvm/llvm-project/commit/aa1902f917fa3e9b31036d4ae347e74929d15fa7
DIFF: https://github.com/llvm/llvm-project/commit/aa1902f917fa3e9b31036d4ae347e74929d15fa7.diff

LOG: [libc] add basic strtold implementation

Due to the differences between the types of long double, this function
is effectively three functions in one. This patch adds basic support for
the types of long double, although it's just using the fast path and the
fallback for the moment. I still need to implement a version of
Eisel-Lemire for performance, but the existing algorithms should be
correct.

Reviewed By: sivachandra, lntue

Differential Revision: https://reviews.llvm.org/D113710

Added: 
    libc/src/stdlib/strtold.cpp
    libc/src/stdlib/strtold.h
    libc/test/src/stdlib/strtold_test.cpp

Modified: 
    libc/config/linux/x86_64/entrypoints.txt
    libc/spec/stdc.td
    libc/src/__support/str_to_float.h
    libc/src/stdlib/CMakeLists.txt
    libc/test/src/stdlib/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a757dc35b5d22..2e3b453561de0 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -71,6 +71,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdlib.strtod
     libc.src.stdlib.strtof
     libc.src.stdlib.strtol
+    libc.src.stdlib.strtold
     libc.src.stdlib.strtoll
     libc.src.stdlib.strtoul
     libc.src.stdlib.strtoull

diff  --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 2218bfca283f5..6a11b37163de2 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -516,8 +516,9 @@ def StdC : StandardSpec<"stdc"> {
 
           FunctionSpec<"qsort", RetValSpec<VoidType>, [ArgSpec<VoidPtr>, ArgSpec<SizeTType>, ArgSpec<SizeTType>, ArgSpec<QSortCompareT>]>,
 
-          FunctionSpec<"strtod", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
           FunctionSpec<"strtof", RetValSpec<FloatType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
+          FunctionSpec<"strtod", RetValSpec<DoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
+          FunctionSpec<"strtold", RetValSpec<LongDoubleType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>]>,
           FunctionSpec<"strtol", RetValSpec<LongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
           FunctionSpec<"strtoll", RetValSpec<LongLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,
           FunctionSpec<"strtoul", RetValSpec<UnsignedLongType>, [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtrPtr>, ArgSpec<IntType>]>,

diff  --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index 16b5cd3beee9f..a7ac3e2e9a681 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -67,6 +67,17 @@ static inline uint64_t high64(__uint128_t num) {
   return static_cast<uint64_t>(num >> 64);
 }
 
+template <class T> inline void set_implicit_bit(fputil::FPBits<T> &result) {
+  return;
+}
+
+#if defined(SPECIAL_X86_LONG_DOUBLE)
+template <>
+inline void set_implicit_bit<long double>(fputil::FPBits<long double> &result) {
+  result.set_implicit_bit(result.get_unbiased_exponent() != 0);
+}
+#endif
+
 // This Eisel-Lemire implementation is based on the algorithm described in the
 // paper Number Parsing at a Gigabyte per Second, Software: Practice and
 // Experience 51 (8), 2021 (https://arxiv.org/abs/2101.11408), as well as the
@@ -114,9 +125,12 @@ eisel_lemire(typename fputil::FPBits<T>::UIntType mantissa, int32_t exp10,
   // The halfway constant is used to check if the bits that will be shifted away
   // intially are all 1. For doubles this is 64 (bitstype size) - 52 (final
   // mantissa size) - 3 (we shift away the last two bits separately for
-  // accuracy, and the most significant bit is ignored.) = 9. Similarly, it's 6
-  // for floats in this case.
-  const uint64_t halfway_constant = sizeof(T) == 8 ? 0x1FF : 0x3F;
+  // accuracy, and the most significant bit is ignored.) = 9 bits. Similarly,
+  // it's 6 bits for floats in this case.
+  const uint64_t halfway_constant =
+      (uint64_t(1) << (BITS_IN_MANTISSA -
+                       fputil::FloatProperties<T>::MANTISSA_WIDTH - 3)) -
+      1;
   if ((high64(first_approx) & halfway_constant) == halfway_constant &&
       low64(first_approx) + mantissa < mantissa) {
     __uint128_t low_bits = static_cast<__uint128_t>(mantissa) *
@@ -289,6 +303,13 @@ simple_decimal_conversion(const char *__restrict numStart,
                             << fputil::FloatProperties<T>::MANTISSA_WIDTH) {
     final_mantissa >>= 1;
     ++exp2;
+
+    // Check if this rounding causes exp2 to go out of range and make the result
+    // INF. If this is the case, then finalMantissa and exp2 are already the
+    // correct values for an INF result.
+    if (exp2 >= fputil::FPBits<T>::MAX_EXPONENT) {
+      errno = ERANGE; // NOLINT
+    }
   }
 
   if (exp2 == 0) {
@@ -328,6 +349,45 @@ template <> class ClingerConsts<double> {
   static constexpr double MAX_EXACT_INT = 9007199254740991.0;
 };
 
+#if defined(LONG_DOUBLE_IS_DOUBLE)
+template <> class ClingerConsts<long double> {
+public:
+  static constexpr long double POWERS_OF_TEN_ARRAY[] =
+      ClingerConsts<double>::POWERS_OF_TEN_ARRAY;
+  static constexpr int32_t EXACT_POWERS_OF_TEN =
+      ClingerConsts<double>::EXACT_POWERS_OF_TEN;
+  static constexpr int32_t DIGITS_IN_MANTISSA =
+      ClingerConsts<double>::DIGITS_IN_MANTISSA;
+  static constexpr long double MAX_EXACT_INT =
+      ClingerConsts<double>::MAX_EXACT_INT;
+};
+#elif defined(SPECIAL_X86_LONG_DOUBLE)
+template <> class ClingerConsts<long double> {
+public:
+  static constexpr long double POWERS_OF_TEN_ARRAY[] = {
+      1e0L,  1e1L,  1e2L,  1e3L,  1e4L,  1e5L,  1e6L,  1e7L,  1e8L,  1e9L,
+      1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L,
+      1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L};
+  static constexpr int32_t EXACT_POWERS_OF_TEN = 27;
+  static constexpr int32_t DIGITS_IN_MANTISSA = 21;
+  static constexpr long double MAX_EXACT_INT = 18446744073709551615.0L;
+};
+#else
+template <> class ClingerConsts<long double> {
+public:
+  static constexpr long double POWERS_OF_TEN_ARRAY[] = {
+      1e0L,  1e1L,  1e2L,  1e3L,  1e4L,  1e5L,  1e6L,  1e7L,  1e8L,  1e9L,
+      1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L,
+      1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L, 1e28L, 1e29L,
+      1e30L, 1e31L, 1e32L, 1e33L, 1e34L, 1e35L, 1e36L, 1e37L, 1e38L, 1e39L,
+      1e40L, 1e41L, 1e42L, 1e43L, 1e44L, 1e45L, 1e46L, 1e47L, 1e48L};
+  static constexpr int32_t EXACT_POWERS_OF_TEN = 48;
+  static constexpr int32_t DIGITS_IN_MANTISSA = 33;
+  static constexpr long double MAX_EXACT_INT =
+      10384593717069655257060992658440191.0L;
+};
+#endif
+
 // Take an exact mantissa and exponent and attempt to convert it using only
 // exact floating point arithmetic. This only handles numbers with low
 // exponents, but handles them quickly. This is an implementation of Clinger's
@@ -837,6 +897,10 @@ static inline T strtofloatingpoint(const char *__restrict src,
   if (strEnd != nullptr)
     *strEnd = const_cast<char *>(src);
 
+  // This function only does something if T is long double and the platform uses
+  // special 80 bit long doubles. Otherwise it should be inlined out.
+  set_implicit_bit<T>(result);
+
   return T(result);
 }
 

diff  --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index f5f339080e82f..7aeb654fd2d68 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -58,6 +58,16 @@ add_entrypoint_object(
     libc.src.__support.str_to_float
 )
 
+add_entrypoint_object(
+  strtold
+  SRCS
+    strtold.cpp
+  HDRS
+    strtold.h
+  DEPENDS
+    libc.src.__support.str_to_float
+)
+
 add_entrypoint_object(
   strtol
   SRCS

diff  --git a/libc/src/stdlib/strtold.cpp b/libc/src/stdlib/strtold.cpp
new file mode 100644
index 0000000000000..58e49ae00a9bb
--- /dev/null
+++ b/libc/src/stdlib/strtold.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of strtold -----------------------------------------===//
+//
+// 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/stdlib/strtold.h"
+#include "src/__support/common.h"
+#include "src/__support/str_to_float.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(long double, strtold,
+                   (const char *__restrict str, char **__restrict str_end)) {
+  return internal::strtofloatingpoint<long double>(str, str_end);
+}
+
+} // namespace __llvm_libc

diff  --git a/libc/src/stdlib/strtold.h b/libc/src/stdlib/strtold.h
new file mode 100644
index 0000000000000..47e8732068d45
--- /dev/null
+++ b/libc/src/stdlib/strtold.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for strtold -----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDLIB_STRTOLD_H
+#define LLVM_LIBC_SRC_STDLIB_STRTOLD_H
+
+namespace __llvm_libc {
+
+long double strtold(const char *__restrict str, char **__restrict str_end);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STDLIB_STRTOLD_H

diff  --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index 230f245b25608..cd2c081a98feb 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -70,6 +70,16 @@ add_libc_unittest(
     libc.src.stdlib.strtol
 )
 
+add_libc_unittest(
+  strtold_test
+  SUITE
+    libc_stdlib_unittests
+  SRCS
+    strtold_test.cpp
+  DEPENDS
+    libc.src.stdlib.strtold
+)
+
 add_libc_unittest(
   strtoll_test
   SUITE

diff  --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp
new file mode 100644
index 0000000000000..c1d41bc302f59
--- /dev/null
+++ b/libc/test/src/stdlib/strtold_test.cpp
@@ -0,0 +1,221 @@
+//===-- Unittests for strtold ---------------------------------------------===//
+//
+// 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/stdlib/strtold.h"
+
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+
+class LlvmLibcStrToLDTest : public __llvm_libc::testing::Test {
+public:
+  void runTest(const char *inputString, const ptr
diff _t expectedStrLen,
+               const uint64_t expectedRawData64,
+               const __uint128_t expectedRawData80,
+               const __uint128_t expectedRawData128,
+               const int expectedErrno64 = 0, const int expectedErrno80 = 0,
+               const int expectedErrno128 = 0) {
+    // expectedRawData64 is the expected long double result as a uint64_t,
+    // organized according to the IEEE754 double precision format:
+    //
+    // +-- 1 Sign Bit                        +-- 52 Mantissa bits
+    // |                                     |
+    // |           +-------------------------+------------------------+
+    // |           |                                                  |
+    // SEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
+    //  |         |
+    //  +----+----+
+    //       |
+    //       +-- 11 Exponent Bits
+
+    // expectedRawData80 is the expected long double result as a __uint128_t,
+    // organized according to the x86 extended precision format:
+    //
+    // +-- 1 Sign Bit
+    // |
+    // |               +-- 1 Integer part bit (1 unless this is a subnormal)
+    // |               |
+    // SEEEEEEEEEEEEEEEIMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM...M
+    //  |             | |                                                      |
+    //  +------+------+ +---------------------------+--------------------------+
+    //         |                                    |
+    //         +-- 15 Exponent Bits                 +-- 63 Mantissa bits
+
+    // expectedRawData64 is the expected long double result as a __uint128_t,
+    // organized according to IEEE754 quadruple precision format:
+    //
+    // +-- 1 Sign Bit                               +-- 112 Mantissa bits
+    // |                                            |
+    // |               +----------------------------+--------------------------+
+    // |               |                                                       |
+    // SEEEEEEEEEEEEEEEMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM...M
+    //  |             |
+    //  +------+------+
+    //         |
+    //         +-- 15 Exponent Bits
+    char *strEnd = nullptr;
+
+#if defined(LONG_DOUBLE_IS_DOUBLE)
+    __llvm_libc::fputil::FPBits<long double> expectedFP =
+        __llvm_libc::fputil::FPBits<long double>(expectedRawData64);
+    const int expectedErrno = expectedErrno64;
+#elif defined(SPECIAL_X86_LONG_DOUBLE)
+    __llvm_libc::fputil::FPBits<long double> expectedFP =
+        __llvm_libc::fputil::FPBits<long double>(expectedRawData80);
+    const int expectedErrno = expectedErrno80;
+#else
+    __llvm_libc::fputil::FPBits<long double> expectedFP =
+        __llvm_libc::fputil::FPBits<long double>(expectedRawData128);
+    const int expectedErrno = expectedErrno128;
+#endif
+
+    errno = 0;
+    long double result = __llvm_libc::strtold(inputString, &strEnd);
+
+    __llvm_libc::fputil::FPBits<long double> actualFP =
+        __llvm_libc::fputil::FPBits<long double>();
+    actualFP = __llvm_libc::fputil::FPBits<long double>(result);
+
+    EXPECT_EQ(strEnd - inputString, expectedStrLen);
+
+    EXPECT_EQ(actualFP.bits, expectedFP.bits);
+    EXPECT_EQ(actualFP.get_sign(), expectedFP.get_sign());
+    EXPECT_EQ(actualFP.get_exponent(), expectedFP.get_exponent());
+    EXPECT_EQ(actualFP.get_mantissa(), expectedFP.get_mantissa());
+    EXPECT_EQ(errno, expectedErrno);
+  }
+};
+
+TEST_F(LlvmLibcStrToLDTest, SimpleTest) {
+  runTest("123", 3, uint64_t(0x405ec00000000000),
+          __uint128_t(0x4005f60000) << 40,
+          __uint128_t(0x4005ec0000000000) << 64);
+
+  // This should fail on Eisel-Lemire, forcing a fallback to simple decimal
+  // conversion.
+  runTest("12345678901234549760", 20, uint64_t(0x43e56a95319d63d8),
+          (__uint128_t(0x403eab54a9) << 40) + __uint128_t(0x8ceb1ec400),
+          (__uint128_t(0x403e56a95319d63d) << 64) +
+              __uint128_t(0x8800000000000000));
+
+  // Found while looking for 
diff icult test cases here:
+  // https://github.com/nigeltao/parse-number-fxx-test-data/blob/main/more-test-cases/golang-org-issue-36657.txt
+  runTest("1090544144181609348835077142190", 31, uint64_t(0x462b8779f2474dfb),
+          (__uint128_t(0x4062dc3bcf) << 40) + __uint128_t(0x923a6fd402),
+          (__uint128_t(0x4062b8779f2474df) << 64) +
+              __uint128_t(0xa804bfd8c6d5c000));
+
+  runTest("0x123", 5, uint64_t(0x4072300000000000),
+          (__uint128_t(0x4007918000) << 40),
+          (__uint128_t(0x4007230000000000) << 64));
+}
+
+// These are tests that have caused problems for doubles in the past.
+TEST_F(LlvmLibcStrToLDTest, Float64SpecificFailures) {
+  runTest("3E70000000000000", 16, uint64_t(0x7FF0000000000000),
+          (__uint128_t(0x7fff800000) << 40),
+          (__uint128_t(0x7fff000000000000) << 64), ERANGE, ERANGE, ERANGE);
+  runTest("358416272e-33", 13, uint64_t(0x3adbbb2a68c9d0b9),
+          (__uint128_t(0x3fadddd953) << 40) + __uint128_t(0x464e85c400),
+          (__uint128_t(0x3fadbbb2a68c9d0b) << 64) +
+              __uint128_t(0x8800e7969e1c5fc8));
+  runTest(
+      "2.16656806400000023841857910156251e9", 36, uint64_t(0x41e0246690000001),
+      (__uint128_t(0x401e812334) << 40) + __uint128_t(0x8000000400),
+      (__uint128_t(0x401e024669000000) << 64) + __uint128_t(0x800000000000018));
+  runTest("27949676547093071875", 20, uint64_t(0x43f83e132bc608c9),
+          (__uint128_t(0x403fc1f099) << 40) + __uint128_t(0x5e30464402),
+          (__uint128_t(0x403f83e132bc608c) << 64) +
+              __uint128_t(0x8803000000000000));
+}
+
+TEST_F(LlvmLibcStrToLDTest, MaxSizeNumbers) {
+  runTest("1.1897314953572317650e4932", 26, uint64_t(0x7FF0000000000000),
+          (__uint128_t(0x7ffeffffff) << 40) + __uint128_t(0xffffffffff),
+          (__uint128_t(0x7ffeffffffffffff) << 64) +
+              __uint128_t(0xfffd57322e3f8675),
+          ERANGE, 0, 0);
+  runTest("1.18973149535723176508e4932", 27, uint64_t(0x7FF0000000000000),
+          (__uint128_t(0x7fff800000) << 40),
+          (__uint128_t(0x7ffeffffffffffff) << 64) +
+              __uint128_t(0xffffd2478338036c),
+          ERANGE, ERANGE, 0);
+}
+
+// These tests check subnormal behavior for 80 bit and 128 bit floats. They will
+// be too small for 64 bit floats.
+TEST_F(LlvmLibcStrToLDTest, SubnormalTests) {
+  runTest("1e-4950", 7, uint64_t(0), (__uint128_t(0x00000000000000000003)),
+          (__uint128_t(0x000000000000000000057c9647e1a018)), ERANGE, ERANGE,
+          ERANGE);
+  runTest("1.89e-4951", 10, uint64_t(0), (__uint128_t(0x00000000000000000001)),
+          (__uint128_t(0x0000000000000000000109778a006738)), ERANGE, ERANGE,
+          ERANGE);
+  runTest("4e-4966", 7, uint64_t(0), (__uint128_t(0)),
+          (__uint128_t(0x00000000000000000000000000000001)), ERANGE, ERANGE,
+          ERANGE);
+}
+
+TEST_F(LlvmLibcStrToLDTest, SmallNormalTests) {
+  runTest("3.37e-4932", 10, uint64_t(0),
+          (__uint128_t(0x1804cf7) << 40) + __uint128_t(0x908850712),
+          (__uint128_t(0x10099ee12110a) << 64) + __uint128_t(0xe24b75c0f50dc0c),
+          ERANGE, 0, 0);
+}
+
+TEST_F(LlvmLibcStrToLDTest, ComplexHexadecimalTests) {
+  runTest("0x1p16383", 9, 0x7ff0000000000000, (__uint128_t(0x7ffe800000) << 40),
+          (__uint128_t(0x7ffe000000000000) << 64));
+  runTest("0x123456789abcdef", 17, 0x43723456789abcdf,
+          (__uint128_t(0x403791a2b3) << 40) + __uint128_t(0xc4d5e6f780),
+          (__uint128_t(0x403723456789abcd) << 64) +
+              __uint128_t(0xef00000000000000));
+  runTest("0x123456789abcdef0123456789ABCDEF", 33, 0x7ff0000000000000,
+          (__uint128_t(0x407791a2b3) << 40) + __uint128_t(0xc4d5e6f781),
+          (__uint128_t(0x407723456789abcd) << 64) +
+              __uint128_t(0xef0123456789abce));
+}
+
+TEST_F(LlvmLibcStrToLDTest, InfTests) {
+  runTest("INF", 3, 0x7ff0000000000000, (__uint128_t(0x7fff800000) << 40),
+          (__uint128_t(0x7fff000000000000) << 64));
+  runTest("INFinity", 8, 0x7ff0000000000000, (__uint128_t(0x7fff800000) << 40),
+          (__uint128_t(0x7fff000000000000) << 64));
+  runTest("-inf", 4, 0xfff0000000000000, (__uint128_t(0xffff800000) << 40),
+          (__uint128_t(0xffff000000000000) << 64));
+}
+
+TEST_F(LlvmLibcStrToLDTest, NaNTests) {
+  runTest("NaN", 3, 0x7ff8000000000000, (__uint128_t(0x7fffc00000) << 40),
+          (__uint128_t(0x7fff800000000000) << 64));
+  runTest("-nAn", 4, 0xfff8000000000000, (__uint128_t(0xffffc00000) << 40),
+          (__uint128_t(0xffff800000000000) << 64));
+  runTest("NaN()", 5, 0x7ff8000000000000, (__uint128_t(0x7fffc00000) << 40),
+          (__uint128_t(0x7fff800000000000) << 64));
+  runTest("NaN(1234)", 9, 0x7ff80000000004d2,
+          (__uint128_t(0x7fffc00000) << 40) + __uint128_t(0x4d2),
+          (__uint128_t(0x7fff800000000000) << 64) + __uint128_t(0x4d2));
+  runTest("NaN(0xffffffffffff)", 19, 0x7ff8ffffffffffff,
+          (__uint128_t(0x7fffc000ff) << 40) + __uint128_t(0xffffffffff),
+          (__uint128_t(0x7fff800000000000) << 64) +
+              __uint128_t(0xffffffffffff));
+  runTest("NaN(0xfffffffffffff)", 20, 0x7fffffffffffffff,
+          (__uint128_t(0x7fffc00fff) << 40) + __uint128_t(0xffffffffff),
+          (__uint128_t(0x7fff800000000000) << 64) +
+              __uint128_t(0xfffffffffffff));
+  runTest("NaN(0xffffffffffffffff)", 23, 0x7fffffffffffffff,
+          (__uint128_t(0x7fffffffff) << 40) + __uint128_t(0xffffffffff),
+          (__uint128_t(0x7fff800000000000) << 64) +
+              __uint128_t(0xffffffffffffffff));
+  runTest("NaN( 1234)", 3, 0x7ff8000000000000,
+          (__uint128_t(0x7fffc00000) << 40),
+          (__uint128_t(0x7fff800000000000) << 64));
+}


        


More information about the libc-commits mailing list