Skip to content

Commit 1cb8645

Browse files
authored
[libc][math] Refactor tanf16 to header only (llvm#181523)
Part of llvm#147386
1 parent 8d2eb4e commit 1cb8645

9 files changed

Lines changed: 208 additions & 123 deletions

File tree

libc/shared/math.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#include "math/sqrtf16.h"
135135
#include "math/tan.h"
136136
#include "math/tanf.h"
137+
#include "math/tanf16.h"
137138
#include "math/tanhf.h"
138139
#include "math/tanhf16.h"
139140

libc/shared/math/tanf16.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===-- Shared tanf16 function ----------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SHARED_MATH_TANF16_H
10+
#define LLVM_LIBC_SHARED_MATH_TANF16_H
11+
12+
#include "include/llvm-libc-macros/float16-macros.h"
13+
14+
#ifdef LIBC_TYPES_HAS_FLOAT16
15+
16+
#include "shared/libc_common.h"
17+
#include "src/__support/math/tanf16.h"
18+
19+
namespace LIBC_NAMESPACE_DECL {
20+
namespace shared {
21+
22+
using math::tanf16;
23+
24+
} // namespace shared
25+
} // namespace LIBC_NAMESPACE_DECL
26+
27+
#endif // LIBC_TYPES_HAS_FLOAT16
28+
29+
#endif // LLVM_LIBC_SHARED_MATH_TANF16_H

libc/src/__support/math/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1888,6 +1888,23 @@ add_header_library(
18881888
libc.src.__support.macros.optimization
18891889
)
18901890

1891+
add_header_library(
1892+
tanf16
1893+
HDRS
1894+
tanf16.h
1895+
DEPENDS
1896+
.sincosf16_utils
1897+
libc.hdr.errno_macros
1898+
libc.hdr.fenv_macros
1899+
libc.src.__support.FPUtil.cast
1900+
libc.src.__support.FPUtil.fenv_impl
1901+
libc.src.__support.FPUtil.fp_bits
1902+
libc.src.__support.FPUtil.except_value_utils
1903+
libc.src.__support.FPUtil.multiply_add
1904+
libc.src.__support.macros.optimization
1905+
libc.include.llvm-libc-macros.float16_macros
1906+
)
1907+
18911908
add_header_library(
18921909
tanhf
18931910
HDRS

libc/src/__support/math/tanf16.h

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//===-- Single-precision tanf16 function ----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANF16_H
10+
#define LLVM_LIBC_SRC___SUPPORT_MATH_TANF16_H
11+
12+
#include "include/llvm-libc-macros/float16-macros.h"
13+
14+
#ifdef LIBC_TYPES_HAS_FLOAT16
15+
16+
#include "hdr/errno_macros.h"
17+
#include "hdr/fenv_macros.h"
18+
#include "sincosf16_utils.h"
19+
#include "src/__support/FPUtil/FEnvImpl.h"
20+
#include "src/__support/FPUtil/FPBits.h"
21+
#include "src/__support/FPUtil/cast.h"
22+
#include "src/__support/FPUtil/except_value_utils.h"
23+
#include "src/__support/FPUtil/multiply_add.h"
24+
#include "src/__support/macros/optimization.h"
25+
26+
namespace LIBC_NAMESPACE_DECL {
27+
28+
namespace math {
29+
30+
LIBC_INLINE float16 tanf16(float16 x) {
31+
using namespace sincosf16_internal;
32+
using FPBits = fputil::FPBits<float16>;
33+
FPBits xbits(x);
34+
35+
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
36+
constexpr size_t N_EXCEPTS = 9;
37+
constexpr fputil::ExceptValues<float16, N_EXCEPTS> TANF16_EXCEPTS{{
38+
// (input, RZ output, RU offset, RD offset, RN offset)
39+
{0x2894, 0x2894, 1, 0, 1},
40+
{0x3091, 0x3099, 1, 0, 0},
41+
{0x3098, 0x30a0, 1, 0, 0},
42+
{0x55ed, 0x3911, 1, 0, 0},
43+
{0x607b, 0xc638, 0, 1, 1},
44+
{0x674e, 0x3b7d, 1, 0, 0},
45+
{0x6807, 0x4014, 1, 0, 1},
46+
{0x6f4d, 0xbe19, 0, 1, 1},
47+
{0x7330, 0xcb62, 0, 1, 0},
48+
}};
49+
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
50+
51+
uint16_t x_u = xbits.uintval();
52+
uint16_t x_abs = x_u & 0x7fff;
53+
float xf = x;
54+
55+
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
56+
bool x_sign = x_u >> 15;
57+
// Handle exceptional values
58+
if (auto r = TANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
59+
LIBC_UNLIKELY(r.has_value()))
60+
return r.value();
61+
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
62+
63+
// |x| <= 0x1.d1p-5
64+
if (LIBC_UNLIKELY(x_abs <= 0x2b44)) {
65+
// |x| <= 0x1.398p-11
66+
if (LIBC_UNLIKELY(x_abs <= 0x10e6)) {
67+
// tan(+/-0) = +/-0
68+
if (LIBC_UNLIKELY(x_abs == 0))
69+
return x;
70+
71+
int rounding = fputil::quick_get_round();
72+
73+
// Exhaustive tests show that, when:
74+
// x > 0, and rounding upward or
75+
// x < 0, and rounding downward then,
76+
// tan(x) = x * 2^-11 + x
77+
if ((xbits.is_pos() && rounding == FE_UPWARD) ||
78+
(xbits.is_neg() && rounding == FE_DOWNWARD))
79+
return fputil::cast<float16>(fputil::multiply_add(xf, 0x1.0p-11f, xf));
80+
return x;
81+
}
82+
83+
float xsq = xf * xf;
84+
85+
// Degree-6 minimax odd polynomial of tan(x) generated by Sollya with:
86+
// > P = fpminimax(tan(x)/x, [|0, 2, 4, 6|], [|1, SG...|], [0, pi/32]);
87+
float result = fputil::polyeval(xsq, 0x1p0f, 0x1.555556p-2f, 0x1.110ee4p-3f,
88+
0x1.be80f6p-5f);
89+
90+
return fputil::cast<float16>(xf * result);
91+
}
92+
93+
// tan(+/-inf) = NaN, and tan(NaN) = NaN
94+
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
95+
if (xbits.is_signaling_nan()) {
96+
fputil::raise_except_if_required(FE_INVALID);
97+
return FPBits::quiet_nan().get_val();
98+
}
99+
// x = +/-inf
100+
if (x_abs == 0x7c00) {
101+
fputil::set_errno_if_required(EDOM);
102+
fputil::raise_except_if_required(FE_INVALID);
103+
}
104+
105+
return x + FPBits::quiet_nan().get_val();
106+
}
107+
108+
// Range reduction:
109+
// For |x| > pi/32, we perform range reduction as follows:
110+
// Find k and y such that:
111+
// x = (k + y) * pi/32;
112+
// k is an integer, |y| < 0.5
113+
//
114+
// This is done by performing:
115+
// k = round(x * 32/pi)
116+
// y = x * 32/pi - k
117+
//
118+
// Once k and y are computed, we then deduce the answer by the formula:
119+
// tan(x) = sin(x) / cos(x)
120+
// = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
121+
float sin_k, cos_k, sin_y, cosm1_y;
122+
sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
123+
124+
// Note that, cosm1_y = cos_y - 1:
125+
using fputil::multiply_add;
126+
return fputil::cast<float16>(
127+
multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) /
128+
multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k)));
129+
}
130+
131+
} // namespace math
132+
133+
} // namespace LIBC_NAMESPACE_DECL
134+
135+
#endif // LIBC_TYPES_HAS_FLOAT16
136+
137+
#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANF16_H

libc/src/math/generic/CMakeLists.txt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -453,16 +453,7 @@ add_entrypoint_object(
453453
HDRS
454454
../tanf16.h
455455
DEPENDS
456-
libc.hdr.errno_macros
457-
libc.hdr.fenv_macros
458-
libc.src.__support.FPUtil.cast
459-
libc.src.__support.FPUtil.fenv_impl
460-
libc.src.__support.FPUtil.fp_bits
461-
libc.src.__support.FPUtil.except_value_utils
462-
libc.src.__support.FPUtil.multiply_add
463-
libc.src.__support.macros.optimization
464-
libc.src.__support.macros.properties.types
465-
libc.src.__support.math.sincosf16_utils
456+
libc.src.__support.math.tanf16
466457
)
467458

468459
add_entrypoint_object(

libc/src/math/generic/tanf16.cpp

Lines changed: 2 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -7,118 +7,10 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "src/math/tanf16.h"
10-
#include "hdr/errno_macros.h"
11-
#include "hdr/fenv_macros.h"
12-
#include "src/__support/FPUtil/FEnvImpl.h"
13-
#include "src/__support/FPUtil/FPBits.h"
14-
#include "src/__support/FPUtil/cast.h"
15-
#include "src/__support/FPUtil/except_value_utils.h"
16-
#include "src/__support/FPUtil/multiply_add.h"
17-
#include "src/__support/macros/optimization.h"
18-
#include "src/__support/math/sincosf16_utils.h"
10+
#include "src/__support/math/tanf16.h"
1911

2012
namespace LIBC_NAMESPACE_DECL {
2113

22-
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
23-
constexpr size_t N_EXCEPTS = 9;
24-
25-
constexpr fputil::ExceptValues<float16, N_EXCEPTS> TANF16_EXCEPTS{{
26-
// (input, RZ output, RU offset, RD offset, RN offset)
27-
{0x2894, 0x2894, 1, 0, 1},
28-
{0x3091, 0x3099, 1, 0, 0},
29-
{0x3098, 0x30a0, 1, 0, 0},
30-
{0x55ed, 0x3911, 1, 0, 0},
31-
{0x607b, 0xc638, 0, 1, 1},
32-
{0x674e, 0x3b7d, 1, 0, 0},
33-
{0x6807, 0x4014, 1, 0, 1},
34-
{0x6f4d, 0xbe19, 0, 1, 1},
35-
{0x7330, 0xcb62, 0, 1, 0},
36-
}};
37-
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
38-
39-
LLVM_LIBC_FUNCTION(float16, tanf16, (float16 x)) {
40-
using namespace math::sincosf16_internal;
41-
using FPBits = fputil::FPBits<float16>;
42-
FPBits xbits(x);
43-
44-
uint16_t x_u = xbits.uintval();
45-
uint16_t x_abs = x_u & 0x7fff;
46-
float xf = x;
47-
48-
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
49-
bool x_sign = x_u >> 15;
50-
// Handle exceptional values
51-
if (auto r = TANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
52-
LIBC_UNLIKELY(r.has_value()))
53-
return r.value();
54-
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
55-
56-
// |x| <= 0x1.d1p-5
57-
if (LIBC_UNLIKELY(x_abs <= 0x2b44)) {
58-
// |x| <= 0x1.398p-11
59-
if (LIBC_UNLIKELY(x_abs <= 0x10e6)) {
60-
// tan(+/-0) = +/-0
61-
if (LIBC_UNLIKELY(x_abs == 0))
62-
return x;
63-
64-
int rounding = fputil::quick_get_round();
65-
66-
// Exhaustive tests show that, when:
67-
// x > 0, and rounding upward or
68-
// x < 0, and rounding downward then,
69-
// tan(x) = x * 2^-11 + x
70-
if ((xbits.is_pos() && rounding == FE_UPWARD) ||
71-
(xbits.is_neg() && rounding == FE_DOWNWARD))
72-
return fputil::cast<float16>(fputil::multiply_add(xf, 0x1.0p-11f, xf));
73-
return x;
74-
}
75-
76-
float xsq = xf * xf;
77-
78-
// Degree-6 minimax odd polynomial of tan(x) generated by Sollya with:
79-
// > P = fpminimax(tan(x)/x, [|0, 2, 4, 6|], [|1, SG...|], [0, pi/32]);
80-
float result = fputil::polyeval(xsq, 0x1p0f, 0x1.555556p-2f, 0x1.110ee4p-3f,
81-
0x1.be80f6p-5f);
82-
83-
return fputil::cast<float16>(xf * result);
84-
}
85-
86-
// tan(+/-inf) = NaN, and tan(NaN) = NaN
87-
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
88-
if (xbits.is_signaling_nan()) {
89-
fputil::raise_except_if_required(FE_INVALID);
90-
return FPBits::quiet_nan().get_val();
91-
}
92-
// x = +/-inf
93-
if (x_abs == 0x7c00) {
94-
fputil::set_errno_if_required(EDOM);
95-
fputil::raise_except_if_required(FE_INVALID);
96-
}
97-
98-
return x + FPBits::quiet_nan().get_val();
99-
}
100-
101-
// Range reduction:
102-
// For |x| > pi/32, we perform range reduction as follows:
103-
// Find k and y such that:
104-
// x = (k + y) * pi/32;
105-
// k is an integer, |y| < 0.5
106-
//
107-
// This is done by performing:
108-
// k = round(x * 32/pi)
109-
// y = x * 32/pi - k
110-
//
111-
// Once k and y are computed, we then deduce the answer by the formula:
112-
// tan(x) = sin(x) / cos(x)
113-
// = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
114-
float sin_k, cos_k, sin_y, cosm1_y;
115-
sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
116-
117-
// Note that, cosm1_y = cos_y - 1:
118-
using fputil::multiply_add;
119-
return fputil::cast<float16>(
120-
multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) /
121-
multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k)));
122-
}
14+
LLVM_LIBC_FUNCTION(float16, tanf16, (float16 x)) { return math::tanf16(x); }
12315

12416
} // namespace LIBC_NAMESPACE_DECL

libc/test/shared/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ add_fp_unittest(
131131
libc.src.__support.math.sqrtf
132132
libc.src.__support.math.tan
133133
libc.src.__support.math.tanf
134+
libc.src.__support.math.tanf16
134135
libc.src.__support.math.tanhf
135136
libc.src.__support.math.tanhf16
136137
)

libc/test/shared/shared_math_test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat16) {
7373
EXPECT_FP_EQ(0x1.921fb6p+0f16, LIBC_NAMESPACE::shared::acosf16(0.0f16));
7474
EXPECT_FP_EQ(0x1p+0f16, LIBC_NAMESPACE::shared::f16sqrtl(1.0L));
7575
EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::sinf16(0.0f16));
76+
EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::tanf16(0.0f16));
7677
EXPECT_FP_EQ(0x0p+0f16, LIBC_NAMESPACE::shared::sinpif16(0.0f16));
7778
EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::shared::tanhf16(0.0f16));
7879

utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4087,6 +4087,24 @@ libc_support_library(
40874087
],
40884088
)
40894089

4090+
libc_support_library(
4091+
name = "__support_math_tanf16",
4092+
hdrs = ["src/__support/math/tanf16.h"],
4093+
deps = [
4094+
":__support_fputil_cast",
4095+
":__support_fputil_except_value_utils",
4096+
":__support_fputil_fenv_impl",
4097+
":__support_fputil_fp_bits",
4098+
":__support_fputil_multiply_add",
4099+
":__support_macros_optimization",
4100+
":__support_macros_properties_types",
4101+
":__support_math_sincosf16_utils",
4102+
":hdr_errno_macros",
4103+
":hdr_fenv_macros",
4104+
":llvm_libc_macros_float16_macros",
4105+
],
4106+
)
4107+
40904108
libc_support_library(
40914109
name = "__support_math_tanhf",
40924110
hdrs = ["src/__support/math/tanhf.h"],
@@ -5651,9 +5669,7 @@ libc_math_function(
56515669
libc_math_function(
56525670
name = "tanf16",
56535671
additional_deps = [
5654-
":__support_fputil_nearest_integer",
5655-
":__support_fputil_polyeval",
5656-
":__support_math_sincosf16_utils",
5672+
":__support_math_tanf16",
56575673
],
56585674
)
56595675

0 commit comments

Comments
 (0)