diff options
Diffstat (limited to 'libc')
32 files changed, 411 insertions, 32 deletions
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 4824684..8bf6c44 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -735,6 +735,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.rintf16 libc.src.math.roundevenf16 libc.src.math.roundf16 + libc.src.math.rsqrtf libc.src.math.rsqrtf16 libc.src.math.scalblnf16 libc.src.math.scalbnf16 diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 99c9d3d..dffccba 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -750,6 +750,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.rintf16 libc.src.math.roundevenf16 libc.src.math.roundf16 + libc.src.math.rsqrtf libc.src.math.rsqrtf16 libc.src.math.scalblnf16 libc.src.math.scalbnf16 diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 82a83a2..b4ab073 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -786,6 +786,7 @@ if(LIBC_TYPES_HAS_FLOAT16) libc.src.math.rintf16 libc.src.math.roundevenf16 libc.src.math.roundf16 + libc.src.math.rsqrtf libc.src.math.rsqrtf16 libc.src.math.scalblnf16 libc.src.math.scalbnf16 diff --git a/libc/docs/build_and_test.rst b/libc/docs/build_and_test.rst index dfdd965..d608591 100644 --- a/libc/docs/build_and_test.rst +++ b/libc/docs/build_and_test.rst @@ -47,12 +47,18 @@ and put the following in your settings.json file: .. code-block:: javascript { - "cmake.sourceDirectory": "${workspaceFolder}/llvm", + "cmake.sourceDirectory": "${workspaceFolder}/runtimes", "cmake.configureSettings": { - "LLVM_ENABLE_PROJECTS" : "libc", - "LLVM_LIBC_FULL_BUILD" : true, - "LLVM_ENABLE_SPHINX" : true, - "LIBC_INCLUDE_DOCS" : true + "LLVM_ENABLE_RUNTIMES" : ["libc", "compiler-rt"], + "LLVM_LIBC_FULL_BUILD" : true, + "LLVM_ENABLE_SPHINX" : true, + "LIBC_INCLUDE_DOCS" : true, + "LLVM_LIBC_INCLUDE_SCUDO" : true, + "COMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC": true, + "COMPILER_RT_BUILD_GWP_ASAN" : false, + "COMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED" : false, + "CMAKE_EXPORT_COMPILE_COMMANDS" : true, + "LIBC_CMAKE_VERBOSE_LOGGING" : true } } diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst index 51bf238..51bb17f 100644 --- a/libc/docs/headers/math/index.rst +++ b/libc/docs/headers/math/index.rst @@ -343,7 +343,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | rootn | | | | | | | 7.12.7.8 | F.10.4.8 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ -| rsqrt | | | | |check| | | | 7.12.7.9 | F.10.4.9 | +| rsqrt | |check| | | | |check| | | | 7.12.7.9 | F.10.4.9 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | sin | |check| | |check| | | |check| | | | 7.12.4.6 | F.10.1.6 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/include/math.yaml b/libc/include/math.yaml index 6c800a0..afd3ae3 100644 --- a/libc/include/math.yaml +++ b/libc/include/math.yaml @@ -2349,6 +2349,12 @@ functions: return_type: long double arguments: - type: long double + - name: rsqrtf + standards: + - stdc + return_type: float + arguments: + - type: float - name: rsqrtf16 standards: - stdc diff --git a/libc/shared/math.h b/libc/shared/math.h index 1262fa6..82b9250 100644 --- a/libc/shared/math.h +++ b/libc/shared/math.h @@ -57,7 +57,7 @@ #include "math/ldexpf.h" #include "math/ldexpf128.h" #include "math/ldexpf16.h" - +#include "math/rsqrtf.h" #include "math/rsqrtf16.h" #endif // LLVM_LIBC_SHARED_MATH_H diff --git a/libc/shared/math/rsqrtf.h b/libc/shared/math/rsqrtf.h new file mode 100644 index 0000000..32d0a61 --- /dev/null +++ b/libc/shared/math/rsqrtf.h @@ -0,0 +1,23 @@ +//===-- Shared rsqrtf function ----------------------------------*- 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_SHARED_MATH_RSQRTF_H +#define LLVM_LIBC_SHARED_MATH_RSQRTF_H + +#include "shared/libc_common.h" +#include "src/__support/math/rsqrtf.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::rsqrtf; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_RSQRTF_H diff --git a/libc/shared/math/rsqrtf16.h b/libc/shared/math/rsqrtf16.h index 54c7499..8dbf065 100644 --- a/libc/shared/math/rsqrtf16.h +++ b/libc/shared/math/rsqrtf16.h @@ -1,4 +1,4 @@ -//===-- Shared rsqrtf16 function -------------------------------*- C++ -*-===// +//===-- Shared rsqrtf16 function --------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libc/src/__support/OSUtil/linux/auxv.h b/libc/src/__support/OSUtil/linux/auxv.h index 894868a..9c07c54 100644 --- a/libc/src/__support/OSUtil/linux/auxv.h +++ b/libc/src/__support/OSUtil/linux/auxv.h @@ -16,6 +16,7 @@ #include <linux/auxvec.h> // For AT_ macros #include <linux/mman.h> // For mmap flags +#include <linux/param.h> // For EXEC_PAGESIZE #include <linux/prctl.h> // For prctl #include <sys/syscall.h> // For syscall numbers @@ -90,7 +91,7 @@ LIBC_INLINE void Vector::fallback_initialize_unsync() { PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // We do not proceed if mmap fails. - if (mmap_ret <= 0) + if (!linux_utils::is_valid_mmap(mmap_ret)) return; // Initialize the auxv array with AT_NULL entries. diff --git a/libc/src/__support/OSUtil/linux/syscall.h b/libc/src/__support/OSUtil/linux/syscall.h index 24e0fca..0e25618 100644 --- a/libc/src/__support/OSUtil/linux/syscall.h +++ b/libc/src/__support/OSUtil/linux/syscall.h @@ -12,6 +12,7 @@ #include "src/__support/CPP/bit.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" #include "src/__support/macros/properties/architectures.h" #ifdef LIBC_TARGET_ARCH_IS_X86_32 @@ -34,6 +35,19 @@ LIBC_INLINE R syscall_impl(long __number, Ts... ts) { return cpp::bit_or_static_cast<R>(syscall_impl(__number, (long)ts...)); } +// Linux-specific function for checking +namespace linux_utils { +LIBC_INLINE_VAR constexpr unsigned long MAX_ERRNO = 4095; +// Ideally, this should be defined using PAGE_OFFSET +// However, that is a configurable parameter. We mimic kernel's behavior +// by checking against MAX_ERRNO. +template <typename PointerLike> +LIBC_INLINE constexpr bool is_valid_mmap(PointerLike ptr) { + long addr = cpp::bit_cast<long>(ptr); + return LIBC_LIKELY(addr > 0 || addr < -static_cast<long>(MAX_ERRNO)); +} +} // namespace linux_utils + } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSCALL_H diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index 203ebb4..61253de 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -109,22 +109,6 @@ add_header_library( libc.src.__support.macros.properties.types ) - -add_header_library( - rsqrtf16 - HDRS - rsqrtf16.h - DEPENDS - libc.src.__support.FPUtil.cast - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.manipulation_functions - libc.src.__support.macros.optimization - libc.src.__support.macros.properties.types -) - add_header_library( asin_utils HDRS @@ -867,6 +851,34 @@ add_header_library( ) add_header_library( + rsqrtf + HDRS + rsqrtf.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization +) + +add_header_library( + rsqrtf16 + HDRS + rsqrtf16.h + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization +) + +add_header_library( sincos_eval HDRS sincos_eval.h diff --git a/libc/src/__support/math/rsqrtf.h b/libc/src/__support/math/rsqrtf.h new file mode 100644 index 0000000..5da1e73 --- /dev/null +++ b/libc/src/__support/math/rsqrtf.h @@ -0,0 +1,71 @@ +//===-- Implementation header for rsqrtf ------------------------*- 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___SUPPORT_MATH_RSQRTF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static constexpr float rsqrtf(float x) { + using FPBits = fputil::FPBits<float>; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + + constexpr uint32_t INF_BITS = FPBits::inf().uintval(); + + // x is 0, inf/nan, or negative. + if (LIBC_UNLIKELY(x_u == 0 || x_u >= INF_BITS)) { + // x is NaN + if (x_abs > INF_BITS) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + return x; + } + + // |x| = 0 + if (x_abs == 0) { + fputil::raise_except_if_required(FE_DIVBYZERO); + fputil::set_errno_if_required(ERANGE); + return FPBits::inf(xbits.sign()).get_val(); + } + + // -inf <= x < 0 + if (x_u > 0x7fff'ffffU) { + fputil::raise_except_if_required(FE_INVALID); + fputil::set_errno_if_required(EDOM); + return FPBits::quiet_nan().get_val(); + } + + // x = +inf => rsqrt(x) = 0 + return FPBits::zero(xbits.sign()).get_val(); + } + + // TODO: add float based approximation when + // LIBC_TARGET_CPU_HAS_FPU_DOUBLE is not defined + double result = 1.0 / fputil::sqrt<double>(fputil::cast<double>(x)); + + return fputil::cast<float>(result); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_RSQRTF_H diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp index d9e479ee..4f1e911 100644 --- a/libc/src/__support/threads/linux/thread.cpp +++ b/libc/src/__support/threads/linux/thread.cpp @@ -100,7 +100,7 @@ LIBC_INLINE ErrorOr<void *> alloc_stack(size_t stacksize, size_t guardsize) { -1, // Not backed by any file 0 // No offset ); - if (mmap_result < 0 && (uintptr_t(mmap_result) >= UINTPTR_MAX - size)) + if (!linux_utils::is_valid_mmap(mmap_result)) return Error{int(-mmap_result)}; if (guardsize) { diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 3c7e99f..e37e22f 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -517,6 +517,7 @@ add_math_entrypoint_object(roundevenf16) add_math_entrypoint_object(roundevenf128) add_math_entrypoint_object(roundevenbf16) +add_math_entrypoint_object(rsqrtf) add_math_entrypoint_object(rsqrtf16) add_math_entrypoint_object(scalbln) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 5738fe8..55f4aaf 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -989,6 +989,16 @@ add_entrypoint_object( ) add_entrypoint_object( + rsqrtf + SRCS + rsqrtf.cpp + HDRS + ../rsqrtf.h + DEPENDS + libc.src.__support.math.rsqrtf +) + +add_entrypoint_object( rsqrtf16 SRCS rsqrtf16.cpp diff --git a/libc/src/math/generic/rsqrtf.cpp b/libc/src/math/generic/rsqrtf.cpp new file mode 100644 index 0000000..6a38fa7 --- /dev/null +++ b/libc/src/math/generic/rsqrtf.cpp @@ -0,0 +1,16 @@ +//===-- Single-precision rsqrt 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/rsqrtf.h" +#include "src/__support/math/rsqrtf.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float, rsqrtf, (float x)) { return math::rsqrtf(x); } + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/rsqrtf.h b/libc/src/math/rsqrtf.h new file mode 100644 index 0000000..bc55904 --- /dev/null +++ b/libc/src/math/rsqrtf.h @@ -0,0 +1,20 @@ +//===-- Implementation header for rsqrtf ------------------------*- 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_RSQRTF_H +#define LLVM_LIBC_SRC_MATH_RSQRTF_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +float rsqrtf(float x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_RSQRTF_H diff --git a/libc/src/sys/mman/linux/mmap.cpp b/libc/src/sys/mman/linux/mmap.cpp index 33f9fe8..76a6611 100644 --- a/libc/src/sys/mman/linux/mmap.cpp +++ b/libc/src/sys/mman/linux/mmap.cpp @@ -56,7 +56,7 @@ LLVM_LIBC_FUNCTION(void *, mmap, // However, since a valid return address cannot be within the last page, a // return value corresponding to a location in the last page is an error // value. - if (ret < 0 && ret > -EXEC_PAGESIZE) { + if (!linux_utils::is_valid_mmap(ret)) { libc_errno = static_cast<int>(-ret); return MAP_FAILED; } diff --git a/libc/startup/linux/aarch64/tls.cpp b/libc/startup/linux/aarch64/tls.cpp index ea1b50c..7847797 100644 --- a/libc/startup/linux/aarch64/tls.cpp +++ b/libc/startup/linux/aarch64/tls.cpp @@ -62,7 +62,7 @@ void init_tls(TLSDescriptor &tls_descriptor) { MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // We cannot check the return value with MAP_FAILED as that is the return // of the mmap function and not the mmap syscall. - if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.page_size) + if (!linux_utils::is_valid_mmap(mmap_ret_val)) syscall_impl<long>(SYS_exit, 1); uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val)); uintptr_t tls_addr = thread_ptr + size_of_pointers + padding; diff --git a/libc/startup/linux/riscv/tls.cpp b/libc/startup/linux/riscv/tls.cpp index 04d44e6..e9d23c5 100644 --- a/libc/startup/linux/riscv/tls.cpp +++ b/libc/startup/linux/riscv/tls.cpp @@ -50,7 +50,7 @@ void init_tls(TLSDescriptor &tls_descriptor) { MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // We cannot check the return value with MAP_FAILED as that is the return // of the mmap function and not the mmap syscall. - if (mmap_ret_val < 0 && static_cast<uintptr_t>(mmap_ret_val) > -app.page_size) + if (!linux_utils::is_valid_mmap(mmap_ret_val)) syscall_impl<long>(SYS_exit, 1); uintptr_t thread_ptr = uintptr_t(reinterpret_cast<uintptr_t *>(mmap_ret_val)); uintptr_t tls_addr = thread_ptr + size_of_pointers + padding; diff --git a/libc/startup/linux/x86_64/tls.cpp b/libc/startup/linux/x86_64/tls.cpp index d6b549a..497f744 100644 --- a/libc/startup/linux/x86_64/tls.cpp +++ b/libc/startup/linux/x86_64/tls.cpp @@ -53,7 +53,7 @@ void init_tls(TLSDescriptor &tls_descriptor) { MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); // We cannot check the return value with MAP_FAILED as that is the return // of the mmap function and not the mmap syscall. - if (mmap_retval < 0 && static_cast<uintptr_t>(mmap_retval) > -app.page_size) + if (!linux_utils::is_valid_mmap(mmap_retval)) syscall_impl<long>(SYS_exit, 1); uintptr_t *tls_addr = reinterpret_cast<uintptr_t *>(mmap_retval); diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index dbc3889c..f341d3f 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -53,6 +53,6 @@ add_fp_unittest( libc.src.__support.math.ldexpf libc.src.__support.math.ldexpf128 libc.src.__support.math.ldexpf16 + libc.src.__support.math.rsqrtf libc.src.__support.math.rsqrtf16 - ) diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp index d118d96..477b7ec 100644 --- a/libc/test/shared/shared_math_test.cpp +++ b/libc/test/shared/shared_math_test.cpp @@ -70,6 +70,8 @@ TEST(LlvmLibcSharedMathTest, AllFloat) { ASSERT_FP_EQ(float(8 << 5), LIBC_NAMESPACE::shared::ldexpf(8.0f, 5)); ASSERT_FP_EQ(float(-1 * (8 << 5)), LIBC_NAMESPACE::shared::ldexpf(-8.0f, 5)); + + EXPECT_FP_EQ(0x1p+0f, LIBC_NAMESPACE::shared::rsqrtf(1.0f)); } TEST(LlvmLibcSharedMathTest, AllDouble) { diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 2d2d528..b3f54ab 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -1679,6 +1679,17 @@ add_fp_unittest( ) add_fp_unittest( + rsqrtf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + rsqrtf_test.cpp + DEPENDS + libc.src.math.rsqrtf +) + +add_fp_unittest( rsqrtf16_test NEED_MPFR SUITE diff --git a/libc/test/src/math/RsqrtTest.h b/libc/test/src/math/RsqrtTest.h new file mode 100644 index 0000000..d11d708 --- /dev/null +++ b/libc/test/src/math/RsqrtTest.h @@ -0,0 +1,74 @@ +//===-- Utility class to test rsqrt[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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_TEST_SRC_MATH_RSQRTTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_RSQRTTEST_H + +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template <typename OutType, typename InType = OutType> +class RsqrtTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(InType) + + static constexpr StorageType HIDDEN_BIT = + StorageType(1) << LIBC_NAMESPACE::fputil::FPBits<InType>::FRACTION_LEN; + +public: + using RsqrtFunc = OutType (*)(InType); + + // Subnormal inputs: probe both power-of-two mantissas and an even sampling + // across the subnormal range. + void test_denormal_values(RsqrtFunc func) { + // Powers of two in the subnormal mantissa space. + for (StorageType mant = 1; mant < HIDDEN_BIT; mant <<= 1) { + FPBits denormal(zero); + denormal.set_mantissa(mant); + InType x = denormal.get_val(); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Rsqrt, x, func(x), 0.5); + } + + // Even sampling across all subnormals. + constexpr StorageType COUNT = 200'001; + constexpr StorageType STEP = HIDDEN_BIT / COUNT; + for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + InType x = FPBits(i).get_val(); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Rsqrt, x, func(x), 0.5); + } + } + + // Positive normal range sampling: skip NaNs and negative values. + void test_normal_range(RsqrtFunc func) { + constexpr StorageType COUNT = 200'001; + constexpr StorageType STEP = STORAGE_MAX / COUNT; + for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + FPBits x_bits(v); + InType x = x_bits.get_val(); + if (x_bits.is_nan() || x_bits.is_neg()) + continue; + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Rsqrt, x, func(x), 0.5); + } + } +}; + +#define LIST_RSQRT_TESTS(T, func) \ + using LlvmLibcRsqrtTest = RsqrtTest<T, T>; \ + TEST_F(LlvmLibcRsqrtTest, DenormalValues) { test_denormal_values(&func); } \ + TEST_F(LlvmLibcRsqrtTest, NormalRange) { test_normal_range(&func); } + +#define LIST_NARROWING_RSQRT_TESTS(OutType, InType, func) \ + using LlvmLibcRsqrtTest = RsqrtTest<OutType, InType>; \ + TEST_F(LlvmLibcRsqrtTest, DenormalValues) { test_denormal_values(&func); } \ + TEST_F(LlvmLibcRsqrtTest, NormalRange) { test_normal_range(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_RSQRTTEST_H diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt index 07c36f424..1583ab6 100644 --- a/libc/test/src/math/exhaustive/CMakeLists.txt +++ b/libc/test/src/math/exhaustive/CMakeLists.txt @@ -27,6 +27,21 @@ add_fp_unittest( ) add_fp_unittest( + rsqrtf_test + NO_RUN_POSTBUILD + NEED_MPFR + SUITE + libc_math_exhaustive_tests + SRCS + rsqrtf_test.cpp + DEPENDS + .exhaustive_test + libc.src.math.rsqrtf + LINK_LIBRARIES + -lpthread +) + +add_fp_unittest( sinf_test NO_RUN_POSTBUILD NEED_MPFR diff --git a/libc/test/src/math/exhaustive/rsqrtf_test.cpp b/libc/test/src/math/exhaustive/rsqrtf_test.cpp new file mode 100644 index 0000000..803c9b4 --- /dev/null +++ b/libc/test/src/math/exhaustive/rsqrtf_test.cpp @@ -0,0 +1,27 @@ +//===-- Exhaustive test for rsqrtf ----------------------------------------===// +// +// 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 "exhaustive_test.h" +#include "src/math/rsqrtf.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcRsqrtfTest = LIBC_NAMESPACE::testing::FPTest<float>; + +using LlvmLibcRsqrtfExhaustiveTest = + LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Rsqrt, + LIBC_NAMESPACE::rsqrtf>; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// Range: [0, Inf] +static constexpr uint32_t POS_START = 0x0000'0000U; +static constexpr uint32_t POS_STOP = 0x7f80'0000U; + +TEST_F(LlvmLibcRsqrtfExhaustiveTest, PositiveRange) { + test_full_range_all_roundings(POS_START, POS_STOP); +} diff --git a/libc/test/src/math/rsqrtf_test.cpp b/libc/test/src/math/rsqrtf_test.cpp new file mode 100644 index 0000000..4e476c0 --- /dev/null +++ b/libc/test/src/math/rsqrtf_test.cpp @@ -0,0 +1,12 @@ +//===-- Unittests for rsqrtf ----------------------------------------------===// +// 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 "RsqrtTest.h" + +#include "src/math/rsqrtf.h" + +LIST_RSQRT_TESTS(float, LIBC_NAMESPACE::rsqrtf) diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 42a97ba..5afd3a9 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3503,14 +3503,27 @@ add_fp_unittest( ) add_fp_unittest( + rsqrtf_test + SUITE + libc-math-smoke-tests + SRCS + rsqrtf_test.cpp + DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.math.rsqrtf +) + +add_fp_unittest( rsqrtf16_test SUITE libc-math-smoke-tests SRCS rsqrtf16_test.cpp DEPENDS + libc.hdr.errno_macros + libc.hdr.fenv_macros libc.src.math.rsqrtf16 - libc.hdr.errno_macros ) add_fp_unittest( diff --git a/libc/test/src/math/smoke/rsqrtf16_test.cpp b/libc/test/src/math/smoke/rsqrtf16_test.cpp index e103e73..13d9a33 100644 --- a/libc/test/src/math/smoke/rsqrtf16_test.cpp +++ b/libc/test/src/math/smoke/rsqrtf16_test.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" #include "src/__support/FPUtil/cast.h" #include "src/__support/macros/properties/architectures.h" #include "src/math/rsqrtf16.h" diff --git a/libc/test/src/math/smoke/rsqrtf_test.cpp b/libc/test/src/math/smoke/rsqrtf_test.cpp new file mode 100644 index 0000000..d71b82c --- /dev/null +++ b/libc/test/src/math/smoke/rsqrtf_test.cpp @@ -0,0 +1,41 @@ +//===-- Unittests for rsqrtf --------------------------------------------===// +// +// 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 "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/math/rsqrtf.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +using LlvmLibcRsqrtfTest = LIBC_NAMESPACE::testing::FPTest<float>; + +TEST_F(LlvmLibcRsqrtfTest, SpecialNumbers) { + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::rsqrtf(aNaN)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::rsqrtf(sNaN), FE_INVALID); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(inf, LIBC_NAMESPACE::rsqrtf(zero)); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ(neg_inf, LIBC_NAMESPACE::rsqrtf(neg_zero)); + EXPECT_MATH_ERRNO(ERANGE); + + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::rsqrtf(1.0f)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(zero, LIBC_NAMESPACE::rsqrtf(inf)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::rsqrtf(neg_inf)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::rsqrtf(-2.0f)); + EXPECT_MATH_ERRNO(EDOM); +} |