Skip to content

Commit 096f017

Browse files
committed
[libc][math][c23] Add f16addf C23 math function
1 parent 2a6e32e commit 096f017

File tree

18 files changed

+546
-1
lines changed

18 files changed

+546
-1
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
507507
libc.src.math.canonicalizef16
508508
libc.src.math.ceilf16
509509
libc.src.math.copysignf16
510+
libc.src.math.f16addf
510511
libc.src.math.f16div
511512
libc.src.math.f16divf
512513
libc.src.math.f16fmaf

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
537537
libc.src.math.canonicalizef16
538538
libc.src.math.ceilf16
539539
libc.src.math.copysignf16
540+
libc.src.math.f16addf
540541
libc.src.math.f16div
541542
libc.src.math.f16divf
542543
libc.src.math.f16divl

libc/docs/math/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ 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 |

libc/spec/stdc.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,8 @@ def StdC : StandardSpec<"stdc"> {
729729

730730
GuardedFunctionSpec<"setpayloadsigf16", RetValSpec<IntType>, [ArgSpec<Float16Ptr>, ArgSpec<Float16Type>], "LIBC_TYPES_HAS_FLOAT16">,
731731

732+
GuardedFunctionSpec<"f16addf", RetValSpec<Float16Type>, [ArgSpec<FloatType>, ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,
733+
732734
GuardedFunctionSpec<"f16divf128", RetValSpec<Float16Type>, [ArgSpec<Float128Type>, ArgSpec<Float128Type>], "LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128">,
733735

734736
GuardedFunctionSpec<"f16sqrtf", RetValSpec<Float16Type>, [ArgSpec<FloatType>], "LIBC_TYPES_HAS_FLOAT16">,

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ add_header_library(
4848
libc.src.__support.macros.optimization
4949
)
5050

51+
add_header_library(
52+
add
53+
HDRS
54+
add.h
55+
DEPENDS
56+
libc.hdr.errno_macros
57+
libc.hdr.fenv_macros
58+
libc.src.__support.CPP.algorithm
59+
libc.src.__support.CPP.bit
60+
libc.src.__support.CPP.type_traits
61+
libc.src.__support.FPUtil.basic_operations
62+
libc.src.__support.FPUtil.fenv_impl
63+
libc.src.__support.FPUtil.fp_bits
64+
libc.src.__support.FPUtil.dyadic_float
65+
libc.src.__support.FPUtil.rounding_mode
66+
libc.src.__support.macros.attributes
67+
libc.src.__support.macros.optimization
68+
)
69+
5170
add_header_library(
5271
div
5372
HDRS
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//===-- Addition of 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_H
10+
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_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 <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(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+
if (LIBC_UNLIKELY(x_bits.is_inf_or_nan() || y_bits.is_inf_or_nan() ||
49+
x_bits.is_zero() || y_bits.is_zero())) {
50+
if (x_bits.is_nan() || y_bits.is_nan()) {
51+
if (x_bits.is_signaling_nan() || y_bits.is_signaling_nan())
52+
raise_except_if_required(FE_INVALID);
53+
54+
if (x_bits.is_quiet_nan()) {
55+
InStorageType x_payload = static_cast<InStorageType>(getpayload(x));
56+
if ((x_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
57+
return OutFPBits::quiet_nan(x_bits.sign(),
58+
static_cast<OutStorageType>(x_payload))
59+
.get_val();
60+
}
61+
62+
if (y_bits.is_quiet_nan()) {
63+
InStorageType y_payload = static_cast<InStorageType>(getpayload(y));
64+
if ((y_payload & ~(OutFPBits::FRACTION_MASK >> 1)) == 0)
65+
return OutFPBits::quiet_nan(y_bits.sign(),
66+
static_cast<OutStorageType>(y_payload))
67+
.get_val();
68+
}
69+
70+
return OutFPBits::quiet_nan().get_val();
71+
}
72+
73+
if (x_bits.is_inf()) {
74+
if (y_bits.is_inf()) {
75+
if (x_bits.sign() != y_bits.sign()) {
76+
raise_except_if_required(FE_INVALID);
77+
return OutFPBits::quiet_nan().get_val();
78+
}
79+
80+
return OutFPBits::inf(x_bits.sign()).get_val();
81+
}
82+
83+
return OutFPBits::inf(x_bits.sign()).get_val();
84+
}
85+
86+
if (y_bits.is_inf())
87+
return OutFPBits::inf(y_bits.sign()).get_val();
88+
89+
if (x_bits.is_zero()) {
90+
if (y_bits.is_zero()) {
91+
switch (quick_get_round()) {
92+
case FE_DOWNWARD:
93+
return OutFPBits::zero(Sign::NEG).get_val();
94+
default:
95+
return OutFPBits::zero(Sign::POS).get_val();
96+
}
97+
}
98+
99+
return static_cast<OutType>(y);
100+
}
101+
102+
if (y_bits.is_zero())
103+
return static_cast<OutType>(x);
104+
}
105+
106+
InType x_abs = x_bits.abs().get_val();
107+
InType y_abs = y_bits.abs().get_val();
108+
109+
if (x_abs == y_abs && x_bits.sign() != y_bits.sign()) {
110+
switch (quick_get_round()) {
111+
case FE_DOWNWARD:
112+
return OutFPBits::zero(Sign::NEG).get_val();
113+
default:
114+
return OutFPBits::zero(Sign::POS).get_val();
115+
}
116+
}
117+
118+
Sign result_sign = Sign::POS;
119+
120+
if (x_abs > y_abs)
121+
result_sign = x_bits.sign();
122+
else if (x_abs < y_abs)
123+
result_sign = y_bits.sign();
124+
else if (x_bits.sign() == y_bits.sign())
125+
result_sign = x_bits.sign();
126+
127+
InFPBits max_bits(cpp::max(x_abs, y_abs));
128+
InFPBits min_bits(cpp::min(x_abs, y_abs));
129+
130+
InStorageType result_mant;
131+
132+
if (max_bits.is_subnormal()) {
133+
// min_bits must be subnormal too.
134+
if (max_bits.sign() == min_bits.sign())
135+
result_mant = max_bits.get_mantissa() + min_bits.get_mantissa();
136+
else
137+
result_mant = max_bits.get_mantissa() - min_bits.get_mantissa();
138+
139+
result_mant <<= GUARD_BITS_LEN;
140+
} else {
141+
InStorageType max_mant = max_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
142+
InStorageType min_mant = min_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
143+
int alignment =
144+
max_bits.get_biased_exponent() - min_bits.get_biased_exponent();
145+
146+
InStorageType aligned_min_mant =
147+
min_mant >> cpp::min(alignment, RESULT_MANTISSA_LEN);
148+
bool aligned_min_mant_sticky;
149+
150+
if (alignment <= 3)
151+
aligned_min_mant_sticky = false;
152+
else if (alignment <= InFPBits::FRACTION_LEN + 3)
153+
aligned_min_mant_sticky =
154+
(min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
155+
else
156+
aligned_min_mant_sticky = true;
157+
158+
if (max_bits.sign() == min_bits.sign())
159+
result_mant = max_mant + (aligned_min_mant | aligned_min_mant_sticky);
160+
else
161+
result_mant = max_mant - (aligned_min_mant | aligned_min_mant_sticky);
162+
}
163+
164+
int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;
165+
DyadicFloat result(result_sign, result_exp, result_mant);
166+
return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
167+
}
168+
169+
} // namespace LIBC_NAMESPACE::fputil::generic
170+
171+
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_H

libc/src/math/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
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)

libc/src/math/f16addf.h

Lines changed: 20 additions & 0 deletions
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/generic/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3776,6 +3776,19 @@ add_entrypoint_object(
37763776
-O3
37773777
)
37783778

3779+
add_entrypoint_object(
3780+
f16addf
3781+
SRCS
3782+
f16addf.cpp
3783+
HDRS
3784+
../f16addf.h
3785+
DEPENDS
3786+
libc.src.__support.macros.properties.types
3787+
libc.src.__support.FPUtil.generic.add
3788+
COMPILE_OPTIONS
3789+
-O3
3790+
)
3791+
37793792
add_entrypoint_object(
37803793
f16div
37813794
SRCS

libc/src/math/generic/f16addf.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===-- Implementation of f16addf 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/f16addf.h"
10+
#include "src/__support/FPUtil/generic/add.h"
11+
#include "src/__support/common.h"
12+
13+
namespace LIBC_NAMESPACE {
14+
15+
LLVM_LIBC_FUNCTION(float16, f16addf, (float x, float y)) {
16+
return fputil::generic::add<float16>(x, y);
17+
}
18+
19+
} // namespace LIBC_NAMESPACE

libc/test/src/math/AddTest.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===-- Utility class to test different flavors of float add ----*- 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_TEST_SRC_MATH_ADDTEST_H
10+
#define LLVM_LIBC_TEST_SRC_MATH_ADDTEST_H
11+
12+
#include "test/UnitTest/FEnvSafeTest.h"
13+
#include "test/UnitTest/FPMatcher.h"
14+
#include "test/UnitTest/Test.h"
15+
#include "utils/MPFRWrapper/MPFRUtils.h"
16+
17+
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
18+
19+
template <typename OutType, typename InType>
20+
class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
21+
22+
struct InConstants {
23+
DECLARE_SPECIAL_CONSTANTS(InType)
24+
};
25+
26+
using InFPBits = typename InConstants::FPBits;
27+
using InStorageType = typename InConstants::StorageType;
28+
29+
static constexpr InStorageType IN_MAX_NORMAL_U =
30+
InFPBits::max_normal().uintval();
31+
static constexpr InStorageType IN_MIN_NORMAL_U =
32+
InFPBits::min_normal().uintval();
33+
static constexpr InStorageType IN_MAX_SUBNORMAL_U =
34+
InFPBits::max_subnormal().uintval();
35+
static constexpr InStorageType IN_MIN_SUBNORMAL_U =
36+
InFPBits::min_subnormal().uintval();
37+
38+
public:
39+
typedef OutType (*AddFunc)(InType, InType);
40+
41+
void test_subnormal_range(AddFunc func) {
42+
constexpr InStorageType COUNT = 100'001;
43+
constexpr InStorageType STEP =
44+
(IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT;
45+
for (InStorageType i = 0, v = 0, w = IN_MAX_SUBNORMAL_U; i <= COUNT;
46+
++i, v += STEP, w -= STEP) {
47+
InType x = InFPBits(v).get_val();
48+
InType y = InFPBits(w).get_val();
49+
mpfr::BinaryInput<InType> input{x, y};
50+
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Add, input, func(x, y),
51+
0.5);
52+
}
53+
}
54+
55+
void test_normal_range(AddFunc func) {
56+
constexpr InStorageType COUNT = 100'001;
57+
constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT;
58+
for (InStorageType i = 0, v = 0, w = IN_MAX_NORMAL_U; i <= COUNT;
59+
++i, v += STEP, w -= STEP) {
60+
InType x = InFPBits(v).get_val();
61+
InType y = InFPBits(w).get_val();
62+
mpfr::BinaryInput<InType> input{x, y};
63+
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Add, input, func(x, y),
64+
0.5);
65+
}
66+
}
67+
};
68+
69+
#define LIST_ADD_TESTS(OutType, InType, func) \
70+
using LlvmLibcAddTest = AddTest<OutType, InType>; \
71+
TEST_F(LlvmLibcAddTest, SubnormalRange) { test_subnormal_range(&func); } \
72+
TEST_F(LlvmLibcAddTest, NormalRange) { test_normal_range(&func); }
73+
74+
#endif // LLVM_LIBC_TEST_SRC_MATH_ADDTEST_H

libc/test/src/math/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,6 +1902,19 @@ add_fp_unittest(
19021902
libc.src.__support.FPUtil.fp_bits
19031903
)
19041904

1905+
add_fp_unittest(
1906+
f16addf_test
1907+
NEED_MPFR
1908+
SUITE
1909+
libc-math-unittests
1910+
SRCS
1911+
f16addf_test.cpp
1912+
HDRS
1913+
AddTest.h
1914+
DEPENDS
1915+
libc.src.math.f16addf
1916+
)
1917+
19051918
add_fp_unittest(
19061919
f16div_test
19071920
NEED_MPFR

0 commit comments

Comments
 (0)