Skip to content
Merged
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,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
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,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
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/headers/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+
Expand Down
6 changes: 6 additions & 0 deletions libc/include/math.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion libc/shared/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,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
23 changes: 23 additions & 0 deletions libc/shared/math/rsqrtf.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion libc/shared/math/rsqrtf16.h
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
44 changes: 28 additions & 16 deletions libc/src/__support/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -775,6 +759,34 @@ add_header_library(
libc.src.__support.common
)

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
Expand Down
71 changes: 71 additions & 0 deletions libc/src/__support/math/rsqrtf.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions libc/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,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)
Expand Down
10 changes: 10 additions & 0 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,16 @@ add_entrypoint_object(
ROUND_OPT
)

add_entrypoint_object(
rsqrtf
SRCS
rsqrtf.cpp
HDRS
../rsqrtf.h
DEPENDS
libc.src.__support.math.rsqrtf
)

add_entrypoint_object(
rsqrtf16
SRCS
Expand Down
16 changes: 16 additions & 0 deletions libc/src/math/generic/rsqrtf.cpp
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions libc/src/math/rsqrtf.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion libc/test/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,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

)
2 changes: 2 additions & 0 deletions libc/test/shared/shared_math_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,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) {
Expand Down
11 changes: 11 additions & 0 deletions libc/test/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,17 @@ add_fp_unittest(
libc.src.math.sqrtl
)

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
Expand Down
74 changes: 74 additions & 0 deletions libc/test/src/math/RsqrtTest.h
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading