diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt index da4a2345f389c..02a0925660695 100644 --- a/libc/config/darwin/arm/entrypoints.txt +++ b/libc/config/darwin/arm/entrypoints.txt @@ -193,6 +193,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.modf libc.src.math.modff libc.src.math.modfl + libc.src.math.nan + libc.src.math.nanf + libc.src.math.nanl libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nearbyintl diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt index e29e75ec92dad..91493cb77b1d8 100644 --- a/libc/config/darwin/x86_64/entrypoints.txt +++ b/libc/config/darwin/x86_64/entrypoints.txt @@ -172,6 +172,9 @@ set(TARGET_LIBM_ENTRYPOINTS #libc.src.math.modf #libc.src.math.modff #libc.src.math.modfl + #libc.src.math.nan + #libc.src.math.nanf + #libc.src.math.nanl #libc.src.math.nearbyint #libc.src.math.nearbyintf #libc.src.math.nearbyintl diff --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt index ba86e31ee0adc..b333c6be14462 100644 --- a/libc/config/gpu/entrypoints.txt +++ b/libc/config/gpu/entrypoints.txt @@ -215,6 +215,8 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.lroundf libc.src.math.modf libc.src.math.modff + libc.src.math.nan + libc.src.math.nanf libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nextafter diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 77c9a50b8b7e5..ce3f5eb40e38a 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -313,6 +313,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.modf libc.src.math.modff libc.src.math.modfl + libc.src.math.nan + libc.src.math.nanf + libc.src.math.nanl libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nearbyintl diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index e389936ffca1e..ec2a16f5cf473 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -322,6 +322,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.modf libc.src.math.modff libc.src.math.modfl + libc.src.math.nan + libc.src.math.nanf + libc.src.math.nanl libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nearbyintl diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 3adcd57d0c084..30900de365bf9 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -323,6 +323,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.modf libc.src.math.modff libc.src.math.modfl + libc.src.math.nan + libc.src.math.nanf + libc.src.math.nanl libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nearbyintl diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index 4c0a6ec37fe4c..5c3a2e287b952 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -192,6 +192,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.modf libc.src.math.modff libc.src.math.modfl + libc.src.math.nan + libc.src.math.nanf + libc.src.math.nanl libc.src.math.nearbyint libc.src.math.nearbyintf libc.src.math.nearbyintl diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index eaa7a40a29ae7..3668524af03c2 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -212,11 +212,11 @@ Basic Operations +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ | modfl | |check| | |check| | | |check| | |check| | | | |check| | | | | | +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ -| nan | | | | | | | | | | | | | +| nan | |check| | |check| | | |check| | |check| | | | |check| | | | | | +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ -| nanf | | | | | | | | | | | | | +| nanf | |check| | |check| | | |check| | |check| | | | |check| | | | | | +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ -| nanl | | | | | | | | | | | | | +| nanl | |check| | |check| | | |check| | |check| | | | |check| | | | | | +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ | nearbyint | |check| | |check| | | |check| | |check| | | | |check| | | | | | +--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 58c95b856535a..78095eb23f071 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -515,6 +515,10 @@ def StdC : StandardSpec<"stdc"> { FunctionSpec<"scalbn", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"scalbnf", RetValSpec, [ArgSpec, ArgSpec]>, FunctionSpec<"scalbnl", RetValSpec, [ArgSpec, ArgSpec]>, + + FunctionSpec<"nanf", RetValSpec, [ArgSpec]>, + FunctionSpec<"nan", RetValSpec, [ArgSpec]>, + FunctionSpec<"nanl", RetValSpec, [ArgSpec]>, ] >; diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h index be4b55645417f..f2d4ec7fb11f8 100644 --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/bit.h" #include "src/__support/CPP/limits.h" #include "src/__support/CPP/optional.h" +#include "src/__support/CPP/string_view.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/dyadic_float.h" @@ -1044,6 +1045,27 @@ hexadecimal_string_to_float(const char *__restrict src, return output; } +LIBC_INLINE uint64_t +nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) { + uint64_t nan_mantissa = 0; + + if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) { + // This is to prevent errors when StorageType is larger than 64 + // bits, since strtointeger only supports up to 64 bits. This is + // actually more than is required by the specification, which says + // for the input type "NAN(n-char-sequence)" that "the meaning of + // the n-char sequence is implementation-defined." + auto strtoint_result = strtointeger(ncharseq.data(), 0); + if (!strtoint_result.has_error()) + nan_mantissa = strtoint_result.value; + + if (strtoint_result.parsed_len != static_cast(ncharseq.size())) + nan_mantissa = 0; + } + + return nan_mantissa; +} + // Takes a pointer to a string and a pointer to a string pointer. This function // is used as the backend for all of the string to float functions. template @@ -1136,31 +1158,18 @@ LIBC_INLINE StrToNumResult strtofloatingpoint(const char *__restrict src) { ++index; if (src[index] == ')') { ++index; - if (isdigit(src[left_paren + 1])) { - // This is to prevent errors when StorageType is larger than 64 - // bits, since strtointeger only supports up to 64 bits. This is - // actually more than is required by the specification, which says - // for the input type "NAN(n-char-sequence)" that "the meaning of - // the n-char sequence is implementation-defined." - - auto strtoint_result = - strtointeger(src + (left_paren + 1), 0); - if (strtoint_result.has_error()) { - error = strtoint_result.error; - } - nan_mantissa = static_cast(strtoint_result.value); - if (src[left_paren + 1 + strtoint_result.parsed_len] != ')') - nan_mantissa = 0; - } + auto nan_mantissa_result = nan_mantissa_from_ncharseq( + cpp::string_view(src + (left_paren + 1), index - left_paren - 2)); + nan_mantissa = static_cast(nan_mantissa_result); } else { index = left_paren; } } + if (result.get_sign()) { result = FPBits(result.build_quiet_nan(nan_mantissa)); result.set_sign(true); } else { - result.set_sign(false); result = FPBits(result.build_quiet_nan(nan_mantissa)); } } @@ -1195,6 +1204,28 @@ LIBC_INLINE StrToNumResult strtofloatingpoint(const char *__restrict src) { return {T(result), index, error}; } +template LIBC_INLINE StrToNumResult strtonan(const char *arg) { + using FPBits = typename fputil::FPBits; + using StorageType = typename FPBits::StorageType; + + FPBits result; + int error = 0; + StorageType nan_mantissa = 0; + + ptrdiff_t index = 0; + while (isalnum(arg[index]) || arg[index] == '_') + ++index; + + if (arg[index] == '\0') { + auto nan_mantissa_result = + nan_mantissa_from_ncharseq(cpp::string_view(arg, index)); + nan_mantissa = static_cast(nan_mantissa_result); + } + + result = FPBits(result.build_quiet_nan(nan_mantissa)); + return {T(result), 0, error}; +} + } // namespace internal } // namespace LIBC_NAMESPACE diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index ffabc27bc00ab..e2b1026fcad7e 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -179,6 +179,10 @@ add_math_entrypoint_object(modf) add_math_entrypoint_object(modff) add_math_entrypoint_object(modfl) +add_math_entrypoint_object(nan) +add_math_entrypoint_object(nanf) +add_math_entrypoint_object(nanl) + add_math_entrypoint_object(nearbyint) add_math_entrypoint_object(nearbyintf) add_math_entrypoint_object(nearbyintl) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 214d57842d93b..eeb09652961fd 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -1437,6 +1437,45 @@ add_entrypoint_object( -O3 ) +add_entrypoint_object( + nan + SRCS + nan.cpp + HDRS + ../nan.h + DEPENDS + libc.src.__support.str_to_float + libc.src.errno.errno + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + nanf + SRCS + nanf.cpp + HDRS + ../nanf.h + DEPENDS + libc.src.__support.str_to_float + libc.src.errno.errno + COMPILE_OPTIONS + -O3 +) + +add_entrypoint_object( + nanl + SRCS + nanl.cpp + HDRS + ../nanl.h + DEPENDS + libc.src.__support.str_to_float + libc.src.errno.errno + COMPILE_OPTIONS + -O3 +) + add_entrypoint_object( nextafter SRCS diff --git a/libc/src/math/generic/nan.cpp b/libc/src/math/generic/nan.cpp new file mode 100644 index 0000000000000..c0d7fbf4ba483 --- /dev/null +++ b/libc/src/math/generic/nan.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of nan function ------------------------------------===// +// +// 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/math/nan.h" +#include "src/__support/common.h" +#include "src/__support/str_to_float.h" +#include "src/errno/libc_errno.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(double, nan, (const char *arg)) { + auto result = internal::strtonan(arg); + if (result.has_error()) + libc_errno = result.error; + return result.value; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/nanf.cpp b/libc/src/math/generic/nanf.cpp new file mode 100644 index 0000000000000..2751a81ac4619 --- /dev/null +++ b/libc/src/math/generic/nanf.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of nanf function -----------------------------------===// +// +// 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/math/nanf.h" +#include "src/__support/common.h" +#include "src/__support/str_to_float.h" +#include "src/errno/libc_errno.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float, nanf, (const char *arg)) { + auto result = internal::strtonan(arg); + if (result.has_error()) + libc_errno = result.error; + return result.value; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/nanl.cpp b/libc/src/math/generic/nanl.cpp new file mode 100644 index 0000000000000..76dcb56b47b2d --- /dev/null +++ b/libc/src/math/generic/nanl.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of nanl function -----------------------------------===// +// +// 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/math/nanl.h" +#include "src/__support/common.h" +#include "src/__support/str_to_float.h" +#include "src/errno/libc_errno.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(long double, nanl, (const char *arg)) { + auto result = internal::strtonan(arg); + if (result.has_error()) + libc_errno = result.error; + return result.value; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/nan.h b/libc/src/math/nan.h new file mode 100644 index 0000000000000..463940b01a272 --- /dev/null +++ b/libc/src/math/nan.h @@ -0,0 +1,18 @@ +//===-- Implementation header for nan ---------------------------*- 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_MATH_NAN_H +#define LLVM_LIBC_SRC_MATH_NAN_H + +namespace LIBC_NAMESPACE { + +double nan(const char *arg); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_NAN_H diff --git a/libc/src/math/nanf.h b/libc/src/math/nanf.h new file mode 100644 index 0000000000000..f05d60e3a9671 --- /dev/null +++ b/libc/src/math/nanf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for nanf --------------------------*- 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_MATH_NANF_H +#define LLVM_LIBC_SRC_MATH_NANF_H + +namespace LIBC_NAMESPACE { + +float nanf(const char *arg); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_NANF_H diff --git a/libc/src/math/nanl.h b/libc/src/math/nanl.h new file mode 100644 index 0000000000000..d8bbce7cc1bcc --- /dev/null +++ b/libc/src/math/nanl.h @@ -0,0 +1,18 @@ +//===-- Implementation header for nanl --------------------------*- 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_MATH_NANL_H +#define LLVM_LIBC_SRC_MATH_NANL_H + +namespace LIBC_NAMESPACE { + +long double nanl(const char *arg); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_NANL_H diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 6ebd374d04a5b..65dc80c2a882a 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -1203,6 +1203,45 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + nanf_test + SUITE + libc-math-smoke-tests + SRCS + nanf_test.cpp + DEPENDS + libc.include.math + libc.include.signal + libc.src.math.nanf + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + nan_test + SUITE + libc-math-smoke-tests + SRCS + nan_test.cpp + DEPENDS + libc.include.math + libc.include.signal + libc.src.math.nan + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + nanl_test + SUITE + libc-math-smoke-tests + SRCS + nanl_test.cpp + DEPENDS + libc.include.math + libc.include.signal + libc.src.math.nanl + libc.src.__support.FPUtil.fp_bits +) + # FIXME: These tests are currently spurious for NVPTX. if(NOT LIBC_GPU_TARGET_ARCHITECTURE_IS_NVPTX) add_fp_unittest( diff --git a/libc/test/src/math/smoke/nan_test.cpp b/libc/test/src/math/smoke/nan_test.cpp new file mode 100644 index 0000000000000..ae6da143ae415 --- /dev/null +++ b/libc/test/src/math/smoke/nan_test.cpp @@ -0,0 +1,47 @@ +//===-- Unittests for nan -------------------------------------------------===// +// +// 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/math/nan.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include + +class LlvmLibcNanTest : public LIBC_NAMESPACE::testing::Test { +public: + using StorageType = LIBC_NAMESPACE::fputil::FPBits::StorageType; + + void run_test(const char *input_str, StorageType bits) { + double result = LIBC_NAMESPACE::nan(input_str); + auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); + auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); + EXPECT_EQ(actual_fp.bits, expected_fp.bits); + }; +}; + +TEST_F(LlvmLibcNanTest, NCharSeq) { + run_test("", 0x7ff8000000000000); + run_test("1234", 0x7ff80000000004d2); + run_test("0x1234", 0x7ff8000000001234); + run_test("1a", 0x7ff8000000000000); + run_test("1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_", + 0x7ff8000000000000); + run_test("10000000000000000000000000000000000000000000000000", + 0x7ff8000000000000); +} + +TEST_F(LlvmLibcNanTest, RandomString) { + run_test(" 1234", 0x7ff8000000000000); + run_test("-1234", 0x7ff8000000000000); + run_test("asd&f", 0x7ff8000000000000); + run_test("123 ", 0x7ff8000000000000); +} + +TEST_F(LlvmLibcNanTest, InvalidInput) { + EXPECT_DEATH([] { LIBC_NAMESPACE::nan(nullptr); }, WITH_SIGNAL(SIGSEGV)); +} diff --git a/libc/test/src/math/smoke/nanf_test.cpp b/libc/test/src/math/smoke/nanf_test.cpp new file mode 100644 index 0000000000000..a602aa9f8cebe --- /dev/null +++ b/libc/test/src/math/smoke/nanf_test.cpp @@ -0,0 +1,46 @@ +//===-- Unittests for nanf ------------------------------------------------===// +// +// 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/math/nanf.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include + +class LlvmLibcNanfTest : public LIBC_NAMESPACE::testing::Test { +public: + using StorageType = LIBC_NAMESPACE::fputil::FPBits::StorageType; + + void run_test(const char *input_str, StorageType bits) { + float result = LIBC_NAMESPACE::nanf(input_str); + auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); + auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); + EXPECT_EQ(actual_fp.bits, expected_fp.bits); + }; +}; + +TEST_F(LlvmLibcNanfTest, NCharSeq) { + run_test("", 0x7fc00000); + run_test("1234", 0x7fc004d2); + run_test("0x1234", 0x7fc01234); + run_test("1a", 0x7fc00000); + run_test("1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_", + 0x7fc00000); + run_test("10000000000000000000000000000000000000000000000000", 0x7fc00000); +} + +TEST_F(LlvmLibcNanfTest, RandomString) { + run_test(" 1234", 0x7fc00000); + run_test("-1234", 0x7fc00000); + run_test("asd&f", 0x7fc00000); + run_test("123 ", 0x7fc00000); +} + +TEST_F(LlvmLibcNanfTest, InvalidInput) { + EXPECT_DEATH([] { LIBC_NAMESPACE::nanf(nullptr); }, WITH_SIGNAL(SIGSEGV)); +} diff --git a/libc/test/src/math/smoke/nanl_test.cpp b/libc/test/src/math/smoke/nanl_test.cpp new file mode 100644 index 0000000000000..c0e9540161129 --- /dev/null +++ b/libc/test/src/math/smoke/nanl_test.cpp @@ -0,0 +1,72 @@ +//===-- Unittests for nanl ------------------------------------------------===// +// +// 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/math/nanl.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include + +#if defined(LIBC_LONG_DOUBLE_IS_FLOAT64) +#define SELECT_LONG_DOUBLE(val, _, __) val +#elif defined(LIBC_LONG_DOUBLE_IS_X86_FLOAT80) +#define SELECT_LONG_DOUBLE(_, val, __) val +#else +#define SELECT_LONG_DOUBLE(_, __, val) val +#endif + +class LlvmLibcNanlTest : public LIBC_NAMESPACE::testing::Test { +public: + using StorageType = LIBC_NAMESPACE::fputil::FPBits::StorageType; + + void run_test(const char *input_str, StorageType bits) { + long double result = LIBC_NAMESPACE::nanl(input_str); + auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); + auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); + EXPECT_EQ(actual_fp.bits, expected_fp.bits); + }; +}; + +TEST_F(LlvmLibcNanlTest, NCharSeq) { + run_test("", + SELECT_LONG_DOUBLE(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); + run_test("1234", SELECT_LONG_DOUBLE( + 0x7ff80000000004d2, + (UInt128(0x7fffc00000) << 40) + UInt128(0x4d2), + (UInt128(0x7fff800000000000) << 64) + UInt128(0x4d2))); + run_test("0x1234", + SELECT_LONG_DOUBLE(0x7ff8000000001234, + (UInt128(0x7fffc00000) << 40) + UInt128(0x1234), + (UInt128(0x7fff800000000000) << 64) + + UInt128(0x1234))); + run_test("1a", + SELECT_LONG_DOUBLE(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); + run_test("1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_", + SELECT_LONG_DOUBLE(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); + run_test("10000000000000000000000000000000000000000000000000", + SELECT_LONG_DOUBLE(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64))); +} + +TEST_F(LlvmLibcNanlTest, RandomString) { + StorageType expected = + SELECT_LONG_DOUBLE(0x7ff8000000000000, (UInt128(0x7fffc00000) << 40), + (UInt128(0x7fff800000000000) << 64)); + + run_test(" 1234", expected); + run_test("-1234", expected); + run_test("asd&f", expected); + run_test("123 ", expected); +} + +TEST_F(LlvmLibcNanlTest, InvalidInput) { + EXPECT_DEATH([] { LIBC_NAMESPACE::nanl(nullptr); }, WITH_SIGNAL(SIGSEGV)); +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index b5238f7686e5f..7d2bb29802552 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -1874,6 +1874,12 @@ libc_math_function(name = "llroundf") libc_math_function(name = "llroundl") +libc_math_function(name = "nan") + +libc_math_function(name = "nanf") + +libc_math_function(name = "nanl") + libc_math_function(name = "nearbyint") libc_math_function(name = "nearbyintf")