Skip to content

Commit 8078665

Browse files
authored
[libc][math][c23] Add hypotf16 function (#131991)
Implement hypot for Float16 along with tests.
1 parent c7572ae commit 8078665

File tree

18 files changed

+321
-5
lines changed

18 files changed

+321
-5
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
706706
libc.src.math.fromfpf16
707707
libc.src.math.fromfpxf16
708708
libc.src.math.getpayloadf16
709+
libc.src.math.hypotf16
709710
libc.src.math.ilogbf16
710711
libc.src.math.iscanonicalf16
711712
libc.src.math.issignalingf16

libc/docs/headers/math/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ Higher Math Functions
305305
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
306306
| fsqrt | N/A | |check| | |check| | N/A | |check|\* | 7.12.14.6 | F.10.11 |
307307
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
308-
| hypot | |check| | |check| | | | | 7.12.7.4 | F.10.4.4 |
308+
| hypot | |check| | |check| | | |check| | | 7.12.7.4 | F.10.4.4 |
309309
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
310310
| lgamma | | | | | | 7.12.8.3 | F.10.5.3 |
311311
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+

libc/include/math.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,14 @@ functions:
13951395
arguments:
13961396
- type: float
13971397
- type: float
1398+
- name: hypotf16
1399+
standards:
1400+
- stdc
1401+
return_type: _Float16
1402+
arguments:
1403+
- type: _Float16
1404+
- type: _Float16
1405+
guard: LIBC_TYPES_HAS_FLOAT16
13981406
- name: ilogb
13991407
standards:
14001408
- stdc

libc/src/__support/FPUtil/Hypot.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ LIBC_INLINE T find_leading_one(T mant, int &shift_length) {
3030
if (mant > 0) {
3131
shift_length = (sizeof(mant) * 8) - 1 - cpp::countl_zero(mant);
3232
}
33-
return T(1) << shift_length;
33+
return static_cast<T>((T(1) << shift_length));
3434
}
3535

3636
} // namespace internal
@@ -207,8 +207,10 @@ LIBC_INLINE T hypot(T x, T y) {
207207

208208
for (StorageType current_bit = leading_one >> 1; current_bit;
209209
current_bit >>= 1) {
210-
r = (r << 1) + ((tail_bits & current_bit) ? 1 : 0);
211-
StorageType tmp = (y_new << 1) + current_bit; // 2*y_new(n - 1) + 2^(-n)
210+
r = static_cast<StorageType>((r << 1)) +
211+
((tail_bits & current_bit) ? 1 : 0);
212+
StorageType tmp = static_cast<StorageType>((y_new << 1)) +
213+
current_bit; // 2*y_new(n - 1) + 2^(-n)
212214
if (r >= tmp) {
213215
r -= tmp;
214216
y_new += current_bit;

libc/src/__support/FPUtil/cast.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
namespace LIBC_NAMESPACE::fputil {
2020

21+
// TODO: Add optimization for known good targets with fast
22+
// float to float16 conversion:
23+
// https://github.com/llvm/llvm-project/issues/133517
2124
template <typename OutType, typename InType>
2225
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
2326
cpp::is_floating_point_v<InType>,

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ add_math_entrypoint_object(getpayloadf128)
313313

314314
add_math_entrypoint_object(hypot)
315315
add_math_entrypoint_object(hypotf)
316+
add_math_entrypoint_object(hypotf16)
316317

317318
add_math_entrypoint_object(ilogb)
318319
add_math_entrypoint_object(ilogbf)

libc/src/math/generic/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3105,6 +3105,22 @@ add_entrypoint_object(
31053105
libc.src.__support.macros.optimization
31063106
)
31073107

3108+
add_entrypoint_object(
3109+
hypotf16
3110+
SRCS
3111+
hypotf16.cpp
3112+
HDRS
3113+
../hypotf16.h
3114+
DEPENDS
3115+
libc.src.__support.FPUtil.fenv_impl
3116+
libc.src.__support.FPUtil.fp_bits
3117+
libc.src.__support.FPUtil.cast
3118+
libc.src.__support.FPUtil.multiply_add
3119+
libc.src.__support.FPUtil.sqrt
3120+
libc.src.__support.macros.optimization
3121+
libc.src.__support.macros.properties.types
3122+
)
3123+
31083124
add_entrypoint_object(
31093125
fdim
31103126
SRCS

libc/src/math/generic/hypotf16.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//===-- Implementation of hypotf16 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+
#include "src/math/hypotf16.h"
10+
#include "src/__support/FPUtil/FEnvImpl.h"
11+
#include "src/__support/FPUtil/FPBits.h"
12+
#include "src/__support/FPUtil/cast.h"
13+
#include "src/__support/FPUtil/multiply_add.h"
14+
#include "src/__support/FPUtil/sqrt.h"
15+
#include "src/__support/common.h"
16+
#include "src/__support/macros/optimization.h"
17+
#include "src/__support/macros/properties/types.h"
18+
19+
namespace LIBC_NAMESPACE_DECL {
20+
21+
// For targets where conversion from float to float16 has to be
22+
// emulated, fputil::hypot<float16> is faster
23+
LLVM_LIBC_FUNCTION(float16, hypotf16, (float16 x, float16 y)) {
24+
using FloatBits = fputil::FPBits<float>;
25+
using FPBits = fputil::FPBits<float16>;
26+
27+
FPBits x_abs = FPBits(x).abs();
28+
FPBits y_abs = FPBits(y).abs();
29+
30+
bool x_abs_larger = x_abs.uintval() >= y_abs.uintval();
31+
32+
FPBits a_bits = x_abs_larger ? x_abs : y_abs;
33+
FPBits b_bits = x_abs_larger ? y_abs : x_abs;
34+
35+
uint16_t a_u = a_bits.uintval();
36+
uint16_t b_u = b_bits.uintval();
37+
38+
// Note: replacing `a_u >= FPBits::EXP_MASK` with `a_bits.is_inf_or_nan()`
39+
// generates extra exponent bit masking instructions on x86-64.
40+
if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) {
41+
// x or y is inf or nan
42+
if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) {
43+
fputil::raise_except_if_required(FE_INVALID);
44+
return FPBits::quiet_nan().get_val();
45+
}
46+
if (a_bits.is_inf() || b_bits.is_inf())
47+
return FPBits::inf().get_val();
48+
return a_bits.get_val();
49+
}
50+
51+
if (LIBC_UNLIKELY(a_u - b_u >=
52+
static_cast<uint16_t>((FPBits::FRACTION_LEN + 2)
53+
<< FPBits::FRACTION_LEN)))
54+
return x_abs.get_val() + y_abs.get_val();
55+
56+
float af = fputil::cast<float>(a_bits.get_val());
57+
float bf = fputil::cast<float>(b_bits.get_val());
58+
59+
// These squares are exact.
60+
float a_sq = af * af;
61+
float sum_sq = fputil::multiply_add(bf, bf, a_sq);
62+
63+
FloatBits result(fputil::sqrt<float>(sum_sq));
64+
uint32_t r_u = result.uintval();
65+
66+
// If any of the sticky bits of the result are non-zero, except the LSB, then
67+
// the rounded result is correct.
68+
if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0FFE) == 0)) {
69+
float r_d = result.get_val();
70+
71+
// Perform rounding correction.
72+
float sum_sq_lo = fputil::multiply_add(bf, bf, a_sq - sum_sq);
73+
float err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq);
74+
75+
if (err > 0) {
76+
r_u |= 1;
77+
} else if ((err < 0) && (r_u & 1) == 0) {
78+
r_u -= 1;
79+
} else if ((r_u & 0x0000'1FFF) == 0) {
80+
// The rounded result is exact.
81+
fputil::clear_except_if_required(FE_INEXACT);
82+
}
83+
return fputil::cast<float16>(FloatBits(r_u).get_val());
84+
}
85+
86+
return fputil::cast<float16>(result.get_val());
87+
}
88+
89+
} // namespace LIBC_NAMESPACE_DECL

libc/src/math/hypotf16.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for hypotf16 ----------------------*- 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_SRC_MATH_HYPOTF16_H
10+
#define LLVM_LIBC_SRC_MATH_HYPOTF16_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include "src/__support/macros/properties/types.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
float16 hypotf16(float16 x, float16 y);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_MATH_HYPOTF16_H

libc/test/src/math/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,17 @@ add_fp_unittest(
17011701
libc.src.__support.FPUtil.fp_bits
17021702
)
17031703

1704+
add_fp_unittest(
1705+
hypotf16_test
1706+
NEED_MPFR
1707+
SUITE
1708+
libc-math-unittests
1709+
SRCS
1710+
hypotf16_test.cpp
1711+
DEPENDS
1712+
libc.src.math.hypotf16
1713+
)
1714+
17041715
add_fp_unittest(
17051716
nextafter_test
17061717
SUITE

0 commit comments

Comments
 (0)