[libc-commits] [libc] [libc][math][C23] add software float16 support (PR #184283)

via libc-commits libc-commits at lists.llvm.org
Fri Aug 28 21:51:38 PDT 2026


https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/184283

>From 8608a2f31d6d9bc469fdbad813b4f8ab4d072984 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 d853ec0f13678..9954b09b44af9 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -583,6 +583,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 6080638f20bf4..20df43647306e 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 a32244e478532..161d87eb4171a 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 aad4c41005c45..80789791d3d97 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -70,8 +70,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 272e9425a4e1e..fdc54d63bf9d6 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3257,6 +3257,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 46b5b138cfb11..34dab8d05dede 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -739,6 +739,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 be532041a7562..075db03922d57 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -240,6 +240,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 8efa6fc1f0b12..611d78455dc98 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
@@ -44,6 +45,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 bc32b11466e5a..cdd60f510436f 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 c76cac63a0e3e33698626f2b310cf3722cf469bc 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      |   2 +-
 .../__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, 242 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 20df43647306e..6ba31abd93df3 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 4a5984e38a8cf..973fd9909b244 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 161d87eb4171a..ce8a97913a579 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 6127dede03f4a..596d24b05a14c 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -818,6 +818,8 @@ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
     return FPType::IEEE754_Binary128;
   else if constexpr (cpp::is_same_v<UnqualT, Float80>)
     return FPType::X86_Binary80;
+  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 2a9bfd5a9f62e..56ee24fd28a4b 100644
--- a/libc/src/__support/FPUtil/cast.h
+++ b/libc/src/__support/FPUtil/cast.h
@@ -35,7 +35,9 @@ cast(InType x) {
                   cpp::is_same_v<OutType, Float128> ||
                   cpp::is_same_v<InType, Float128> ||
                   cpp::is_same_v<OutType, Float80> ||
-                  cpp::is_same_v<InType, Float80>
+                  cpp::is_same_v<InType, Float80> ||
+                  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>
@@ -54,12 +56,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 e32906e3cf9cf..227edb95faafd 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -441,7 +441,7 @@ template <size_t Bits> struct DyadicFloat {
                                         void>>
   LIBC_INLINE LIBC_CONSTEXPR_DEFAULT T as() const {
     if constexpr (cpp::is_same_v<T, bfloat16> || cpp::is_same_v<T, Float128> ||
-                  cpp::is_same_v<T, Float80>
+                  cpp::is_same_v<T, Float80> || 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 80789791d3d97..86276cd9365dc 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -69,15 +69,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 fdc54d63bf9d6..c0e596c85aeee 100644
--- a/libc/src/__support/math/CMakeLists.txt
+++ b/libc/src/__support/math/CMakeLists.txt
@@ -3257,7 +3257,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 b5d9ca2331697..cc7394f8e2eee 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -70,6 +70,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 34dab8d05dede..0313b7079826c 100644
--- a/libc/test/src/math/exhaustive/CMakeLists.txt
+++ b/libc/test/src/math/exhaustive/CMakeLists.txt
@@ -749,7 +749,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 075db03922d57..0f111c5dcc27e 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -240,7 +240,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 611d78455dc98..2ff8f77d27d08 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
@@ -45,7 +45,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 cdd60f510436f..92ac58d9fd6ba 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 5de8b1e04be313ba4388eda0cd273e2ea2d341ec 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 +
 .../include/llvm-libc-macros/float16-macros.h | 19 ++++++-------------
 .../CPP/type_traits/is_floating_point.h       |  6 +-----
 libc/src/__support/FPUtil/float16.h           |  5 +++++
 libc/src/__support/macros/properties/types.h  | 19 ++++++++-----------
 libc/src/__support/math/fabsf16.h             | 14 +++++++-------
 libc/src/math/fabsf16.h                       |  5 +++++
 libc/test/src/__support/FPUtil/CMakeLists.txt |  2 ++
 .../FPUtil/comparison_operations_test.cpp     |  1 +
 .../__support/FPUtil/dyadic_float_test.cpp    |  1 +
 .../src/__support/FPUtil/float16_test.cpp     |  9 ++++-----
 .../test/src/math/exhaustive/float16_test.cpp |  4 ++--
 libc/test/src/math/smoke/fabsf16_test.cpp     |  4 ++++
 libc/utils/MPFRWrapper/MPCommon.cpp           |  4 +---
 libc/utils/MPFRWrapper/MPCommon.h             | 15 ++++++---------
 libc/utils/MPFRWrapper/MPFRUtils.cpp          |  2 +-
 25 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt
index 9a296693e22eb..a7f46be553c32 100644
--- a/libc/config/baremetal/aarch64/entrypoints.txt
+++ b/libc/config/baremetal/aarch64/entrypoints.txt
@@ -400,6 +400,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
@@ -656,7 +657,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 7ac1a9ce0d35f..d829c34984a74 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -412,6 +412,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
@@ -668,7 +669,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 9dbaf71d285ee..3703c56464876 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -408,6 +408,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
@@ -664,7 +665,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 ba397e2958cae..d5dce30feb851 100644
--- a/libc/config/darwin/aarch64/entrypoints.txt
+++ b/libc/config/darwin/aarch64/entrypoints.txt
@@ -219,6 +219,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
@@ -476,7 +477,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 2bb022667dd09..2ece6042717b8 100644
--- a/libc/config/freebsd/x86_64/entrypoints.txt
+++ b/libc/config/freebsd/x86_64/entrypoints.txt
@@ -155,6 +155,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
@@ -426,7 +427,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 0c810752c06d7..3ae620fa79bee 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -569,6 +569,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
@@ -815,7 +816,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 9954b09b44af9..9147816beec98 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -392,6 +392,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 842dc0e48cf23..0079f3c115302 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -634,6 +634,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
@@ -898,7 +899,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 7a2dc6a4283b0..e669f33212ca0 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -643,6 +643,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
@@ -907,7 +908,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 2a9d0a81b82f8..1654edc78297d 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -187,6 +187,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 6ba31abd93df3..9e20528ad7120 100644
--- a/libc/include/llvm-libc-macros/float16-macros.h
+++ b/libc/include/llvm-libc-macros/float16-macros.h
@@ -11,25 +11,18 @@
 
 #include "../llvm-libc-types/float128.h"
 
-#if (defined(__arm__) && defined(_M_ARM)) || defined(__riscv)
-#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__) &&         \
+#if defined(__FLT16_MANT_DIG__) &&                                             \
     (!defined(__GNUC__) || __GNUC__ >= 13 ||                                   \
      (defined(__clang__) && __clang_major__ >= 12)) &&                         \
-    !defined(__riscv) && !defined(_WIN32)
+    !defined(__arm__) && !defined(_M_ARM) && !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_NATIVE_FLOAT128
+#if defined(LIBC_TYPES_HAS_FLOAT16) && defined(LIBC_TYPES_HAS_NATIVE_FLOAT128)
 #define LIBC_TYPES_HAS_FLOAT16_AND_FLOAT128
-#endif // LIBC_TYPES_HAS_NATIVE_FLOAT128
-#endif
+#endif // LIBC_TYPES_HAS_FLOAT16 && LIBC_TYPES_HAS_NATIVE_FLOAT128
 
 #endif // LLVM_LIBC_MACROS_FLOAT16_MACROS_H
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 973fd9909b244..d64f8784db0d8 100644
--- a/libc/src/__support/CPP/type_traits/is_floating_point.h
+++ b/libc/src/__support/CPP/type_traits/is_floating_point.h
@@ -41,11 +41,7 @@ template <typename T> struct is_floating_point {
                               float128
 #endif
                               ,
-                              bfloat16
-                              ,
-                              fputil::Float16
-                              ,
-                              fputil::Float128
+                              bfloat16, fputil::Float16, fputil::Float128
 
                               ,
                               fputil::Float80>();
diff --git a/libc/src/__support/FPUtil/float16.h b/libc/src/__support/FPUtil/float16.h
index d1c0981bc240e..58672b6f24e74 100644
--- a/libc/src/__support/FPUtil/float16.h
+++ b/libc/src/__support/FPUtil/float16.h
@@ -29,6 +29,11 @@ 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/macros/properties/types.h b/libc/src/__support/macros/properties/types.h
index 86276cd9365dc..82aa6db59e89a 100644
--- a/libc/src/__support/macros/properties/types.h
+++ b/libc/src/__support/macros/properties/types.h
@@ -69,23 +69,20 @@
 // -- float16 support ---------------------------------------------------------
 // LIBC_TYPES_HAS_FLOAT16 is provided by
 // "include/llvm-libc-macros/float16-macros.h"
+#ifdef LIBC_TYPES_HAS_FLOAT16
+// Type alias for internal use.
+using float16 = _Float16;
+#endif // LIBC_TYPES_HAS_FLOAT16
+
+// -- Emulated float16 support ------------------------------------------------
+// Float16 is always available regardless of built-in float16 type support in
+// the compiler.
 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.
-using float16 = _Float16;
-#endif
-
-#endif // LIBC_TYPES_HAS_FLOAT16
-
 // -- float128 support --------------------------------------------------------
 // LIBC_TYPES_HAS_NATIVE_FLOAT128 and 'float128' type are provided by
 // "include/llvm-libc-types/float128.h"
diff --git a/libc/src/__support/math/fabsf16.h b/libc/src/__support/math/fabsf16.h
index 65b786fd77331..9ff447d888da1 100644
--- a/libc/src/__support/math/fabsf16.h
+++ b/libc/src/__support/math/fabsf16.h
@@ -9,17 +9,19 @@
 #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 {
+
+#ifndef LIBC_TYPES_HAS_FLOAT16
+using float16 = LIBC_NAMESPACE::fputil::Float16;
+#endif // LIBC_TYPES_HAS_FLOAT16
+
 namespace math {
 
 LIBC_INLINE constexpr float16 fabsf16(float16 x) {
@@ -29,7 +31,7 @@ LIBC_INLINE constexpr float16 fabsf16(float16 x) {
   // 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_USE_SOFT_FLOAT16)
+    defined(LIBC_TYPES_HAS_FLOAT16)
   return __builtin_fabsf16(x);
 #else
   return fputil::abs(x);
@@ -39,6 +41,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/src/math/fabsf16.h b/libc/src/math/fabsf16.h
index f48a51f5ff58e..5876f9c3a48f3 100644
--- a/libc/src/math/fabsf16.h
+++ b/libc/src/math/fabsf16.h
@@ -9,11 +9,16 @@
 #ifndef LLVM_LIBC_SRC_MATH_FABSF16_H
 #define LLVM_LIBC_SRC_MATH_FABSF16_H
 
+#include "src/__support/FPUtil/float16.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/types.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
+#ifndef LIBC_TYPES_HAS_FLOAT16
+using float16 = LIBC_NAMESPACE::fputil::Float16;
+#endif // LIBC_TYPES_HAS_FLOAT16
+
 float16 fabsf16(float16 x);
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index cc7394f8e2eee..c80e0e8af9203 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.
@@ -101,5 +102,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 5b56240222c62..f8f2b4384d9e8 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"
diff --git a/libc/test/src/__support/FPUtil/float16_test.cpp b/libc/test/src/__support/FPUtil/float16_test.cpp
index 203e22c580692..674afd0fefd1c 100644
--- a/libc/test/src/__support/FPUtil/float16_test.cpp
+++ b/libc/test/src/__support/FPUtil/float16_test.cpp
@@ -12,8 +12,7 @@
 #include "utils/MPFRWrapper/MPCommon.h"
 
 using Float16 = LIBC_NAMESPACE::fputil::Float16;
-using LlvmLibcFloat16ConversionTest =
-    LIBC_NAMESPACE::testing::FPTest<Float16>;
+using LlvmLibcFloat16ConversionTest = LIBC_NAMESPACE::testing::FPTest<Float16>;
 
 // range: [0, inf]
 static constexpr uint16_t POS_START = 0x0000U;
@@ -69,9 +68,9 @@ TEST_F(LlvmLibcFloat16ConversionTest, FromInteger) {
 }
 
 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),
+  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) {
diff --git a/libc/test/src/math/exhaustive/float16_test.cpp b/libc/test/src/math/exhaustive/float16_test.cpp
index 3d1ba1ab805a6..ea0eb9547b001 100644
--- a/libc/test/src/math/exhaustive/float16_test.cpp
+++ b/libc/test/src/math/exhaustive/float16_test.cpp
@@ -31,8 +31,8 @@ struct Float16ConversionChecker : public virtual LIBC_NAMESPACE::testing::Test {
       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 Float16 libc_result = cast<Float16>(x);
+      const Float16 mpfr_result = mpfr::MPFRNumber(x).as<Float16>();
 
       const bool correct =
           LIBC_NAMESPACE::testing::getMatcher<
diff --git a/libc/test/src/math/smoke/fabsf16_test.cpp b/libc/test/src/math/smoke/fabsf16_test.cpp
index c7bab4b305f99..33ed262ae0f04 100644
--- a/libc/test/src/math/smoke/fabsf16_test.cpp
+++ b/libc/test/src/math/smoke/fabsf16_test.cpp
@@ -10,4 +10,8 @@
 #include "src/__support/FPUtil/float16.h"
 #include "src/math/fabsf16.h"
 
+#ifndef LIBC_TYPES_HAS_FLOAT16
+using float16 = LIBC_NAMESPACE::fputil::Float16;
+#endif // LIBC_TYPES_HAS_FLOAT16
+
 LIST_FABS_TESTS(float16, LIBC_NAMESPACE::fabsf16)
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index 0393ce6421ca7..a5cb4c41c3c20 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -10,8 +10,8 @@
 
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/FPUtil/bfloat16.h"
-#include "src/__support/FPUtil/float16.h"
 #include "src/__support/FPUtil/cast.h"
+#include "src/__support/FPUtil/float16.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/types.h"
 
@@ -641,11 +641,9 @@ 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 {
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 32a6a3ee47fca..65fcec8f63576 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -65,11 +65,9 @@ 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;
@@ -118,15 +116,14 @@ class MPFRNumber {
   // to float, as the MPFR API does not support float16, thus requiring
   // conversion to a higher-precision format.
   template <typename XType,
-            cpp::enable_if_t<cpp::is_same_v<float, XType>
+            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>
+                    || cpp::is_same_v<float16, XType>
 #endif
-                                 || cpp::is_same_v<bfloat16, XType>,
-                             int> = 0>
+                    || cpp::is_same_v<LIBC_NAMESPACE::fputil::Float16, XType> ||
+                    cpp::is_same_v<bfloat16, XType>,
+                int> = 0>
   explicit MPFRNumber(XType x,
                       unsigned int precision = ExtraPrecision<XType>::VALUE,
                       RoundingMode rounding = RoundingMode::Nearest)
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 92ac58d9fd6ba..3e61031fda3cc 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -11,8 +11,8 @@
 
 #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/float16.h"
 #include "src/__support/FPUtil/fpbits_str.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/properties/types.h"



More information about the libc-commits mailing list