-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[libc][math][c23] Add asinf16() function #124212
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
Changes from 6 commits
9c6454f
d8fa4dd
c6002ff
299a753
dc173e3
96ab636
5a5136c
cdf231a
e3653bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| //===-- Implementation header for asinf16 -----------------------*- 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_ASINF16_H | ||
| #define LLVM_LIBC_SRC_MATH_ASINF16_H | ||
|
|
||
| #include "src/__support/macros/config.h" | ||
| #include "src/__support/macros/properties/types.h" | ||
|
|
||
| namespace LIBC_NAMESPACE_DECL { | ||
|
|
||
| float16 asinf16(float16 x); | ||
|
|
||
| } // namespace LIBC_NAMESPACE_DECL | ||
|
|
||
| #endif // LLVM_LIBC_SRC_MATH_ASINF16_H |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,135 @@ | ||||||||||||||||||||||||||||||||||||||
| //===-- Half-precision asinf16(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/asinf16.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/PolyEval.h" | ||||||||||||||||||||||||||||||||||||||
| #include "src/__support/FPUtil/cast.h" | ||||||||||||||||||||||||||||||||||||||
| #include "src/__support/FPUtil/multiply_add.h" | ||||||||||||||||||||||||||||||||||||||
| #include "src/__support/FPUtil/sqrt.h" | ||||||||||||||||||||||||||||||||||||||
| #include "src/__support/macros/optimization.h" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| namespace LIBC_NAMESPACE_DECL { | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Generated by Sollya using the following command: | ||||||||||||||||||||||||||||||||||||||
| // > round(pi/2, D, RN); | ||||||||||||||||||||||||||||||||||||||
| static constexpr float PI_2 = 0x1.921fb54442d18p0f; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| LLVM_LIBC_FUNCTION(float16, asinf16, (float16 x)) { | ||||||||||||||||||||||||||||||||||||||
| using FPBits = fputil::FPBits<float16>; | ||||||||||||||||||||||||||||||||||||||
| FPBits xbits(x); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| uint16_t x_u = xbits.uintval(); | ||||||||||||||||||||||||||||||||||||||
| uint16_t x_abs = x_u & 0x7fff; | ||||||||||||||||||||||||||||||||||||||
| float xf = x; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| float xsq = xf * xf; | ||||||||||||||||||||||||||||||||||||||
overmighty marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // |x| <= 0x1p-1, |x| <= 0.5 | ||||||||||||||||||||||||||||||||||||||
| if (x_abs <= 0x3800) { | ||||||||||||||||||||||||||||||||||||||
| // asinf16(NaN) = NaN | ||||||||||||||||||||||||||||||||||||||
| if (xbits.is_nan()) { | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| float xsq = xf * xf; | |
| // |x| <= 0x1p-1, |x| <= 0.5 | |
| if (x_abs <= 0x3800) { | |
| // asinf16(NaN) = NaN | |
| if (xbits.is_nan()) { | |
| // |x| <= 0x1p-1, |x| <= 0.5, or x is NaN. | |
| if (LIBC_UNLIKELY(x_abs <= 0x3800 || x_abs > 0x7c00)) { | |
| // asinf16(NaN) = NaN | |
| if (xbits.is_nan()) { | |
| // ... | |
| } | |
| // ... | |
| } | |
| // ... | |
| float xsq = xf * xf; |
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.
What about directly checking xbits.is_nan(), like so?
...
float xf = x;
if (xbits.is_nan()) {
if (xbits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
return x;
}
float xsq = xf * xf;
...
I mean, that'd be equivalent to checking if x_abs > 0x7c00, right?
Also, why include the x_abs <= 0x3800 in the NaN condition? If it falls within the domain of the function, it couldn't be NaN, right?
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.
What about directly checking
xbits.is_nan(), like so?
It might generate more instructions than x_abs > 0x7c00, although I haven't verified it in this case, and I haven't benchmarked it.
Also, why include the
x_abs <= 0x3800in the NaN condition? If it falls within the domain of the function, it couldn't be NaN, right?
The point is to group all unlikely cases under a single if (LIBC_UNLIKELY(...)) statement so that the compiler generates better code for the likely case: https://godbolt.org/z/bjzM5fv1z.
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.
It might generate more instructions than x_abs > 0x7c00, although I haven't verified it in this case, and I haven't benchmarked it.
How can I quickly verify the instructions generated?
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.
llvm-objdump -Cdr path/to/*.o
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.
// |x| > 0x1p0, |x| > 1, or x is NaN.
if (LIBC_UNLIKELY(x_abs > 0x3c00)) {
// asinf16(NaN) = NaN
if (xbits.is_nan()) {
if (xbits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}
return x;
}
// 1 < |x| <= +/-inf
fputil::raise_except_if_required(FE_INVALID);
fputil::set_errno_if_required(EDOM);
return FPBits::quiet_nan().get_val();
}
It might generate more instructions than x_abs > 0x7c00, although I haven't verified it in this case, and I haven't benchmarked it
xbits.is_nan() and x_abs > 0x7c00 generate the same instructions. Also, what do you think of having the final check for inf values in the same conditional scope as the check for NaN-ness like above?
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, what do you think of having the final check for
infvalues in the same conditional scope as the check for NaN-ness like above?
It's what I would do. I would even move the x_abs <= 0x3800 case under the same if (LIBC_UNLIKELY(...)) statement, but I guess it's fine either way.
overmighty marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
overmighty marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| //===-- Exhaustive test for asinf16 ---------------------------------------===// | ||
| // | ||
| // 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/asinf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
| #include "utils/MPFRWrapper/MPFRUtils.h" | ||
|
|
||
| using LlvmLibcAsinf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| namespace mpfr = LIBC_NAMESPACE::testing::mpfr; | ||
|
|
||
| // Range: [0, Inf] | ||
| static constexpr uint16_t POS_START = 0x0000U; | ||
| static constexpr uint16_t POS_STOP = 0x7c00U; | ||
|
|
||
| // Range: [-Inf, 0] | ||
| static constexpr uint16_t NEG_START = 0x8000U; | ||
| static constexpr uint16_t NEG_STOP = 0xfc00U; | ||
|
|
||
| TEST_F(LlvmLibcAsinf16Test, PositiveRange) { | ||
| for (uint16_t v = POS_START; v <= POS_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
|
|
||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asin, x, | ||
| LIBC_NAMESPACE::asinf16(x), 0.5); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(LlvmLibcAsinf16Test, NegativeRange) { | ||
| for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { | ||
| float16 x = FPBits(v).get_val(); | ||
|
|
||
| EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asin, x, | ||
| LIBC_NAMESPACE::asinf16(x), 0.5); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| //===-- Unittests for asinf16 ---------------------------------------------===// | ||
| // | ||
| // | ||
| // 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/errno/libc_errno.h" | ||
| #include "src/math/asinf16.h" | ||
| #include "test/UnitTest/FPMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using LlvmLibcAsinf16Test = LIBC_NAMESPACE::testing::FPTest<float16>; | ||
|
|
||
| TEST_F(LlvmLibcAsinf16Test, SpecialNumbers) { | ||
| LIBC_NAMESPACE::libc_errno = 0; | ||
| EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(aNaN)); | ||
| EXPECT_MATH_ERRNO(0); | ||
overmighty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| EXPECT_FP_EQ(zero, LIBC_NAMESPACE::asinf16(zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::asinf16(neg_zero)); | ||
| EXPECT_MATH_ERRNO(0); | ||
|
|
||
| EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(inf)); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
|
|
||
| EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(neg_inf)); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
|
|
||
| EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(2.0f)); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
|
|
||
| EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::asinf16(-2.0f)); | ||
| EXPECT_MATH_ERRNO(EDOM); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.