mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-10-07 10:54:01 +00:00
[libc][math] Implement acoshf function correctly rounded to all rounding modes.
Implement acoshf function correctly rounded to all rounding modes. Reviewed By: zimmermann6 Differential Revision: https://reviews.llvm.org/D142781
This commit is contained in:
parent
47fbb247da
commit
9b30f6b6d7
@ -110,6 +110,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||
|
||||
# math.h entrypoints
|
||||
libc.src.math.acosf
|
||||
libc.src.math.acoshf
|
||||
libc.src.math.asinf
|
||||
libc.src.math.asinhf
|
||||
libc.src.math.atanf
|
||||
|
@ -210,6 +210,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||
|
||||
# math.h entrypoints
|
||||
libc.src.math.acosf
|
||||
libc.src.math.acoshf
|
||||
libc.src.math.asin
|
||||
libc.src.math.asinf
|
||||
libc.src.math.asinhf
|
||||
|
@ -211,6 +211,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||
|
||||
# math.h entrypoints
|
||||
libc.src.math.acosf
|
||||
libc.src.math.acoshf
|
||||
libc.src.math.asin
|
||||
libc.src.math.asinf
|
||||
libc.src.math.asinhf
|
||||
|
@ -111,6 +111,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||
|
||||
# math.h entrypoints
|
||||
libc.src.math.acosf
|
||||
libc.src.math.acoshf
|
||||
libc.src.math.asin
|
||||
libc.src.math.asinf
|
||||
libc.src.math.asinhf
|
||||
|
@ -122,7 +122,7 @@ Higher Math Functions
|
||||
<Func> <Func_f> (float) <Func> (double) <Func_l> (long double)
|
||||
============== ================ =============== ======================
|
||||
acos :green:`XA`
|
||||
acosh
|
||||
acosh :green:`XA`
|
||||
asin :green:`XA`
|
||||
asinh :green:`XA`
|
||||
atan :green:`XA`
|
||||
@ -161,6 +161,7 @@ Accuracy of Higher Math Functions
|
||||
<Func> <Func_f> (float) <Func> (double) <Func_l> (long double)
|
||||
============== ================ =============== ======================
|
||||
acos :green:`XA`
|
||||
acosh :green:`XA`
|
||||
asin :green:`XA`
|
||||
asinh :green:`XA`
|
||||
atan :green:`XA`
|
||||
@ -216,6 +217,8 @@ Performance
|
||||
+==============+===========+===================+===========+===================+=====================================+============+=========================+==============+===============+
|
||||
| acosf | 24 | 29 | 62 | 77 | :math:`[-1, 1]` | Ryzen 1700 | Ubuntu 22.04 LTS x86_64 | Clang 14.0.0 | FMA |
|
||||
+--------------+-----------+-------------------+-----------+-------------------+-------------------------------------+------------+-------------------------+--------------+---------------+
|
||||
| acoshf | 18 | 26 | 73 | 74 | :math:`[1, 21]` | Ryzen 1700 | Ubuntu 22.04 LTS x86_64 | Clang 14.0.0 | FMA |
|
||||
+--------------+-----------+-------------------+-----------+-------------------+-------------------------------------+------------+-------------------------+--------------+---------------+
|
||||
| asinf | 23 | 27 | 62 | 62 | :math:`[-1, 1]` | Ryzen 1700 | Ubuntu 22.04 LTS x86_64 | Clang 14.0.0 | FMA |
|
||||
+--------------+-----------+-------------------+-----------+-------------------+-------------------------------------+------------+-------------------------+--------------+---------------+
|
||||
| asinhf | 21 | 39 | 77 | 91 | :math:`[-10, 10]` | Ryzen 1700 | Ubuntu 22.04 LTS x86_64 | Clang 14.0.0 | FMA |
|
||||
|
@ -492,6 +492,7 @@ def StdC : StandardSpec<"stdc"> {
|
||||
FunctionSpec<"asin", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"atanf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
|
||||
FunctionSpec<"acoshf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"asinhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
]
|
||||
|
@ -65,6 +65,7 @@ add_entrypoint_object(
|
||||
)
|
||||
|
||||
add_math_entrypoint_object(acosf)
|
||||
add_math_entrypoint_object(acoshf)
|
||||
|
||||
add_math_entrypoint_object(asin)
|
||||
add_math_entrypoint_object(asinf)
|
||||
|
18
libc/src/math/acoshf.h
Normal file
18
libc/src/math/acoshf.h
Normal file
@ -0,0 +1,18 @@
|
||||
//===-- Implementation header for acoshf ------------------------*- 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_ACOSHF_H
|
||||
#define LLVM_LIBC_SRC_MATH_ACOSHF_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
float acoshf(float x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_ACOSHF_H
|
@ -1296,6 +1296,23 @@ add_entrypoint_object(
|
||||
-O3
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
acoshf
|
||||
SRCS
|
||||
acoshf.cpp
|
||||
HDRS
|
||||
../acoshf.h
|
||||
DEPENDS
|
||||
.explogxf
|
||||
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
|
||||
COMPILE_OPTIONS
|
||||
-O3
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
asinhf
|
||||
SRCS
|
||||
|
72
libc/src/math/generic/acoshf.cpp
Normal file
72
libc/src/math/generic/acoshf.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
//===-- Single-precision acosh 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/acoshf.h"
|
||||
#include "src/__support/FPUtil/FEnvImpl.h"
|
||||
#include "src/__support/FPUtil/FPBits.h"
|
||||
#include "src/__support/FPUtil/PolyEval.h"
|
||||
#include "src/__support/FPUtil/multiply_add.h"
|
||||
#include "src/__support/FPUtil/sqrt.h"
|
||||
#include "src/math/generic/common_constants.h"
|
||||
#include "src/math/generic/explogxf.h"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
LLVM_LIBC_FUNCTION(float, acoshf, (float x)) {
|
||||
using FPBits_t = typename fputil::FPBits<float>;
|
||||
FPBits_t xbits(x);
|
||||
uint32_t x_u = xbits.uintval();
|
||||
|
||||
if (unlikely(x < 1.0f)) {
|
||||
// x < 1.
|
||||
fputil::set_except(FE_INVALID);
|
||||
return FPBits_t::build_quiet_nan(0);
|
||||
}
|
||||
|
||||
if (unlikely(x_u >= 0x4f8ffb03)) {
|
||||
// Check for exceptional values.
|
||||
uint32_t x_abs = x_u & FPBits_t::FloatProp::EXP_MANT_MASK;
|
||||
if (unlikely(x_abs >= 0x7f80'0000U)) {
|
||||
// x is +inf or NaN.
|
||||
return x;
|
||||
}
|
||||
|
||||
// Helper functions to set results for exceptional cases.
|
||||
auto round_result_slightly_down = [](float r) -> float {
|
||||
volatile float tmp = r;
|
||||
tmp = tmp - 0x1.0p-25f;
|
||||
return tmp;
|
||||
};
|
||||
auto round_result_slightly_up = [](float r) -> float {
|
||||
volatile float tmp = r;
|
||||
tmp = tmp + 0x1.0p-25f;
|
||||
return tmp;
|
||||
};
|
||||
|
||||
switch (x_u) {
|
||||
case 0x4f8ffb03: // x = 0x1.1ff606p32f
|
||||
return round_result_slightly_up(0x1.6fdd34p4f);
|
||||
case 0x5c569e88: // x = 0x1.ad3d1p57f
|
||||
return round_result_slightly_up(0x1.45c146p5f);
|
||||
case 0x5e68984e: // x = 0x1.d1309cp61f
|
||||
return round_result_slightly_up(0x1.5c9442p5f);
|
||||
case 0x655890d3: // x = 0x1.b121a6p75f
|
||||
return round_result_slightly_down(0x1.a9a3f2p5f);
|
||||
case 0x6eb1a8ec: // x = 0x1.6351d8p94f
|
||||
return round_result_slightly_down(0x1.08b512p6f);
|
||||
case 0x7997f30a: // x = 0x1.2fe614p116f
|
||||
return round_result_slightly_up(0x1.451436p6f);
|
||||
}
|
||||
}
|
||||
|
||||
double x_d = static_cast<double>(x);
|
||||
// acosh(x) = log(x + sqrt(x^2 - 1))
|
||||
return log_eval(x_d + fputil::sqrt(fputil::multiply_add(x_d, x_d, -1.0)));
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
@ -1485,6 +1485,20 @@ add_fp_unittest(
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
acoshf_test
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
acoshf_test.cpp
|
||||
DEPENDS
|
||||
libc.include.errno
|
||||
libc.src.errno.errno
|
||||
libc.src.math.acoshf
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
asinf_test
|
||||
NEED_MPFR
|
||||
|
78
libc/test/src/math/acoshf_test.cpp
Normal file
78
libc/test/src/math/acoshf_test.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
//===-- Unittests for acoshf ----------------------------------------------===//
|
||||
//
|
||||
// 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/math/acoshf.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
#include "utils/UnitTest/FPMatcher.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
using FPBits_t = __llvm_libc::fputil::FPBits<float>;
|
||||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
DECLARE_SPECIAL_CONSTANTS(float)
|
||||
|
||||
TEST(LlvmLibcAcoshfTest, SpecialNumbers) {
|
||||
errno = 0;
|
||||
|
||||
EXPECT_FP_EQ(aNaN, __llvm_libc::acoshf(aNaN));
|
||||
EXPECT_MATH_ERRNO(0);
|
||||
|
||||
EXPECT_FP_EQ(aNaN, __llvm_libc::acoshf(0.0f));
|
||||
EXPECT_MATH_ERRNO(0);
|
||||
|
||||
EXPECT_FP_EQ(0.0f, __llvm_libc::acoshf(1.0f));
|
||||
EXPECT_MATH_ERRNO(0);
|
||||
|
||||
EXPECT_FP_EQ(inf, __llvm_libc::acoshf(inf));
|
||||
EXPECT_MATH_ERRNO(0);
|
||||
|
||||
EXPECT_FP_EQ(aNaN, __llvm_libc::acoshf(neg_inf));
|
||||
EXPECT_MATH_ERRNO(0);
|
||||
}
|
||||
|
||||
TEST(LlvmLibcAcoshfTest, InFloatRange) {
|
||||
constexpr uint32_t COUNT = 1000000;
|
||||
constexpr uint32_t STEP = UINT32_MAX / COUNT;
|
||||
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
||||
float x = float(FPBits_t(v));
|
||||
if (isnan(x) || isinf(x))
|
||||
continue;
|
||||
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acosh, x,
|
||||
__llvm_libc::acoshf(x), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LlvmLibcAcoshfTest, SpecificBitPatterns) {
|
||||
constexpr int N = 12;
|
||||
constexpr uint32_t INPUTS[N] = {
|
||||
0x3f800000, // x = 1.0f
|
||||
0x45abaf26, // x = 0x1.575e4cp12f
|
||||
0x49d29048, // x = 0x1.a5209p20f
|
||||
0x4bdd65a5, // x = 0x1.bacb4ap24f
|
||||
0x4c803f2c, // x = 0x1.007e58p26f
|
||||
0x4f8ffb03, // x = 0x1.1ff606p32f
|
||||
0x5c569e88, // x = 0x1.ad3d1p57f
|
||||
0x5e68984e, // x = 0x1.d1309cp61f
|
||||
0x655890d3, // x = 0x1.b121a6p75f
|
||||
0x65de7ca6, // x = 0x1.bcf94cp76f
|
||||
0x6eb1a8ec, // x = 0x1.6351d8p94f
|
||||
0x7997f30a, // x = 0x1.2fe614p116f
|
||||
};
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
float x = float(FPBits_t(INPUTS[i]));
|
||||
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acosh, x,
|
||||
__llvm_libc::acoshf(x), 0.5);
|
||||
}
|
||||
}
|
@ -308,6 +308,23 @@ add_fp_unittest(
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
acoshf_test
|
||||
NO_RUN_POSTBUILD
|
||||
NEED_MPFR
|
||||
SUITE
|
||||
libc_math_exhaustive_tests
|
||||
SRCS
|
||||
acoshf_test.cpp
|
||||
DEPENDS
|
||||
.exhaustive_test
|
||||
libc.include.math
|
||||
libc.src.math.acoshf
|
||||
libc.src.__support.FPUtil.fp_bits
|
||||
LINK_LIBRARIES
|
||||
-lpthread
|
||||
)
|
||||
|
||||
add_fp_unittest(
|
||||
asinhf_test
|
||||
NO_RUN_POSTBUILD
|
||||
|
56
libc/test/src/math/exhaustive/acoshf_test.cpp
Normal file
56
libc/test/src/math/exhaustive/acoshf_test.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
//===-- Exhaustive test for acoshf ----------------------------------------===//
|
||||
//
|
||||
// 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/__support/FPUtil/FPBits.h"
|
||||
#include "src/math/acoshf.h"
|
||||
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<float>;
|
||||
|
||||
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||
|
||||
struct LlvmLibcAcoshfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
|
||||
bool check(uint32_t start, uint32_t stop,
|
||||
mpfr::RoundingMode rounding) override {
|
||||
mpfr::ForceRoundingMode r(rounding);
|
||||
uint32_t bits = start;
|
||||
bool result = true;
|
||||
do {
|
||||
FPBits xbits(bits);
|
||||
float x = float(xbits);
|
||||
result &= EXPECT_MPFR_MATCH(mpfr::Operation::Acosh, x,
|
||||
__llvm_libc::acoshf(x), 0.5, rounding);
|
||||
} while (bits++ < stop);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
static const int NUM_THREADS = std::thread::hardware_concurrency();
|
||||
|
||||
// Range: [1, Inf];
|
||||
static const uint32_t POS_START = 0x3f80'0000U;
|
||||
static const uint32_t POS_STOP = 0x7f80'0000U;
|
||||
|
||||
TEST_F(LlvmLibcAcoshfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
|
||||
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcAcoshfExhaustiveTest, PostiveRangeRoundUp) {
|
||||
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcAcoshfExhaustiveTest, PostiveRangeRoundDown) {
|
||||
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
|
||||
}
|
||||
|
||||
TEST_F(LlvmLibcAcoshfExhaustiveTest, PostiveRangeRoundTowardZero) {
|
||||
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
|
||||
}
|
@ -190,6 +190,12 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
MPFRNumber acosh() const {
|
||||
MPFRNumber result(*this);
|
||||
mpfr_acosh(result.value, value, mpfr_rounding);
|
||||
return result;
|
||||
}
|
||||
|
||||
MPFRNumber asin() const {
|
||||
MPFRNumber result(*this);
|
||||
mpfr_asin(result.value, value, mpfr_rounding);
|
||||
@ -201,6 +207,7 @@ public:
|
||||
mpfr_asinh(result.value, value, mpfr_rounding);
|
||||
return result;
|
||||
}
|
||||
|
||||
MPFRNumber atan() const {
|
||||
MPFRNumber result(*this);
|
||||
mpfr_atan(result.value, value, mpfr_rounding);
|
||||
@ -545,6 +552,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
|
||||
return mpfrInput.abs();
|
||||
case Operation::Acos:
|
||||
return mpfrInput.acos();
|
||||
case Operation::Acosh:
|
||||
return mpfrInput.acosh();
|
||||
case Operation::Asin:
|
||||
return mpfrInput.asin();
|
||||
case Operation::Asinh:
|
||||
|
@ -26,6 +26,7 @@ enum class Operation : int {
|
||||
BeginUnaryOperationsSingleOutput,
|
||||
Abs,
|
||||
Acos,
|
||||
Acosh,
|
||||
Asin,
|
||||
Asinh,
|
||||
Atan,
|
||||
|
Loading…
Reference in New Issue
Block a user