[libc-commits] [libc] [libc][math][C23] add software float16 support (PR #184283)
via libc-commits
libc-commits at lists.llvm.org
Fri Aug 28 20:48:55 PDT 2026
https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/184283
>From 462f21f58041a85431e71a102a933980683a62eb Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Tue, 3 Mar 2026 02:42:07 +0200
Subject: [PATCH 1/3] [libc][math][C23] add software float16 support
---
libc/config/linux/arm/entrypoints.txt | 5 +
.../include/llvm-libc-macros/float16-macros.h | 13 +-
libc/src/__support/FPUtil/BasicOperations.h | 4 +
libc/src/__support/FPUtil/CMakeLists.txt | 18 +++
libc/src/__support/FPUtil/Float16.h | 127 ++++++++++++++++++
libc/src/__support/macros/properties/types.h | 12 ++
libc/src/__support/math/CMakeLists.txt | 1 +
libc/src/__support/math/fabsf16.h | 4 +-
libc/test/src/math/exhaustive/CMakeLists.txt | 17 +++
.../src/math/exhaustive/exhaustive_test.h | 1 +
.../test/src/math/exhaustive/float16_test.cpp | 67 +++++++++
libc/test/src/math/smoke/CMakeLists.txt | 1 +
libc/test/src/math/smoke/fabsf16_test.cpp | 2 +-
libc/utils/MPFRWrapper/CMakeLists.txt | 2 +
libc/utils/MPFRWrapper/MPCommon.cpp | 7 +-
libc/utils/MPFRWrapper/MPFRUtils.cpp | 1 +
16 files changed, 276 insertions(+), 6 deletions(-)
create mode 100644 libc/src/__support/FPUtil/Float16.h
create mode 100644 libc/test/src/math/exhaustive/float16_test.cpp
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 1986d6a5347dc..608b50843b94a 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -506,6 +506,11 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.ufromfpxl
)
+list(APPEND TARGET_LIBM_ENTRYPOINTS
+ # float16 entrypoints
+ libc.src.math.fabsf16
+)
+
list(APPEND TARGET_LIBM_ENTRYPOINTS
# bfloat16 entrypoints
libc.src.math.atanbf16
diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h
index 528c7f016f873..0b40a1b85636c 100644
--- a/libc/include/llvm-libc-macros/float16-macros.h
+++ b/libc/include/llvm-libc-macros/float16-macros.h
@@ -11,11 +11,18 @@
#include "../llvm-libc-types/float128.h"
-#if defined(__FLT16_MANT_DIG__) && \
+#if defined(__arm__) && defined(_M_ARM)
+#define LIBC_USE_SOFT_FLOAT16
+#endif
+
+#ifdef LIBC_USE_SOFT_FLOAT16
+#define LIBC_TYPES_HAS_FLOAT16
+#endif
+
+#if !defined(LIBC_TYPES_HAS_FLOAT16) && defined(__FLT16_MANT_DIG__) && \
(!defined(__GNUC__) || __GNUC__ >= 13 || \
(defined(__clang__) && __clang_major__ >= 12)) && \
- !defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
- !defined(_WIN32)
+ !defined(__riscv) && !defined(_WIN32)
#define LIBC_TYPES_HAS_FLOAT16
// TODO: This would no longer be required if HdrGen let us guard function
diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h
index 5b81b921296a0..747d089f3da73 100644
--- a/libc/src/__support/FPUtil/BasicOperations.h
+++ b/libc/src/__support/FPUtil/BasicOperations.h
@@ -53,6 +53,7 @@ max(T x, T y) {
}
#ifdef LIBC_TYPES_HAS_FLOAT16
+#if !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
template <> LIBC_INLINE constexpr float16 max(float16 x, float16 y) {
if (cpp::is_constant_evaluated())
@@ -69,6 +70,7 @@ template <> LIBC_INLINE constexpr float16 max(float16 x, float16 y) {
return ((xi > yi) != (xi < 0 && yi < 0)) ? x : y;
}
#endif
+#endif // !LIBC_USE_SOFT_FLOAT16
#endif // LIBC_TYPES_HAS_FLOAT16
#if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
@@ -106,6 +108,7 @@ min(T x, T y) {
}
#ifdef LIBC_TYPES_HAS_FLOAT16
+#if !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
template <> LIBC_INLINE constexpr float16 min(float16 x, float16 y) {
if (cpp::is_constant_evaluated())
@@ -122,6 +125,7 @@ template <> LIBC_INLINE constexpr float16 min(float16 x, float16 y) {
return ((xi < yi) != (xi < 0 && yi < 0)) ? x : y;
}
#endif
+#endif // !LIBC_USE_SOFT_FLOAT16
#endif // LIBC_TYPES_HAS_FLOAT16
#if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 4673ef794c80b..2f86adc9b745e 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -43,6 +43,24 @@ add_header_library(
libc.src.__support.uint128
)
+add_header_library(
+ Float16
+ HDRS
+ Float16.h
+ DEPENDS
+ .cast
+ .comparison_operations
+ .dyadic_float
+ libc.hdr.stdint_proxy
+ libc.src.__support.CPP.bit
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.FPUtil.generic.add_sub
+ libc.src.__support.FPUtil.generic.div
+ libc.src.__support.FPUtil.generic.mul
+ libc.src.__support.macros.config
+ libc.src.__support.macros.properties.types
+)
+
add_header_library(
fpbits_str
HDRS
diff --git a/libc/src/__support/FPUtil/Float16.h b/libc/src/__support/FPUtil/Float16.h
new file mode 100644
index 0000000000000..5387e6a7c1c7a
--- /dev/null
+++ b/libc/src/__support/FPUtil/Float16.h
@@ -0,0 +1,127 @@
+//===-- Definition of float16 data type. ------------------------*- 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___SUPPORT_FPUTIL_FLOAT16_H
+#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT16_H
+
+#include "src/__support/macros/properties/types.h"
+
+#ifdef LIBC_USE_SOFT_FLOAT16
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/comparison_operations.h"
+#include "src/__support/FPUtil/dyadic_float.h"
+#include "src/__support/FPUtil/generic/add_sub.h"
+#include "src/__support/FPUtil/generic/div.h"
+#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+struct Float16 {
+ uint16_t bits;
+
+ LIBC_INLINE Float16() = default;
+
+ template <typename T>
+ LIBC_INLINE constexpr explicit Float16(T value)
+ : bits(static_cast<uint16_t>(0U)) {
+ if constexpr (cpp::is_floating_point_v<T>) {
+ bits = fputil::cast<Float16>(value).bits;
+ } else if constexpr (cpp::is_integral_v<T>) {
+ Sign sign = Sign::POS;
+
+ if constexpr (cpp::is_signed_v<T>) {
+ if (value < 0) {
+ sign = Sign::NEG;
+ value = -value;
+ }
+ }
+
+ fputil::DyadicFloat<cpp::numeric_limits<cpp::make_unsigned_t<T>>::digits>
+ xd(sign, 0, value);
+ bits = xd.template as<Float16, /*ShouldSignalExceptions=*/true>().bits;
+
+ } else if constexpr (cpp::is_convertible_v<T, Float16>) {
+ bits = value.operator Float16().bits;
+ }
+ }
+
+ template <cpp::enable_if_t<fputil::get_fp_type<float>() ==
+ fputil::FPType::IEEE754_Binary32,
+ int> = 0>
+ LIBC_INLINE constexpr operator float() const {
+ return fputil::cast<float>(*this);
+ }
+
+ template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
+ LIBC_INLINE constexpr explicit operator T() const {
+ return static_cast<T>(static_cast<float>(*this));
+ }
+
+ LIBC_INLINE bool operator==(Float16 other) const {
+ return fputil::equals(*this, other);
+ }
+
+ LIBC_INLINE bool operator!=(Float16 other) const {
+ return !fputil::equals(*this, other);
+ }
+
+ LIBC_INLINE bool operator<(Float16 other) const {
+ return fputil::less_than(*this, other);
+ }
+
+ LIBC_INLINE bool operator<=(Float16 other) const {
+ return fputil::less_than_or_equals(*this, other);
+ }
+
+ LIBC_INLINE bool operator>(Float16 other) const {
+ return fputil::greater_than(*this, other);
+ }
+
+ LIBC_INLINE bool operator>=(Float16 other) const {
+ return fputil::greater_than_or_equals(*this, other);
+ }
+
+ LIBC_INLINE constexpr Float16 operator-() const {
+ fputil::FPBits<float16> result(*this);
+ result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS);
+ return result.get_val();
+ }
+
+ LIBC_INLINE Float16 operator+(Float16 other) const {
+ return fputil::generic::add<Float16>(*this, other);
+ }
+
+ LIBC_INLINE Float16 operator-(Float16 other) const {
+ return fputil::generic::sub<Float16>(*this, other);
+ }
+
+ LIBC_INLINE Float16 operator*(Float16 other) const {
+ return fputil::generic::mul<float16>(*this, other);
+ }
+
+ LIBC_INLINE Float16 operator/(Float16 other) const {
+ return fputil::generic::div<float16>(*this, other);
+ }
+
+ LIBC_INLINE Float16 &operator*=(const Float16 &other) {
+ *this = *this * other;
+ return *this;
+ }
+}; // struct Float16
+
+} // namespace fputil
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LIBC_USE_SOFT_FLOAT16
+
+#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT16_H
diff --git a/libc/src/__support/macros/properties/types.h b/libc/src/__support/macros/properties/types.h
index 505fa6d7957f8..68907507b9ffc 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -50,8 +50,20 @@
// LIBC_TYPES_HAS_FLOAT16 is provided by
// "include/llvm-libc-macros/float16-macros.h"
#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_USE_SOFT_FLOAT16
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+struct Float16;
+} // namespace fputil
+} // namespace LIBC_NAMESPACE_DECL
+
+using float16 = LIBC_NAMESPACE::fputil::Float16;
+#else
// Type alias for internal use.
using float16 = _Float16;
+#endif
+
#endif // LIBC_TYPES_HAS_FLOAT16
// -- float128 support --------------------------------------------------------
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index 9f4624682eafe..baed5ad3ffea9 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3236,6 +3236,7 @@ add_header_library(
fabsf16.h
DEPENDS
libc.include.llvm-libc-macros.float16_macros
+ libc.src.__support.FPUtil.Float16
libc.src.__support.FPUtil.basic_operations
libc.src.__support.macros.config
FLAGS
diff --git a/libc/src/__support/math/fabsf16.h b/libc/src/__support/math/fabsf16.h
index 26634361adc73..ca568c680b7c2 100644
--- a/libc/src/__support/math/fabsf16.h
+++ b/libc/src/__support/math/fabsf16.h
@@ -14,6 +14,7 @@
#ifdef LIBC_TYPES_HAS_FLOAT16
#include "src/__support/FPUtil/BasicOperations.h"
+#include "src/__support/FPUtil/Float16.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
@@ -27,7 +28,8 @@ LIBC_INLINE constexpr float16 fabsf16(float16 x) {
// For x86, GCC generates better code from the generic implementation.
// https://godbolt.org/z/K9orM4hTa
#if defined(__LIBC_MISC_MATH_BASIC_OPS_OPT) && \
- !(defined(LIBC_TARGET_ARCH_IS_X86) && defined(LIBC_COMPILER_IS_GCC))
+ !(defined(LIBC_TARGET_ARCH_IS_X86) && defined(LIBC_COMPILER_IS_GCC)) && \
+ !defined(LIBC_USE_SOFT_FLOAT16)
return __builtin_fabsf16(x);
#else
return fputil::abs(x);
diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 2d1301d3a1e66..97355fbbf0278 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -713,6 +713,23 @@ add_fp_unittest(
-lpthread
)
+add_fp_unittest(
+ float16_test
+ NO_RUN_POSTBUILD
+ NEED_MPFR
+ SUITE
+ libc_math_exhaustive_tests
+ SRCS
+ float16_test.cpp
+ DEPENDS
+ .exhaustive_test
+ libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.cast
+ libc.src.__support.FPUtil.fp_bits
+ LINK_LIBRARIES
+ -lpthread
+)
+
add_fp_unittest(
bfloat16_test
NO_RUN_POSTBUILD
diff --git a/libc/test/src/math/exhaustive/exhaustive_test.h b/libc/test/src/math/exhaustive/exhaustive_test.h
index 322d774d46a68..04d43214e00a2 100644
--- a/libc/test/src/math/exhaustive/exhaustive_test.h
+++ b/libc/test/src/math/exhaustive/exhaustive_test.h
@@ -8,6 +8,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
+#include "src/__support/FPUtil/Float16.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
diff --git a/libc/test/src/math/exhaustive/float16_test.cpp b/libc/test/src/math/exhaustive/float16_test.cpp
new file mode 100644
index 0000000000000..3d1ba1ab805a6
--- /dev/null
+++ b/libc/test/src/math/exhaustive/float16_test.cpp
@@ -0,0 +1,67 @@
+//===-- Exhaustive tests for float -> float16 conversion ------------------===//
+//
+// 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/cast.h"
+#include "utils/MPFRWrapper/MPCommon.h"
+
+using namespace LIBC_NAMESPACE::fputil;
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
+
+template <typename InType>
+struct Float16ConversionChecker : public virtual LIBC_NAMESPACE::testing::Test {
+ using FloatType = InType;
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<FloatType>;
+ using StorageType = typename FPBits::StorageType;
+
+ // Check in a range, return the number of failures.
+ uint64_t check(StorageType start, StorageType stop,
+ mpfr::RoundingMode rounding) {
+ mpfr::ForceRoundingMode r(rounding);
+ if (!r.success)
+ return (stop > start);
+ StorageType bits = start;
+ uint64_t failed = 0;
+ do {
+ FPBits x_bits(bits);
+ FloatType x = x_bits.get_val();
+
+ const float16 libc_result = cast<float16>(x);
+ const float16 mpfr_result = mpfr::MPFRNumber(x).as<float16>();
+
+ const bool correct =
+ LIBC_NAMESPACE::testing::getMatcher<
+ LIBC_NAMESPACE::testing::TestCond::EQ>(mpfr_result)
+ .match(libc_result);
+
+ failed += (!correct);
+ } while (bits++ < stop);
+ return failed;
+ }
+};
+
+template <typename FloatType>
+using LlvmLibcFloat16ExhaustiveTest =
+ LlvmLibcExhaustiveMathTest<Float16ConversionChecker<FloatType>>;
+using LlvmLibcFloat16FromFloatTest = LlvmLibcFloat16ExhaustiveTest<float>;
+
+// Positive Range: [0, Inf];
+constexpr uint32_t POS_START = 0x0000'0000U;
+constexpr uint32_t POS_STOP = 0x7f80'0000U;
+
+// Negative Range: [-Inf, 0];
+constexpr uint32_t NEG_START = 0xb000'0000U;
+constexpr uint32_t NEG_STOP = 0xff80'0000U;
+
+TEST_F(LlvmLibcFloat16FromFloatTest, PostiveRange) {
+ test_full_range_all_roundings(POS_START, POS_STOP);
+}
+
+TEST_F(LlvmLibcFloat16FromFloatTest, NegativeRange) {
+ test_full_range_all_roundings(NEG_START, NEG_STOP);
+}
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 81f76fa7681fd..8e670ad2a2851 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -229,6 +229,7 @@ add_fp_unittest(
FAbsTest.h
DEPENDS
libc.src.math.fabsf16
+ libc.src.__support.FPUtil.Float16
)
add_fp_unittest(
diff --git a/libc/test/src/math/smoke/fabsf16_test.cpp b/libc/test/src/math/smoke/fabsf16_test.cpp
index c43bd5090f90b..d4d6dd1d2593a 100644
--- a/libc/test/src/math/smoke/fabsf16_test.cpp
+++ b/libc/test/src/math/smoke/fabsf16_test.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "FAbsTest.h"
-
+#include "src/__support/FPUtil/Float16.h"
#include "src/math/fabsf16.h"
LIST_FABS_TESTS(float16, LIBC_NAMESPACE::fabsf16)
diff --git a/libc/utils/MPFRWrapper/CMakeLists.txt b/libc/utils/MPFRWrapper/CMakeLists.txt
index 73151c61a7fcc..a1546992ce21c 100644
--- a/libc/utils/MPFRWrapper/CMakeLists.txt
+++ b/libc/utils/MPFRWrapper/CMakeLists.txt
@@ -14,6 +14,7 @@ if(LIBC_TESTS_CAN_USE_MPFR OR LIBC_TESTS_CAN_USE_MPC)
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
+ libc.src.__support.FPUtil.Float16
libc.src.__support.FPUtil.bfloat16
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.fp_bits
@@ -43,6 +44,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
libc.hdr.stdint_proxy
libc.src.__support.CPP.array
libc.src.__support.CPP.stringstream
+ libc.src.__support.FPUtil.Float16
libc.src.__support.FPUtil.bfloat16
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index 2422bcf45222f..4847f03d1cbfa 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -10,6 +10,11 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/FPUtil/bfloat16.h"
+
+#ifdef LIBC_USE_SOFT_FLOAT16
+#include "src/__support/FPUtil/Float16.h"
+#endif
+
#include "src/__support/FPUtil/cast.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/types.h"
@@ -632,7 +637,7 @@ template <> long double MPFRNumber::as<long double>() const {
return mpfr_get_ld(value, mpfr_rounding);
}
-#ifdef LIBC_TYPES_HAS_FLOAT16
+#if defined(LIBC_TYPES_HAS_FLOAT16) || defined(LIBC_USE_SOFT_FLOAT16)
template <> float16 MPFRNumber::as<float16>() const {
// TODO: Either prove that this cast won't cause double-rounding errors, or
// find a better way to get a float16.
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index d585baa2e0d2c..b928edeebba4b 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -11,6 +11,7 @@
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/stringstream.h"
+#include "src/__support/FPUtil/Float16.h"
#include "src/__support/FPUtil/bfloat16.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/macros/config.h"
>From ad2e245150fb5234cd42f4f95cc6b800b29504e6 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Wed, 5 Aug 2026 03:40:11 +0300
Subject: [PATCH 2/3] address reviews
---
.../include/llvm-libc-macros/float16-macros.h | 2 +-
.../CPP/type_traits/is_floating_point.h | 3 +-
libc/src/__support/FPUtil/BasicOperations.h | 12 +-
libc/src/__support/FPUtil/CMakeLists.txt | 37 +++---
libc/src/__support/FPUtil/FPBits.h | 2 +
libc/src/__support/FPUtil/cast.h | 22 +++-
libc/src/__support/FPUtil/dyadic_float.h | 3 +-
.../__support/FPUtil/{Float16.h => float16.h} | 55 +++++---
libc/src/__support/macros/properties/types.h | 6 +-
libc/src/__support/math/CMakeLists.txt | 2 +-
libc/src/__support/math/fabsf16.h | 2 +-
libc/test/src/__support/FPUtil/CMakeLists.txt | 11 ++
.../src/__support/FPUtil/float16_test.cpp | 124 ++++++++++++++++++
libc/test/src/math/exhaustive/CMakeLists.txt | 2 +-
.../src/math/exhaustive/exhaustive_test.h | 2 +-
libc/test/src/math/smoke/CMakeLists.txt | 2 +-
libc/test/src/math/smoke/fabsf16_test.cpp | 2 +-
libc/utils/MPFRWrapper/CMakeLists.txt | 4 +-
libc/utils/MPFRWrapper/MPCommon.cpp | 14 +-
libc/utils/MPFRWrapper/MPCommon.h | 9 ++
libc/utils/MPFRWrapper/MPFRUtils.cpp | 2 +-
21 files changed, 243 insertions(+), 75 deletions(-)
rename libc/src/__support/FPUtil/{Float16.h => float16.h} (68%)
create mode 100644 libc/test/src/__support/FPUtil/float16_test.cpp
diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h
index 0b40a1b85636c..5a1a9cdd311f8 100644
--- a/libc/include/llvm-libc-macros/float16-macros.h
+++ b/libc/include/llvm-libc-macros/float16-macros.h
@@ -11,7 +11,7 @@
#include "../llvm-libc-types/float128.h"
-#if defined(__arm__) && defined(_M_ARM)
+#if (defined(__arm__) && defined(_M_ARM)) || defined(__riscv)
#define LIBC_USE_SOFT_FLOAT16
#endif
diff --git a/libc/src/__support/CPP/type_traits/is_floating_point.h b/libc/src/__support/CPP/type_traits/is_floating_point.h
index 283c4fcefb6fe..dae4e47a5534c 100644
--- a/libc/src/__support/CPP/type_traits/is_floating_point.h
+++ b/libc/src/__support/CPP/type_traits/is_floating_point.h
@@ -42,7 +42,8 @@ template <typename T> struct is_floating_point {
#endif
,
bfloat16
-
+ ,
+ fputil::Float16
,
fputil::Float128>();
};
diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h
index 747d089f3da73..4c64d6dabbd29 100644
--- a/libc/src/__support/FPUtil/BasicOperations.h
+++ b/libc/src/__support/FPUtil/BasicOperations.h
@@ -52,8 +52,7 @@ max(T x, T y) {
return constexpr_max(x, y);
}
-#ifdef LIBC_TYPES_HAS_FLOAT16
-#if !defined(LIBC_USE_SOFT_FLOAT16)
+#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
template <> LIBC_INLINE constexpr float16 max(float16 x, float16 y) {
if (cpp::is_constant_evaluated())
@@ -70,8 +69,7 @@ template <> LIBC_INLINE constexpr float16 max(float16 x, float16 y) {
return ((xi > yi) != (xi < 0 && yi < 0)) ? x : y;
}
#endif
-#endif // !LIBC_USE_SOFT_FLOAT16
-#endif // LIBC_TYPES_HAS_FLOAT16
+#endif // defined(LIBC_TYPES_HAS_FLOAT16) && !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
template <> LIBC_INLINE constexpr float max(float x, float y) {
@@ -107,8 +105,7 @@ min(T x, T y) {
return constexpr_min(x, y);
}
-#ifdef LIBC_TYPES_HAS_FLOAT16
-#if !defined(LIBC_USE_SOFT_FLOAT16)
+#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAXF16_FMINF16)
template <> LIBC_INLINE constexpr float16 min(float16 x, float16 y) {
if (cpp::is_constant_evaluated())
@@ -125,8 +122,7 @@ template <> LIBC_INLINE constexpr float16 min(float16 x, float16 y) {
return ((xi < yi) != (xi < 0 && yi < 0)) ? x : y;
}
#endif
-#endif // !LIBC_USE_SOFT_FLOAT16
-#endif // LIBC_TYPES_HAS_FLOAT16
+#endif // defined(LIBC_TYPES_HAS_FLOAT16) && !defined(LIBC_USE_SOFT_FLOAT16)
#if defined(__LIBC_USE_BUILTIN_FMAX_FMIN) && !defined(LIBC_TARGET_ARCH_IS_X86)
template <> LIBC_INLINE constexpr float min(float x, float y) {
diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 2f86adc9b745e..299299fb166ca 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -43,24 +43,6 @@ add_header_library(
libc.src.__support.uint128
)
-add_header_library(
- Float16
- HDRS
- Float16.h
- DEPENDS
- .cast
- .comparison_operations
- .dyadic_float
- libc.hdr.stdint_proxy
- libc.src.__support.CPP.bit
- libc.src.__support.CPP.type_traits
- libc.src.__support.FPUtil.generic.add_sub
- libc.src.__support.FPUtil.generic.div
- libc.src.__support.FPUtil.generic.mul
- libc.src.__support.macros.config
- libc.src.__support.macros.properties.types
-)
-
add_header_library(
fpbits_str
HDRS
@@ -294,6 +276,25 @@ add_header_library(
libc.src.__support.macros.properties.types
)
+add_header_library(
+ float16
+ HDRS
+ float16.h
+ DEPENDS
+ .cast
+ .comparison_operations
+ .dyadic_float
+ libc.hdr.stdint_proxy
+ libc.src.__support.CPP.bit
+ libc.src.__support.CPP.type_traits
+ libc.src.__support.FPUtil.generic.add_sub
+ libc.src.__support.FPUtil.generic.div
+ libc.src.__support.FPUtil.generic.mul
+ libc.src.__support.macros.attributes
+ libc.src.__support.macros.config
+ libc.src.__support.macros.properties.types
+)
+
add_header_library(
bfloat16
HDRS
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 83219b7573f46..4567144b6a3b2 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -815,6 +815,8 @@ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
return FPType::BFloat16;
else if constexpr (cpp::is_same_v<UnqualT, Float128>)
return FPType::IEEE754_Binary128;
+ else if constexpr (cpp::is_same_v<UnqualT, Float16>)
+ return FPType::IEEE754_Binary16;
else
static_assert(cpp::always_false<UnqualT>, "Unsupported type");
}
diff --git a/libc/src/__support/FPUtil/cast.h b/libc/src/__support/FPUtil/cast.h
index 4fc5ea0893ebe..f7607b7c67008 100644
--- a/libc/src/__support/FPUtil/cast.h
+++ b/libc/src/__support/FPUtil/cast.h
@@ -33,7 +33,9 @@ cast(InType x) {
if constexpr (cpp::is_same_v<OutType, bfloat16> ||
cpp::is_same_v<InType, bfloat16> ||
cpp::is_same_v<OutType, Float128> ||
- cpp::is_same_v<InType, Float128>
+ cpp::is_same_v<InType, Float128> ||
+ cpp::is_same_v<OutType, Float16> ||
+ cpp::is_same_v<InType, Float16>
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
|| cpp::is_same_v<OutType, float16> ||
cpp::is_same_v<InType, float16>
@@ -52,12 +54,18 @@ cast(InType x) {
return OutFPBits::quiet_nan().get_val();
}
- InStorageType x_mant = x_bits.get_mantissa();
- if (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN)
- x_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
- return OutFPBits::quiet_nan(x_bits.sign(),
- static_cast<OutStorageType>(x_mant))
- .get_val();
+ OutStorageType out_mant = 0;
+ if constexpr (InFPBits::FRACTION_LEN > OutFPBits::FRACTION_LEN) {
+ InStorageType in_mant = x_bits.get_mantissa();
+ in_mant >>= InFPBits::FRACTION_LEN - OutFPBits::FRACTION_LEN;
+ out_mant = static_cast<OutStorageType>(in_mant);
+ } else if constexpr (InFPBits::FRACTION_LEN < OutFPBits::FRACTION_LEN) {
+ out_mant = static_cast<OutStorageType>(x_bits.get_mantissa());
+ out_mant <<= OutFPBits::FRACTION_LEN - InFPBits::FRACTION_LEN;
+ } else {
+ out_mant = static_cast<OutStorageType>(x_bits.get_mantissa());
+ }
+ return OutFPBits::quiet_nan(x_bits.sign(), out_mant).get_val();
}
if (x_bits.is_inf())
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 80892701e689a..f55535327e789 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -438,7 +438,8 @@ template <size_t Bits> struct DyadicFloat {
(FPBits<T>::FRACTION_LEN < Bits),
void>>
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T as() const {
- if constexpr (cpp::is_same_v<T, bfloat16> || cpp::is_same_v<T, Float128>
+ if constexpr (cpp::is_same_v<T, bfloat16> || cpp::is_same_v<T, Float128> ||
+ cpp::is_same_v<T, Float16>
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
|| cpp::is_same_v<T, float16>
#endif
diff --git a/libc/src/__support/FPUtil/Float16.h b/libc/src/__support/FPUtil/float16.h
similarity index 68%
rename from libc/src/__support/FPUtil/Float16.h
rename to libc/src/__support/FPUtil/float16.h
index 5387e6a7c1c7a..d1c0981bc240e 100644
--- a/libc/src/__support/FPUtil/Float16.h
+++ b/libc/src/__support/FPUtil/float16.h
@@ -9,10 +9,6 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT16_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT16_H
-#include "src/__support/macros/properties/types.h"
-
-#ifdef LIBC_USE_SOFT_FLOAT16
-
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/cast.h"
@@ -21,7 +17,9 @@
#include "src/__support/FPUtil/generic/add_sub.h"
#include "src/__support/FPUtil/generic/div.h"
#include "src/__support/FPUtil/generic/mul.h"
+#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
@@ -52,6 +50,8 @@ struct Float16 {
} else if constexpr (cpp::is_convertible_v<T, Float16>) {
bits = value.operator Float16().bits;
+ } else {
+ bits = fputil::cast<Float16>(static_cast<float>(value)).bits;
}
}
@@ -67,61 +67,74 @@ struct Float16 {
return static_cast<T>(static_cast<float>(*this));
}
- LIBC_INLINE bool operator==(Float16 other) const {
+ LIBC_INLINE constexpr bool operator==(Float16 other) const {
return fputil::equals(*this, other);
}
- LIBC_INLINE bool operator!=(Float16 other) const {
+ LIBC_INLINE constexpr bool operator!=(Float16 other) const {
return !fputil::equals(*this, other);
}
- LIBC_INLINE bool operator<(Float16 other) const {
+ LIBC_INLINE constexpr bool operator<(Float16 other) const {
return fputil::less_than(*this, other);
}
- LIBC_INLINE bool operator<=(Float16 other) const {
+ LIBC_INLINE constexpr bool operator<=(Float16 other) const {
return fputil::less_than_or_equals(*this, other);
}
- LIBC_INLINE bool operator>(Float16 other) const {
+ LIBC_INLINE constexpr bool operator>(Float16 other) const {
return fputil::greater_than(*this, other);
}
- LIBC_INLINE bool operator>=(Float16 other) const {
+ LIBC_INLINE constexpr bool operator>=(Float16 other) const {
return fputil::greater_than_or_equals(*this, other);
}
- LIBC_INLINE constexpr Float16 operator-() const {
- fputil::FPBits<float16> result(*this);
+ LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR Float16 operator-() const {
+ fputil::FPBits<Float16> result(*this);
result.set_sign(result.is_pos() ? Sign::NEG : Sign::POS);
return result.get_val();
}
- LIBC_INLINE Float16 operator+(Float16 other) const {
+ LIBC_INLINE constexpr Float16 operator+(Float16 other) const {
return fputil::generic::add<Float16>(*this, other);
}
- LIBC_INLINE Float16 operator-(Float16 other) const {
+ LIBC_INLINE constexpr Float16 operator-(Float16 other) const {
return fputil::generic::sub<Float16>(*this, other);
}
- LIBC_INLINE Float16 operator*(Float16 other) const {
- return fputil::generic::mul<float16>(*this, other);
+ LIBC_INLINE constexpr Float16 operator*(Float16 other) const {
+ return fputil::generic::mul<Float16>(*this, other);
+ }
+
+ LIBC_INLINE constexpr Float16 operator/(Float16 other) const {
+ return fputil::generic::div<Float16>(*this, other);
+ }
+
+ LIBC_INLINE constexpr Float16 &operator+=(Float16 other) {
+ *this = *this + other;
+ return *this;
}
- LIBC_INLINE Float16 operator/(Float16 other) const {
- return fputil::generic::div<float16>(*this, other);
+ LIBC_INLINE constexpr Float16 &operator-=(Float16 other) {
+ *this = *this - other;
+ return *this;
}
- LIBC_INLINE Float16 &operator*=(const Float16 &other) {
+ LIBC_INLINE constexpr Float16 &operator*=(Float16 other) {
*this = *this * other;
return *this;
}
+
+ LIBC_INLINE constexpr Float16 &operator/=(Float16 other) {
+ *this = *this / other;
+ return *this;
+ }
}; // struct Float16
} // namespace fputil
} // namespace LIBC_NAMESPACE_DECL
-#endif // LIBC_USE_SOFT_FLOAT16
-
#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT16_H
diff --git a/libc/src/__support/macros/properties/types.h b/libc/src/__support/macros/properties/types.h
index 68907507b9ffc..b1dddaf58093f 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -49,15 +49,15 @@
// -- float16 support ---------------------------------------------------------
// LIBC_TYPES_HAS_FLOAT16 is provided by
// "include/llvm-libc-macros/float16-macros.h"
-#ifdef LIBC_TYPES_HAS_FLOAT16
-
-#ifdef LIBC_USE_SOFT_FLOAT16
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
struct Float16;
} // namespace fputil
} // namespace LIBC_NAMESPACE_DECL
+#ifdef LIBC_TYPES_HAS_FLOAT16
+
+#ifdef LIBC_USE_SOFT_FLOAT16
using float16 = LIBC_NAMESPACE::fputil::Float16;
#else
// Type alias for internal use.
diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt
index baed5ad3ffea9..765664abe2168 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3236,7 +3236,7 @@ add_header_library(
fabsf16.h
DEPENDS
libc.include.llvm-libc-macros.float16_macros
- libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.float16
libc.src.__support.FPUtil.basic_operations
libc.src.__support.macros.config
FLAGS
diff --git a/libc/src/__support/math/fabsf16.h b/libc/src/__support/math/fabsf16.h
index ca568c680b7c2..65b786fd77331 100644
--- a/libc/src/__support/math/fabsf16.h
+++ b/libc/src/__support/math/fabsf16.h
@@ -14,7 +14,7 @@
#ifdef LIBC_TYPES_HAS_FLOAT16
#include "src/__support/FPUtil/BasicOperations.h"
-#include "src/__support/FPUtil/Float16.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 87fd10aaacd90..1a85391234206 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -58,6 +58,17 @@ if(LLVM_LIBC_FULL_BUILD)
return()
endif()
+add_fp_unittest(
+ float16_test
+ NEED_MPFR
+ SUITE
+ libc-fputil-tests
+ SRCS
+ float16_test.cpp
+ DEPENDS
+ libc.src.__support.FPUtil.float16
+)
+
add_fp_unittest(
bfloat16_test
NEED_MPFR
diff --git a/libc/test/src/__support/FPUtil/float16_test.cpp b/libc/test/src/__support/FPUtil/float16_test.cpp
new file mode 100644
index 0000000000000..203e22c580692
--- /dev/null
+++ b/libc/test/src/__support/FPUtil/float16_test.cpp
@@ -0,0 +1,124 @@
+//===-- Unit tests for float16 type ---------------------------------------===//
+//
+// 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/float16.h"
+#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPCommon.h"
+
+using Float16 = LIBC_NAMESPACE::fputil::Float16;
+using LlvmLibcFloat16ConversionTest =
+ LIBC_NAMESPACE::testing::FPTest<Float16>;
+
+// range: [0, inf]
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7c00U;
+
+// range: [-0, -inf]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xfc00U;
+
+using MPFRNumber = LIBC_NAMESPACE::testing::mpfr::MPFRNumber;
+
+TEST_F(LlvmLibcFloat16ConversionTest, ToFloatPositiveRange) {
+ for (uint16_t bits = POS_START; bits <= POS_STOP; bits++) {
+ Float16 f16_num{bits};
+ MPFRNumber mpfr_num{f16_num};
+
+ // float16 to float
+ float mpfr_float = mpfr_num.as<float>();
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_float, static_cast<float>(f16_num));
+
+ // float to float16
+ Float16 f16_from_float{mpfr_float};
+ MPFRNumber mpfr_num_2{mpfr_float};
+ Float16 mpfr_f16 = mpfr_num_2.as<Float16>();
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, f16_from_float);
+ }
+}
+
+TEST_F(LlvmLibcFloat16ConversionTest, ToFloatNegativeRange) {
+ for (uint16_t bits = NEG_START; bits <= NEG_STOP; bits++) {
+ Float16 f16_num{bits};
+ MPFRNumber mpfr_num{f16_num};
+
+ // float16 to float
+ float mpfr_float = mpfr_num.as<float>();
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_float, static_cast<float>(f16_num));
+
+ // float to float16
+ Float16 f16_from_float{mpfr_float};
+ MPFRNumber mpfr_num_2{mpfr_float};
+ Float16 mpfr_f16 = mpfr_num_2.as<Float16>();
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, f16_from_float);
+ }
+}
+
+TEST_F(LlvmLibcFloat16ConversionTest, FromInteger) {
+ constexpr int RANGE = 1'234;
+ for (int i = -RANGE; i <= RANGE; i++) {
+ Float16 mpfr_f16 = MPFRNumber(i).as<Float16>();
+ Float16 libc_f16{i};
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, libc_f16);
+ }
+}
+
+TEST_F(LlvmLibcFloat16ConversionTest, CompoundAssignmentOperators) {
+ constexpr Float16 VAL[] = {zero, neg_zero, inf,
+ neg_inf, min_normal, max_normal,
+ Float16(1.0f), Float16(-1.0f), Float16(2.0f),
+ Float16(3.0f)};
+ // *=
+ for (const Float16 &x : VAL) {
+ for (const Float16 &y : VAL) {
+ Float16 a = x, b = y;
+ MPFRNumber mpfr_a{a}, mpfr_b{b};
+ MPFRNumber mpfr_c = mpfr_a.mul(mpfr_b);
+ Float16 mpfr_f16 = mpfr_c.as<Float16>();
+ a *= b;
+ Float16 libc_f16 = a;
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, libc_f16);
+ }
+ }
+ // /=
+ for (const Float16 &x : VAL) {
+ for (const Float16 &y : VAL) {
+ Float16 a = x, b = y;
+ MPFRNumber mpfr_a{a}, mpfr_b{b};
+ MPFRNumber mpfr_c = mpfr_a.div(mpfr_b);
+ Float16 mpfr_f16 = mpfr_c.as<Float16>();
+ a /= b;
+ Float16 libc_f16 = a;
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, libc_f16);
+ }
+ }
+ // +=
+ for (const Float16 &x : VAL) {
+ for (const Float16 &y : VAL) {
+ Float16 a = x, b = y;
+ MPFRNumber mpfr_a{a}, mpfr_b{b};
+ MPFRNumber mpfr_c = mpfr_a.add(mpfr_b);
+ Float16 mpfr_f16 = mpfr_c.as<Float16>();
+ a += b;
+ Float16 libc_f16 = a;
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, libc_f16);
+ }
+ }
+ // -=
+ for (const Float16 &x : VAL) {
+ for (const Float16 &y : VAL) {
+ Float16 a = x, b = y;
+ MPFRNumber mpfr_a{a}, mpfr_b{b};
+ MPFRNumber mpfr_c = mpfr_a.sub(mpfr_b);
+ Float16 mpfr_f16 = mpfr_c.as<Float16>();
+ a -= b;
+ Float16 libc_f16 = a;
+ EXPECT_FP_EQ_ALL_ROUNDING(mpfr_f16, libc_f16);
+ }
+ }
+}
diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt
index 97355fbbf0278..dbe8f7bbe2829 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -723,7 +723,7 @@ add_fp_unittest(
float16_test.cpp
DEPENDS
.exhaustive_test
- libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.float16
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.fp_bits
LINK_LIBRARIES
diff --git a/libc/test/src/math/exhaustive/exhaustive_test.h b/libc/test/src/math/exhaustive/exhaustive_test.h
index 04d43214e00a2..fd6452a976eb1 100644
--- a/libc/test/src/math/exhaustive/exhaustive_test.h
+++ b/libc/test/src/math/exhaustive/exhaustive_test.h
@@ -8,7 +8,7 @@
#include "src/__support/CPP/type_traits.h"
#include "src/__support/FPUtil/FPBits.h"
-#include "src/__support/FPUtil/Float16.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 8e670ad2a2851..1c60fb5191683 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -229,7 +229,7 @@ add_fp_unittest(
FAbsTest.h
DEPENDS
libc.src.math.fabsf16
- libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.float16
)
add_fp_unittest(
diff --git a/libc/test/src/math/smoke/fabsf16_test.cpp b/libc/test/src/math/smoke/fabsf16_test.cpp
index d4d6dd1d2593a..c7bab4b305f99 100644
--- a/libc/test/src/math/smoke/fabsf16_test.cpp
+++ b/libc/test/src/math/smoke/fabsf16_test.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "FAbsTest.h"
-#include "src/__support/FPUtil/Float16.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/math/fabsf16.h"
LIST_FABS_TESTS(float16, LIBC_NAMESPACE::fabsf16)
diff --git a/libc/utils/MPFRWrapper/CMakeLists.txt b/libc/utils/MPFRWrapper/CMakeLists.txt
index a1546992ce21c..f90e1007da529 100644
--- a/libc/utils/MPFRWrapper/CMakeLists.txt
+++ b/libc/utils/MPFRWrapper/CMakeLists.txt
@@ -14,7 +14,7 @@ if(LIBC_TESTS_CAN_USE_MPFR OR LIBC_TESTS_CAN_USE_MPC)
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
libc.src.__support.CPP.type_traits
- libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.float16
libc.src.__support.FPUtil.bfloat16
libc.src.__support.FPUtil.cast
libc.src.__support.FPUtil.fp_bits
@@ -44,7 +44,7 @@ if(LIBC_TESTS_CAN_USE_MPFR)
libc.hdr.stdint_proxy
libc.src.__support.CPP.array
libc.src.__support.CPP.stringstream
- libc.src.__support.FPUtil.Float16
+ libc.src.__support.FPUtil.float16
libc.src.__support.FPUtil.bfloat16
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.fpbits_str
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index 4847f03d1cbfa..0393ce6421ca7 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -10,11 +10,7 @@
#include "src/__support/CPP/string_view.h"
#include "src/__support/FPUtil/bfloat16.h"
-
-#ifdef LIBC_USE_SOFT_FLOAT16
-#include "src/__support/FPUtil/Float16.h"
-#endif
-
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/types.h"
@@ -637,7 +633,7 @@ template <> long double MPFRNumber::as<long double>() const {
return mpfr_get_ld(value, mpfr_rounding);
}
-#if defined(LIBC_TYPES_HAS_FLOAT16) || defined(LIBC_USE_SOFT_FLOAT16)
+#ifdef LIBC_TYPES_HAS_FLOAT16
template <> float16 MPFRNumber::as<float16>() const {
// TODO: Either prove that this cast won't cause double-rounding errors, or
// find a better way to get a float16.
@@ -645,6 +641,12 @@ template <> float16 MPFRNumber::as<float16>() const {
}
#endif
+#if !defined(LIBC_USE_SOFT_FLOAT16)
+template <> fputil::Float16 MPFRNumber::as<fputil::Float16>() const {
+ return fputil::cast<fputil::Float16>(mpfr_get_d(value, mpfr_rounding));
+}
+#endif
+
#ifdef LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
template <> float128 MPFRNumber::as<float128>() const {
return mpfr_get_float128(value, mpfr_rounding);
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 38fd15fcc956c..32a6a3ee47fca 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -65,6 +65,12 @@ template <> struct ExtraPrecision<float128> {
};
#endif // LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE
+#if !defined(LIBC_USE_SOFT_FLOAT16)
+template <> struct ExtraPrecision<LIBC_NAMESPACE::fputil::Float16> {
+ static constexpr unsigned int VALUE = 128;
+};
+#endif
+
template <> struct ExtraPrecision<bfloat16> {
static constexpr unsigned int VALUE = 64;
};
@@ -115,6 +121,9 @@ class MPFRNumber {
cpp::enable_if_t<cpp::is_same_v<float, XType>
#ifdef LIBC_TYPES_HAS_FLOAT16
|| cpp::is_same_v<float16, XType>
+#endif
+#if !defined(LIBC_USE_SOFT_FLOAT16)
+ || cpp::is_same_v<LIBC_NAMESPACE::fputil::Float16, XType>
#endif
|| cpp::is_same_v<bfloat16, XType>,
int> = 0>
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index b928edeebba4b..5c9471af1c5a5 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -11,7 +11,7 @@
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/stringstream.h"
-#include "src/__support/FPUtil/Float16.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/FPUtil/bfloat16.h"
#include "src/__support/FPUtil/fpbits_str.h"
#include "src/__support/macros/config.h"
>From 43dcaed51c2a68c799a5e22a618a37a2935e1cb0 Mon Sep 17 00:00:00 2001
From: Anonmiraj <ezzibrahimx at gmail.com>
Date: Sat, 29 Aug 2026 05:52:21 +0300
Subject: [PATCH 3/3] Make soft float16 emulation the default behavior
---
libc/config/baremetal/aarch64/entrypoints.txt | 2 +-
libc/config/baremetal/arm/entrypoints.txt | 2 +-
libc/config/baremetal/riscv/entrypoints.txt | 2 +-
libc/config/darwin/aarch64/entrypoints.txt | 2 +-
libc/config/freebsd/x86_64/entrypoints.txt | 2 +-
libc/config/linux/aarch64/entrypoints.txt | 2 +-
libc/config/linux/arm/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 2 +-
libc/config/linux/x86_64/entrypoints.txt | 2 +-
libc/config/windows/entrypoints.txt | 1 +
libc/include/llvm-libc-macros/float16-macros.h | 8 ++++----
libc/src/__support/FPUtil/float16.h | 4 ++++
libc/src/__support/math/fabsf16.h | 7 +------
libc/test/src/__support/FPUtil/CMakeLists.txt | 2 ++
.../src/__support/FPUtil/comparison_operations_test.cpp | 1 +
libc/test/src/__support/FPUtil/dyadic_float_test.cpp | 1 +
16 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 93808e4c471fc..72a33d15bd9c3 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -398,6 +398,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -637,7 +638,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 71ecbe438bf7b..566a0e40582f1 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -410,6 +410,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -649,7 +650,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index b38f60ab9d5f5..50172348ca048 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -406,6 +406,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -645,7 +646,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt
index 15adad72ab459..cf25a76391ae7 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -217,6 +217,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -457,7 +458,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/freebsd/x86_64/entrypoints.txt b/libc/config/freebsd/x86_64/entrypoints.txt
index df6c0f907725b..140a0829cea3a 100644
--- a/libc/config/freebsd/x86_64/entrypoints.txt
+++ b/libc/config/freebsd/x86_64/entrypoints.txt
@@ -153,6 +153,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -407,7 +408,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 1ccb6cf202cf7..7efc7f799c425 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -545,6 +545,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -774,7 +775,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
# libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.fdiv
libc.src.math.fdivl
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 608b50843b94a..a7a4a34736890 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -332,6 +332,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5083417b453be..6702012d2fd28 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -616,6 +616,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -863,7 +864,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index bf809e268f585..350239779d00a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -621,6 +621,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
@@ -868,7 +869,6 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.f16sub
libc.src.math.f16subf
libc.src.math.f16subl
- libc.src.math.fabsf16
libc.src.math.fdimf16
libc.src.math.floorf16
libc.src.math.fmaf16
diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 5333bc4042070..5b40867b54b81 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -185,6 +185,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.expm1f
libc.src.math.fabs
libc.src.math.fabsf
+ libc.src.math.fabsf16
libc.src.math.fabsl
libc.src.math.fadd
libc.src.math.faddl
diff --git a/libc/include/llvm-libc-macros/float16-macros.h b/libc/include/llvm-libc-macros/float16-macros.h
index 5a1a9cdd311f8..0a537388cc31a 100644
--- a/libc/include/llvm-libc-macros/float16-macros.h
+++ b/libc/include/llvm-libc-macros/float16-macros.h
@@ -11,7 +11,7 @@
#include "../llvm-libc-types/float128.h"
-#if (defined(__arm__) && defined(_M_ARM)) || defined(__riscv)
+#ifndef LIBC_DONT_USE_SOFT_FLOAT16
#define LIBC_USE_SOFT_FLOAT16
#endif
@@ -24,12 +24,12 @@
(defined(__clang__) && __clang_major__ >= 12)) && \
!defined(__riscv) && !defined(_WIN32)
#define LIBC_TYPES_HAS_FLOAT16
+#endif
// TODO: This would no longer be required if HdrGen let us guard function
// declarations with multiple macros.
-#ifdef LIBC_TYPES_HAS_FLOAT128
+#if defined(LIBC_TYPES_HAS_FLOAT16) && defined(LIBC_TYPES_HAS_FLOAT128)
#define LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128
-#endif // LIBC_TYPES_HAS_FLOAT128
-#endif
+#endif // LIBC_TYPES_HAS_FLOAT16 && LIBC_TYPES_HAS_FLOAT128
#endif // LLVM_LIBC_MACROS_FLOAT16_MACROS_H
diff --git a/libc/src/__support/FPUtil/float16.h b/libc/src/__support/FPUtil/float16.h
index d1c0981bc240e..21349d682c826 100644
--- a/libc/src/__support/FPUtil/float16.h
+++ b/libc/src/__support/FPUtil/float16.h
@@ -29,6 +29,10 @@ struct Float16 {
LIBC_INLINE Float16() = default;
+ template <size_t Bits>
+ LIBC_INLINE constexpr explicit Float16(const DyadicFloat<Bits> &df)
+ : bits(df.template as<Float16, /*ShouldSignalExceptions=*/false>().bits) {}
+
template <typename T>
LIBC_INLINE constexpr explicit Float16(T value)
: bits(static_cast<uint16_t>(0U)) {
diff --git a/libc/src/__support/math/fabsf16.h b/libc/src/__support/math/fabsf16.h
index 65b786fd77331..afbc662c5a40c 100644
--- a/libc/src/__support/math/fabsf16.h
+++ b/libc/src/__support/math/fabsf16.h
@@ -9,15 +9,12 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_FABSF16_H
#define LLVM_LIBC_SRC___SUPPORT_MATH_FABSF16_H
-#include "include/llvm-libc-macros/float16-macros.h"
-
-#ifdef LIBC_TYPES_HAS_FLOAT16
-
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/float16.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
+#include "src/__support/macros/properties/types.h"
namespace LIBC_NAMESPACE_DECL {
namespace math {
@@ -39,6 +36,4 @@ LIBC_INLINE constexpr float16 fabsf16(float16 x) {
} // namespace math
} // namespace LIBC_NAMESPACE_DECL
-#endif // LIBC_TYPES_HAS_FLOAT16
-
#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FABSF16_H
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 1a85391234206..bb5b849ceeef7 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -9,6 +9,7 @@ add_fp_unittest(
dyadic_float_test.cpp
DEPENDS
libc.src.__support.FPUtil.dyadic_float
+ libc.src.__support.FPUtil.float16
libc.src.__support.macros.properties.types
COMPILE_OPTIONS
# Prevent constant folding with a default rounding mode.
@@ -89,5 +90,6 @@ add_fp_unittest(
DEPENDS
libc.src.__support.FPUtil.bfloat16
libc.src.__support.FPUtil.comparison_operations
+ libc.src.__support.FPUtil.float16
libc.src.__support.macros.properties.types
)
diff --git a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
index 681b686c2acf0..0580ea848968e 100644
--- a/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
+++ b/libc/test/src/__support/FPUtil/comparison_operations_test.cpp
@@ -8,6 +8,7 @@
#include "src/__support/FPUtil/bfloat16.h"
#include "src/__support/FPUtil/comparison_operations.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FEnvSafeTest.h"
#include "test/UnitTest/FPMatcher.h"
diff --git a/libc/test/src/__support/FPUtil/dyadic_float_test.cpp b/libc/test/src/__support/FPUtil/dyadic_float_test.cpp
index 720b426033dff..2dc670d814c5a 100644
--- a/libc/test/src/__support/FPUtil/dyadic_float_test.cpp
+++ b/libc/test/src/__support/FPUtil/dyadic_float_test.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "src/__support/FPUtil/dyadic_float.h"
+#include "src/__support/FPUtil/float16.h"
#include "src/__support/big_int.h"
#include "src/__support/macros/properties/types.h"
#include "test/UnitTest/FPMatcher.h"
More information about the libc-commits
mailing list