Skip to content

Commit 12a1e6d

Browse files
authored
[libc][math][c23] Add f16{add,sub}f C23 math functions (#96787)
Part of #93566.
1 parent 5b77ed4 commit 12a1e6d

24 files changed

+934
-1
lines changed

libc/config/linux/aarch64/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,13 @@ if(LIBC_TYPES_HAS_FLOAT16)
508508
libc.src.math.canonicalizef16
509509
libc.src.math.ceilf16
510510
libc.src.math.copysignf16
511+
libc.src.math.f16addf
511512
libc.src.math.f16div
512513
libc.src.math.f16divf
513514
libc.src.math.f16fmaf
514515
libc.src.math.f16sqrt
515516
libc.src.math.f16sqrtf
517+
libc.src.math.f16subf
516518
libc.src.math.fabsf16
517519
libc.src.math.fdimf16
518520
libc.src.math.floorf16

libc/config/linux/x86_64/entrypoints.txt

+2
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
538538
libc.src.math.canonicalizef16
539539
libc.src.math.ceilf16
540540
libc.src.math.copysignf16
541+
libc.src.math.f16addf
541542
libc.src.math.f16div
542543
libc.src.math.f16divf
543544
libc.src.math.f16divl
@@ -547,6 +548,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
547548
libc.src.math.f16sqrt
548549
libc.src.math.f16sqrtf
549550
libc.src.math.f16sqrtl
551+
libc.src.math.f16subf
550552
libc.src.math.fabsf16
551553
libc.src.math.fdimf16
552554
libc.src.math.floorf16

libc/docs/math/index.rst

+4
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,14 @@ Basic Operations
124124
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
125125
| dsub | N/A | N/A | | N/A | | 7.12.14.2 | F.10.11 |
126126
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
127+
| f16add | |check|\* | | | N/A | | 7.12.14.1 | F.10.11 |
128+
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
127129
| f16div | |check|\* | |check|\* | |check|\* | N/A | |check| | 7.12.14.4 | F.10.11 |
128130
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
129131
| f16fma | |check| | |check| | |check| | N/A | |check| | 7.12.14.5 | F.10.11 |
130132
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
133+
| f16sub | |check|\* | | | N/A | | 7.12.14.2 | F.10.11 |
134+
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
131135
| fabs | |check| | |check| | |check| | |check| | |check| | 7.12.7.3 | F.10.4.3 |
132136
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
133137
| fadd | N/A | | | N/A | | 7.12.14.1 | F.10.11 |

libc/spec/llvm_libc_ext.td

+4
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def LLVMLibcExt : StandardSpec<"llvm_libc_ext"> {
5757
[], // Types
5858
[], // Enumerations
5959
[
60+
GuardedFunctionSpec<"f16addf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
61+
62+
GuardedFunctionSpec<"f16subf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
63+
6064
GuardedFunctionSpec<"f16div", RetValSpec<Float16Type>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>], "LIBC_TYPES_HAS_FLOAT16">,
6165
GuardedFunctionSpec<"f16divf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
6266
GuardedFunctionSpec<"f16divl", RetValSpec<Float16Type>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>], "LIBC_TYPES_HAS_FLOAT16">,

libc/src/__support/FPUtil/generic/CMakeLists.txt

+19
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,25 @@ add_header_library(
4949
libc.src.__support.macros.optimization
5050
)
5151

52+
add_header_library(
53+
add_sub
54+
HDRS
55+
add_sub.h
56+
DEPENDS
57+
libc.hdr.errno_macros
58+
libc.hdr.fenv_macros
59+
libc.src.__support.CPP.algorithm
60+
libc.src.__support.CPP.bit
61+
libc.src.__support.CPP.type_traits
62+
libc.src.__support.FPUtil.basic_operations
63+
libc.src.__support.FPUtil.fenv_impl
64+
libc.src.__support.FPUtil.fp_bits
65+
libc.src.__support.FPUtil.dyadic_float
66+
libc.src.__support.FPUtil.rounding_mode
67+
libc.src.__support.macros.attributes
68+
libc.src.__support.macros.optimization
69+
)
70+
5271
add_header_library(
5372
div
5473
HDRS
+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
//===-- Add and subtract IEEE 754 floating-point numbers --------*- 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___SUPPORT_FPUTIL_GENERIC_ADD_SUB_H
10+
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_SUB_H
11+
12+
#include "hdr/errno_macros.h"
13+
#include "hdr/fenv_macros.h"
14+
#include "src/__support/CPP/algorithm.h"
15+
#include "src/__support/CPP/bit.h"
16+
#include "src/__support/CPP/type_traits.h"
17+
#include "src/__support/FPUtil/BasicOperations.h"
18+
#include "src/__support/FPUtil/FEnvImpl.h"
19+
#include "src/__support/FPUtil/FPBits.h"
20+
#include "src/__support/FPUtil/dyadic_float.h"
21+
#include "src/__support/FPUtil/rounding_mode.h"
22+
#include "src/__support/macros/attributes.h"
23+
#include "src/__support/macros/optimization.h"
24+
25+
namespace LIBC_NAMESPACE::fputil::generic {
26+
27+
template <bool IsSub, typename OutType, typename InType>
28+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
29+
cpp::is_floating_point_v<InType> &&
30+
sizeof(OutType) <= sizeof(InType),
31+
OutType>
32+
add_or_sub(InType x, InType y) {
33+
using OutFPBits = FPBits<OutType>;
34+
using OutStorageType = typename OutFPBits::StorageType;
35+
using InFPBits = FPBits<InType>;
36+
using InStorageType = typename InFPBits::StorageType;
37+
38+
constexpr int GUARD_BITS_LEN = 3;
39+
constexpr int RESULT_FRACTION_LEN = InFPBits::FRACTION_LEN + GUARD_BITS_LEN;
40+
constexpr int RESULT_MANTISSA_LEN = RESULT_FRACTION_LEN + 1;
41+
42+
using DyadicFloat =
43+
DyadicFloat<cpp::bit_ceil(static_cast<size_t>(RESULT_MANTISSA_LEN))>;
44+
45+
InFPBits x_bits(x);
46+
InFPBits y_bits(y);
47+
48+
bool is_effectively_add = (x_bits.sign() == y_bits.sign()) != IsSub;
49+
50+
if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() ||
51+
x_bits.is_zero() || y_bits.is_zero())) {
52+
if (x_bits.is_nan() || y_bits.is_nan()) {
53+
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
54+
raise_except_if_required(FE_INVALID);
55+
56+
if (x_bits.is_quiet_nan()) {
57+
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
58+
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
59+
return OutFPBits::quiet_nan(x_bits.sign(),
60+
static_cast<OutStorageType>(x_payload))
61+
.get_val();
62+
}
63+
64+
if (y_bits.is_quiet_nan()) {
65+
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
66+
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
67+
return OutFPBits::quiet_nan(y_bits.sign(),
68+
static_cast<OutStorageType>(y_payload))
69+
.get_val();
70+
}
71+
72+
return OutFPBits::quiet_nan().get_val();
73+
}
74+
75+
if (x_bits.is_inf()) {
76+
if (y_bits.is_inf()) {
77+
if (!is_effectively_add) {
78+
raise_except_if_required(FE_INVALID);
79+
return OutFPBits::quiet_nan().get_val();
80+
}
81+
82+
return OutFPBits::inf(x_bits.sign()).get_val();
83+
}
84+
85+
return OutFPBits::inf(x_bits.sign()).get_val();
86+
}
87+
88+
if (y_bits.is_inf())
89+
return OutFPBits::inf(y_bits.sign()).get_val();
90+
91+
if (x_bits.is_zero()) {
92+
if (y_bits.is_zero()) {
93+
switch (quick_get_round()) {
94+
case FE_DOWNWARD:
95+
return OutFPBits::zero(Sign::NEG).get_val();
96+
default:
97+
return OutFPBits::zero(Sign::POS).get_val();
98+
}
99+
}
100+
101+
// volatile prevents Clang from converting tmp to OutType and then
102+
// immediately back to InType before negating it, resulting in double
103+
// rounding.
104+
volatile InType tmp = y;
105+
if constexpr (IsSub)
106+
tmp = -tmp;
107+
return static_cast<OutType>(tmp);
108+
}
109+
110+
if (y_bits.is_zero()) {
111+
volatile InType tmp = y;
112+
if constexpr (IsSub)
113+
tmp = -tmp;
114+
return static_cast<OutType>(tmp);
115+
}
116+
}
117+
118+
InType x_abs = x_bits.abs().get_val();
119+
InType y_abs = y_bits.abs().get_val();
120+
121+
if (x_abs == y_abs && !is_effectively_add) {
122+
switch (quick_get_round()) {
123+
case FE_DOWNWARD:
124+
return OutFPBits::zero(Sign::NEG).get_val();
125+
default:
126+
return OutFPBits::zero(Sign::POS).get_val();
127+
}
128+
}
129+
130+
Sign result_sign = Sign::POS;
131+
132+
if (x_abs > y_abs) {
133+
result_sign = x_bits.sign();
134+
} else if (x_abs < y_abs) {
135+
if (is_effectively_add)
136+
result_sign = y_bits.sign();
137+
else if (y_bits.is_pos())
138+
result_sign = Sign::NEG;
139+
} else if (is_effectively_add) {
140+
result_sign = x_bits.sign();
141+
}
142+
143+
InFPBits max_bits(cpp::max(x_abs, y_abs));
144+
InFPBits min_bits(cpp::min(x_abs, y_abs));
145+
146+
InStorageType result_mant;
147+
148+
if (max_bits.is_subnormal()) {
149+
// min_bits must be subnormal too.
150+
151+
if (is_effectively_add)
152+
result_mant = max_bits.get_mantissa() + min_bits.get_mantissa();
153+
else
154+
result_mant = max_bits.get_mantissa() - min_bits.get_mantissa();
155+
156+
result_mant <<= GUARD_BITS_LEN;
157+
} else {
158+
InStorageType max_mant = max_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
159+
InStorageType min_mant = min_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
160+
int alignment =
161+
max_bits.get_biased_exponent() - min_bits.get_biased_exponent();
162+
163+
InStorageType aligned_min_mant =
164+
min_mant >> cpp::min(alignment, RESULT_MANTISSA_LEN);
165+
bool aligned_min_mant_sticky;
166+
167+
if (alignment <= 3)
168+
aligned_min_mant_sticky = false;
169+
else if (alignment <= InFPBits::FRACTION_LEN + 3)
170+
aligned_min_mant_sticky =
171+
(min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
172+
else
173+
aligned_min_mant_sticky = true;
174+
175+
if (is_effectively_add)
176+
result_mant = max_mant + (aligned_min_mant | aligned_min_mant_sticky);
177+
else
178+
result_mant = max_mant - (aligned_min_mant | aligned_min_mant_sticky);
179+
}
180+
181+
int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;
182+
DyadicFloat result(result_sign, result_exp, result_mant);
183+
return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
184+
}
185+
186+
template <typename OutType, typename InType>
187+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
188+
cpp::is_floating_point_v<InType> &&
189+
sizeof(OutType) <= sizeof(InType),
190+
OutType>
191+
add(InType x, InType y) {
192+
return add_or_sub</*IsSub=*/false, OutType>(x, y);
193+
}
194+
195+
template <typename OutType, typename InType>
196+
LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<OutType> &&
197+
cpp::is_floating_point_v<InType> &&
198+
sizeof(OutType) <= sizeof(InType),
199+
OutType>
200+
sub(InType x, InType y) {
201+
return add_or_sub</*IsSub=*/true, OutType>(x, y);
202+
}
203+
204+
} // namespace LIBC_NAMESPACE::fputil::generic
205+
206+
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_SUB_H

libc/src/math/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ add_math_entrypoint_object(exp10f)
9999
add_math_entrypoint_object(expm1)
100100
add_math_entrypoint_object(expm1f)
101101

102+
add_math_entrypoint_object(f16addf)
103+
102104
add_math_entrypoint_object(f16div)
103105
add_math_entrypoint_object(f16divf)
104106
add_math_entrypoint_object(f16divl)
@@ -114,6 +116,8 @@ add_math_entrypoint_object(f16sqrtf)
114116
add_math_entrypoint_object(f16sqrtl)
115117
add_math_entrypoint_object(f16sqrtf128)
116118

119+
add_math_entrypoint_object(f16subf)
120+
117121
add_math_entrypoint_object(fabs)
118122
add_math_entrypoint_object(fabsf)
119123
add_math_entrypoint_object(fabsl)

libc/src/math/f16addf.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for f16addf -----------------------*- 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_F16ADDF_H
10+
#define LLVM_LIBC_SRC_MATH_F16ADDF_H
11+
12+
#include "src/__support/macros/properties/types.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
float16 f16addf(float x, float y);
17+
18+
} // namespace LIBC_NAMESPACE
19+
20+
#endif // LLVM_LIBC_SRC_MATH_F16ADDF_H

libc/src/math/f16subf.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- Implementation header for f16subf -----------------------*- 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_F16SUBF_H
10+
#define LLVM_LIBC_SRC_MATH_F16SUBF_H
11+
12+
#include "src/__support/macros/properties/types.h"
13+
14+
namespace LIBC_NAMESPACE {
15+
16+
float16 f16subf(float x, float y);
17+
18+
} // namespace LIBC_NAMESPACE
19+
20+
#endif // LLVM_LIBC_SRC_MATH_F16SUBF_H

libc/src/math/generic/CMakeLists.txt

+26
Original file line numberDiff line numberDiff line change
@@ -3795,6 +3795,32 @@ add_entrypoint_object(
37953795
-O3
37963796
)
37973797

3798+
add_entrypoint_object(
3799+
f16addf
3800+
SRCS
3801+
f16addf.cpp
3802+
HDRS
3803+
../f16addf.h
3804+
DEPENDS
3805+
libc.src.__support.macros.properties.types
3806+
libc.src.__support.FPUtil.generic.add_sub
3807+
COMPILE_OPTIONS
3808+
-O3
3809+
)
3810+
3811+
add_entrypoint_object(
3812+
f16subf
3813+
SRCS
3814+
f16subf.cpp
3815+
HDRS
3816+
../f16subf.h
3817+
DEPENDS
3818+
libc.src.__support.macros.properties.types
3819+
libc.src.__support.FPUtil.generic.add_sub
3820+
COMPILE_OPTIONS
3821+
-O3
3822+
)
3823+
37983824
add_entrypoint_object(
37993825
f16div
38003826
SRCS

0 commit comments

Comments
 (0)