-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc][math][c23] Add atanhf16 C23 math function. #132612
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libc Author: Harrison Hao (harrisonGPU) ChangesImplementation of atanhf16 function for 16-bit inputs. Full diff: https://github.com/llvm/llvm-project/pull/132612.diff 11 Files Affected:
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index ac281e8d39066..f92f6f234bfdc 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -655,6 +655,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.asinf16
libc.src.math.acosf16
libc.src.math.acoshf16
+ libc.src.math.atanhf16
libc.src.math.canonicalizef16
libc.src.math.ceilf16
libc.src.math.copysignf16
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index 16903a40c03fa..82a552a6568bf 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -267,7 +267,7 @@ Higher Math Functions
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| atan2pi | | | | | | 7.12.4.11 | F.10.1.11 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| atanh | |check| | | | | | 7.12.5.3 | F.10.2.3 |
+| atanh | |check| | | | |check| | | 7.12.5.3 | F.10.2.3 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| atanpi | | | | | | 7.12.4.10 | F.10.1.10 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index bd29eb0213c4f..627aae9de5942 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -98,6 +98,13 @@ functions:
return_type: float
arguments:
- type: float
+ - name: atanhf16
+ standards:
+ - stdc
+ return_type: _Float16
+ arguments:
+ - type: _Float16
+ guard: LIBC_TYPES_HAS_FLOAT16
- name: canonicalize
standards:
- stdc
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index 92c80a1053c9e..72d2e16622d1a 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -64,6 +64,7 @@ add_math_entrypoint_object(atan2l)
add_math_entrypoint_object(atanh)
add_math_entrypoint_object(atanhf)
+add_math_entrypoint_object(atanhf16)
add_math_entrypoint_object(canonicalize)
add_math_entrypoint_object(canonicalizef)
diff --git a/libc/src/math/atanhf16.h b/libc/src/math/atanhf16.h
new file mode 100644
index 0000000000000..9fbb262c16514
--- /dev/null
+++ b/libc/src/math/atanhf16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for atanhf16 ----------------------*- 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_ATANHF16_H
+#define LLVM_LIBC_SRC_MATH_ATANHF16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 atanhf16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_ATANHF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 77c6244c5e5da..9f3abc0cb1530 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -3955,12 +3955,9 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.FPUtil.cast
- libc.src.__support.FPUtil.except_value_utils
- 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.sqrt
libc.src.__support.macros.optimization
libc.src.__support.macros.properties.types
)
@@ -3992,6 +3989,18 @@ add_entrypoint_object(
libc.src.__support.macros.optimization
)
+add_entrypoint_object(
+ atanhf16
+ SRCS
+ atanhf16.cpp
+ HDRS
+ ../atanhf16.h
+ DEPENDS
+ .explogxf
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.macros.optimization
+)
+
add_object_library(
inv_trigf_utils
HDRS
diff --git a/libc/src/math/generic/atanhf16.cpp b/libc/src/math/generic/atanhf16.cpp
new file mode 100644
index 0000000000000..94d6aa149cf00
--- /dev/null
+++ b/libc/src/math/generic/atanhf16.cpp
@@ -0,0 +1,86 @@
+//===-- Implementation of atanh(x) 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/atanhf16.h"
+#include "explogxf.h"
+#include "hdr/errno_macros.h"
+#include "hdr/fenv_macros.h"
+#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/PolyEval.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/multiply_add.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(float16, atanhf16, (float16 x)) {
+ using FPBits = typename fputil::FPBits<float16>;
+
+ FPBits xbits(x);
+ Sign sign = xbits.sign();
+ uint16_t x_abs = xbits.abs().uintval();
+
+ if (LIBC_UNLIKELY(x_abs >= 0x3c00U)) {
+ if (xbits.is_nan()) {
+ return x;
+ }
+ // |x| == 1.0
+ if (x_abs == 0x3c00U) {
+ fputil::set_errno_if_required(ERANGE);
+ fputil::raise_except_if_required(FE_DIVBYZERO);
+ return FPBits::inf(sign).get_val();
+ } else {
+ fputil::set_errno_if_required(EDOM);
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ }
+
+ // For |x| less than approximately 0.10
+ if (LIBC_UNLIKELY(x_abs <= 0x2e66U)) {
+ // The Taylor expansion of atanh(x) is:
+ // atanh(x) = x + x^3/3 + x^5/5 + x^7/7 + x^9/9 + x^11/11
+ // = x * [1 + x^2/3 + x^4/5 + x^6/7 + x^8/9 + x^10/11]
+ // When |x| < 0x0100U, this can be approximated by:
+ // atanh(x) ≈ x + (1/3)*x^3
+ if (LIBC_UNLIKELY(x_abs < 0x0100U)) {
+ return static_cast<float16>(
+ LIBC_UNLIKELY(x_abs == 0) ? x : (x + 0x1.555556p-2 * x * x * x));
+ }
+
+ // For 0x0100U <= |x| <= 0x2e66U:
+ // Let t = x^2.
+ // Define P(t) ≈ (1/3)*t + (1/5)*t^2 + (1/7)*t^3 + (1/9)*t^4 + (1/11)*t^5.
+ // The coefficients below were derived using Sollya:
+ // > display = hexadecimal;
+ // > round(1/3, SG, RN);
+ // > round(1/5, SG, RN);
+ // > round(1/7, SG, RN);
+ // > round(1/9, SG, RN);
+ // > round(1/11, SG, RN);
+ // This yields:
+ // 0x1.555556p-2
+ // 0x1.99999ap-3
+ // 0x1.24924ap-3
+ // 0x1.c71c72p-4
+ // 0x1.745d18p-4f
+ // Thus, atanh(x) ≈ x * (1 + P(x^2)).
+ float xf = x;
+ float x2 = xf * xf;
+ float pe = fputil::polyeval(x2, 0.0f, 0x1.555556p-2f, 0x1.99999ap-3f,
+ 0x1.24924ap-3f, 0x1.c71c72p-4f, 0x1.745d18p-4f);
+ return static_cast<float16>(fputil::multiply_add(xf, pe, xf));
+ }
+
+ float xf = x;
+ return static_cast<float16>(0.5 * log_eval((xf + 1.0) / (xf - 1.0)));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 6ca4163f07949..371fb0e25a6cf 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2132,6 +2132,17 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ atanhf16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ atanhf16_test.cpp
+ DEPENDS
+ libc.src.math.atanhf16
+)
+
add_fp_unittest(
fmul_test
NEED_MPFR
diff --git a/libc/test/src/math/atanhf16_test.cpp b/libc/test/src/math/atanhf16_test.cpp
new file mode 100644
index 0000000000000..ce0179a1962df
--- /dev/null
+++ b/libc/test/src/math/atanhf16_test.cpp
@@ -0,0 +1,39 @@
+//===-- Unittests for atanhf16 --------------------------------------------===//
+//
+// 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/errno/libc_errno.h"
+#include "src/math/atanhf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
+#include <stdint.h>
+
+using LlvmLibcAtanhf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x3BFFU;
+static constexpr uint16_t NEG_START = 0xBBFFU;
+static constexpr uint16_t NEG_STOP = 0x8000U;
+
+TEST_F(LlvmLibcAtanhf16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atanh, x,
+ LIBC_NAMESPACE::atanhf16(x), 0.5);
+ }
+}
+
+TEST_F(LlvmLibcAtanhf16Test, NegativeRange) {
+ for (uint16_t v = NEG_START; v <= NEG_STOP; --v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atanh, x,
+ LIBC_NAMESPACE::atanhf16(x), 0.5);
+ }
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 660b68687d63c..aae8140f93c5b 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3934,6 +3934,18 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)
+add_fp_unittest(
+ atanhf16_test
+ SUITE
+ libc-math-smoke-tests
+ SRCS
+ atanhf16_test.cpp
+ DEPENDS
+ libc.src.errno.errno
+ libc.src.math.atanhf16
+ libc.src.__support.FPUtil.fp_bits
+)
+
add_fp_unittest(
asinhf_test
SUITE
diff --git a/libc/test/src/math/smoke/atanhf16_test.cpp b/libc/test/src/math/smoke/atanhf16_test.cpp
new file mode 100644
index 0000000000000..1ac483d2ae758
--- /dev/null
+++ b/libc/test/src/math/smoke/atanhf16_test.cpp
@@ -0,0 +1,58 @@
+//===-- Unittests for atanhf16 --------------------------------------------===//
+//
+// 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/cast.h"
+#include "src/errno/libc_errno.h"
+#include "src/math/atanhf16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcAtanhf16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcAtanhf16Test, SpecialNumbers) {
+ LIBC_NAMESPACE::libc_errno = 0;
+ EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf16(aNaN));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::atanhf16(zero));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_ALL_ROUNDING(
+ -0.0f,
+ LIBC_NAMESPACE::atanhf16(LIBC_NAMESPACE::fputil::cast<float16>(-0.0f)));
+ EXPECT_MATH_ERRNO(0);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(
+ inf,
+ LIBC_NAMESPACE::atanhf16(LIBC_NAMESPACE::fputil::cast<float16>(1.0f)),
+ FE_DIVBYZERO);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_EQ_WITH_EXCEPTION(
+ neg_inf,
+ LIBC_NAMESPACE::atanhf16(LIBC_NAMESPACE::fputil::cast<float16>(-1.0f)),
+ FE_DIVBYZERO);
+ EXPECT_MATH_ERRNO(ERANGE);
+
+ EXPECT_FP_IS_NAN_WITH_EXCEPTION(
+ LIBC_NAMESPACE::atanhf16(LIBC_NAMESPACE::fputil::cast<float16>(2.0f)),
+ FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+
+ EXPECT_FP_IS_NAN_WITH_EXCEPTION(
+ LIBC_NAMESPACE::atanhf16(LIBC_NAMESPACE::fputil::cast<float16>(-2.0f)),
+ FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+
+ EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf16(inf), FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+
+ EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf16(neg_inf),
+ FE_INVALID);
+ EXPECT_MATH_ERRNO(EDOM);
+}
|
e56b926
to
049b363
Compare
Hi @jhuber6 @overmighty @lntue Could you please review this PR, if you have time. :-) |
libc/test/src/math/atanhf16_test.cpp
Outdated
|
||
// Range for positive numbers: [0, 1) | ||
static constexpr uint16_t POS_START = 0x0000U; | ||
static constexpr uint16_t POS_STOP = 0x3C00; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think our MPFR testing now can take care of inf/nan cases. So you should be able to test for the entire range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I have updated it. :-)
libc/src/math/generic/atanhf16.cpp
Outdated
// The coefficients below were derived using Sollya: | ||
// > display = hexadecimal; | ||
// > round(1/3, SG, RN); | ||
// > round(1/5, SG, RN); | ||
// > round(1/7, SG, RN); | ||
// > round(1/9, SG, RN); | ||
// > round(1/11, SG, RN); | ||
// This yields: | ||
// 0x1.555556p-2 | ||
// 0x1.99999ap-3 | ||
// 0x1.24924ap-3 | ||
// 0x1.c71c72p-4 | ||
// 0x1.745d18p-4f |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too verbose in my opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have updated it, what do you think about it? @overmighty
libc/src/math/generic/atanhf16.cpp
Outdated
} | ||
|
||
float xf = x; | ||
return static_cast<float16>(0.5 * log_eval((xf + 1.0) / (xf - 1.0))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return static_cast<float16>(0.5 * log_eval((xf + 1.0) / (xf - 1.0))); | |
return fputil::cast<float16>(0.5 * log_eval((xf + 1.0) / (xf - 1.0))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also use float literals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I have updated it.
bea54fc
to
c07ca89
Compare
c07ca89
to
a7f41b0
Compare
Implementation of atanhf16 function for 16-bit inputs.
Closes: #132209