diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -293,6 +293,7 @@ libc.src.math.round libc.src.math.roundf libc.src.math.roundl + libc.src.math.signbitf libc.src.math.sincosf libc.src.math.sinhf libc.src.math.sinf diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -295,6 +295,7 @@ libc.src.math.round libc.src.math.roundf libc.src.math.roundl + libc.src.math.signbitf libc.src.math.sin libc.src.math.sincosf libc.src.math.sinhf diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -464,6 +464,8 @@ FunctionSpec<"llrintf", RetValSpec, [ArgSpec]>, FunctionSpec<"llrintl", RetValSpec, [ArgSpec]>, + FunctionSpec<"signbitf", RetValSpec, [ArgSpec]>, + FunctionSpec<"sqrt", RetValSpec, [ArgSpec]>, FunctionSpec<"sqrtf", RetValSpec, [ArgSpec]>, FunctionSpec<"sqrtl", RetValSpec, [ArgSpec]>, diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h --- a/libc/src/__support/FPUtil/ManipulationFunctions.h +++ b/libc/src/__support/FPUtil/ManipulationFunctions.h @@ -60,6 +60,11 @@ } } +template , int> = 0> +static inline T signbit(T x) { + return FPBits(x).get_sign(); +} + template , int> = 0> static inline T copysign(T x, T y) { FPBits xbits(x); diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -189,6 +189,8 @@ add_math_entrypoint_object(roundf) add_math_entrypoint_object(roundl) +add_math_entrypoint_object(signbitf) + add_math_entrypoint_object(sincosf) add_math_entrypoint_object(sin) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -1380,3 +1380,15 @@ COMPILE_OPTIONS -O3 ) + +add_entrypoint_object( + signbitf + SRCS + signbitf.cpp + HDRS + ../signbitf.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + COMPILE_OPTIONS + -O2 +) \ No newline at end of file diff --git a/libc/src/math/generic/signbitf.cpp b/libc/src/math/generic/signbitf.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/generic/signbitf.cpp @@ -0,0 +1,17 @@ +//===-- Implementation of signbitf 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/signbitf.h" +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(bool, signbitf, (float x)) { return fputil::signbit(x); } + +} // namespace __llvm_libc diff --git a/libc/src/math/signbitf.h b/libc/src/math/signbitf.h new file mode 100644 --- /dev/null +++ b/libc/src/math/signbitf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for signbitf ----------------------*- 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_SIGNBITF_H +#define LLVM_LIBC_SRC_MATH_SIGNBITF_H + +namespace __llvm_libc { + +bool signbitf(float x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_SIGNBITF_H diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1529,9 +1529,24 @@ SRCS pow_test.cpp DEPENDS - libc.include.errno - libc.src.errno.errno - libc.src.math.pow + libc.include.errno + libc.src.errno.errno + libc.src.math.pow +) + +add_fp_unittest( + signbitf_test + NEED_MPFR + SUITE + libc_math_unittests + SRCS + signbitf_test.cpp + HDRS + SignBitTest.h + DEPENDS + libc.include.math + libc.src.math.signbitf + libc.src.__support.FPUtil.fp_bits ) add_subdirectory(generic) diff --git a/libc/test/src/math/SignBitTest.h b/libc/test/src/math/SignBitTest.h new file mode 100644 --- /dev/null +++ b/libc/test/src/math/SignBitTest.h @@ -0,0 +1,51 @@ +//===-- Utility class to test signbit[f|l] ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/FPMatcher.h" +#include "utils/UnitTest/Test.h" + +#include + +namespace mpfr = __llvm_libc::testing::mpfr; + +template class SignBitTest : public __llvm_libc::testing::Test { + + DECLARE_SPECIAL_CONSTANTS(T) + +public: + typedef bool (*SignBitFunc)(T); + + void testSpecialNumbers(SignBitFunc func) { + EXPECT_EQ(true, func(-1.0)); + EXPECT_EQ(false, func(1.0)); + + EXPECT_EQ(true, func(neg_inf)); + EXPECT_EQ(false, func(inf)); + + EXPECT_EQ(true, func(neg_zero)); + EXPECT_EQ(false, func(zero)); + } + + void testRange(SignBitFunc func) { + constexpr UIntType COUNT = 10000000; + constexpr UIntType STEP = UIntType(-1) / COUNT; + for (UIntType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + T x = T(FPBits(v)); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_EQ(mpfr::signbit(x), func(x)); + } + } +}; + +#define LIST_SIGNBIT_TESTS(T, func) \ + using LlvmLibcSignBitTest = SignBitTest; \ + TEST_F(LlvmLibcSignBitTest, SpecialNumbers) { testSpecialNumbers(&func); } \ + TEST_F(LlvmLibcSignBitTest, Range) { testRange(&func); } diff --git a/libc/test/src/math/signbitf_test.cpp b/libc/test/src/math/signbitf_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/signbitf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for copysignf -------------------------------------------===// +// +// 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 "SignBitTest.h" + +#include "src/math/signbitf.h" + +LIST_SIGNBIT_TESTS(float, __llvm_libc::signbitf) diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -316,6 +316,8 @@ template bool round_to_long(T x, long &result); template bool round_to_long(T x, RoundingMode mode, long &result); +template bool signbit(T x); + } // namespace mpfr } // namespace testing } // namespace __llvm_libc diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -363,6 +363,10 @@ return result; } + bool signbit() const { + return mpfr_signbit(value); + } + MPFRNumber sin() const { MPFRNumber result(*this); mpfr_sin(result.value, value, mpfr_rounding); @@ -1022,6 +1026,15 @@ template double round(double, RoundingMode); template long double round(long double, RoundingMode); +template bool signbit(T x) { + MPFRNumber mpfr(x); + return mpfr.signbit(); +} + +template bool signbit(float); +template bool signbit(double); +template bool signbit(long double); + } // namespace mpfr } // namespace testing } // namespace __llvm_libc