[libc-commits] [libc] Float128 arith operator (PR #187425)
via libc-commits
libc-commits at lists.llvm.org
Wed Mar 18 19:01:22 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libc
Author: None (Emmaliu2006git)
<details>
<summary>Changes</summary>
This patch adds basic arithmetic operators for Float128.
Changes
- Implement +, -, *, / for Float128
- Add constructor taking a float128 value from the unified float128 interface
Tests
- Add tests for arithmetic behavior
- Cover zero and signed zero
- Cover special values (inf, NaN)
Notes
The operators take Float128 operands, perform the computation based on their stored values, and return the result as float128.
This PR is based on #<!-- -->187421
---
Full diff: https://github.com/llvm/llvm-project/pull/187425.diff
5 Files Affected:
- (modified) libc/include/llvm-libc-types/float128.h (+4)
- (modified) libc/src/__support/FPUtil/cast.h (+5-1)
- (added) libc/src/__support/FPUtil/float128.h (+63)
- (modified) libc/test/src/__support/FPUtil/CMakeLists.txt (+14)
- (added) libc/test/src/__support/FPUtil/float128_test.cpp (+185)
``````````diff
diff --git a/libc/include/llvm-libc-types/float128.h b/libc/include/llvm-libc-types/float128.h
index 82ebb79f1f580..a7ae7d80f9d92 100644
--- a/libc/include/llvm-libc-types/float128.h
+++ b/libc/include/llvm-libc-types/float128.h
@@ -31,6 +31,10 @@ typedef __float128 float128;
#elif (LDBL_MANT_DIG == 113)
#define LIBC_TYPES_HAS_FLOAT128
typedef long double float128;
+#else
+#define LIBC_TYPES_HAS_FLOAT128
+#include "src/__support/FPUtil/float128.h"
+typedef LIBC_NAMESPACE::fputil::Float128 float128;
#endif
#endif // LLVM_LIBC_TYPES_FLOAT128_H
diff --git a/libc/src/__support/FPUtil/cast.h b/libc/src/__support/FPUtil/cast.h
index 54c80e862523a..3b02d998e84fd 100644
--- a/libc/src/__support/FPUtil/cast.h
+++ b/libc/src/__support/FPUtil/cast.h
@@ -35,7 +35,11 @@ cast(InType x) {
#if defined(LIBC_TYPES_HAS_FLOAT16) && !defined(__LIBC_USE_FLOAT16_CONVERSION)
|| cpp::is_same_v<OutType, float16> ||
cpp::is_same_v<InType, float16>
-#endif
+#endif
+#if defined(LIBC_TYPES_HAS_FLOAT128)
+ || cpp::is_same_v<OutType, float128> ||
+ cpp::is_same_v<InType, float128>
+#endif
) {
using InFPBits = FPBits<InType>;
using InStorageType = typename InFPBits::StorageType;
diff --git a/libc/src/__support/FPUtil/float128.h b/libc/src/__support/FPUtil/float128.h
new file mode 100644
index 0000000000000..01d258caf1b6e
--- /dev/null
+++ b/libc/src/__support/FPUtil/float128.h
@@ -0,0 +1,63 @@
+//===-- Float128 software wrapper ----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a minimal software-backed Float128 wrapper type used when
+// the host compiler does not provide a native 128-bit floating-point type.
+// The wrapper currently only stores the raw 128-bit representation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT128_H
+#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT128_H
+
+#include "src/__support/uint128.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/FPUtil/cast.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace fputil {
+
+struct Float128 {
+ UInt128 bits = 0;
+
+ constexpr Float128() = default;
+ constexpr explicit Float128(UInt128 value) : bits(value) {}
+ constexpr explicit Float128(float128 v) : bits(cpp::bit_cast<UInt128>(v)) {} //add constructor
+ constexpr UInt128 get_bits() const { return bits;}
+
+ //basic arithmetic operators
+ constexpr LIBC_INLINE float128 operator+(const Float128 &other) const {
+ float128 a = cpp::bit_cast<float128>(bits);
+ float128 b = cpp::bit_cast<float128>(other.bits);
+ return a + b;
+ }
+
+ constexpr LIBC_INLINE float128 operator-(const Float128 &other) const {
+ float128 a = cpp::bit_cast<float128>(bits);
+ float128 b = cpp::bit_cast<float128>(other.bits);
+ return a - b;
+ }
+
+ constexpr LIBC_INLINE float128 operator*(const Float128 &other) const {
+ float128 a = cpp::bit_cast<float128>(bits);
+ float128 b = cpp::bit_cast<float128>(other.bits);
+ return a * b;
+ }
+
+ constexpr LIBC_INLINE float128 operator/(const Float128 &other) const {
+ float128 a = cpp::bit_cast<float128>(bits);
+ float128 b = cpp::bit_cast<float128>(other.bits);
+ return a / b;
+ }
+};
+} // namespace fputil
+}// namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT128_H
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index 81db4ccae44c6..820102fa84238 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -39,6 +39,19 @@ add_fp_unittest(
libc.src.__support.FPUtil.rounding_mode
)
+add_libc_test(
+ float128_test
+ NEED_MPFR
+ SUITE
+ libc-fputil-tests
+ SRCS
+ float128_test.cpp
+ DEPENDS
+ libc.src.__support.FPUtil.cast
+ libc.src.__support.FPUtil.fp_bits
+ libc.src.__support.macros.properties.types
+)
+
# TODO: Temporally disable bfloat16 test until MPCommon target is updated
# https://github.com/llvm/llvm-project/pull/149678
if(LLVM_LIBC_FULL_BUILD)
@@ -67,3 +80,4 @@ add_fp_unittest(
libc.src.__support.FPUtil.comparison_operations
libc.src.__support.macros.properties.types
)
+
diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
new file mode 100644
index 0000000000000..614663588d54b
--- /dev/null
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -0,0 +1,185 @@
+//===----------------------------------------------------------------------===//
+// Float128 Tests
+//
+// These tests validate the basic integration of the float128 type with:
+// - type traits (is_floating_point)
+// - FPBits functionality
+// - Float128 casting
+// The goal is to ensure that both the type alias (float128) and the fallback
+// implementation behave consistently with other floating-point types.
+//===----------------------------------------------------------------------===//
+#include "src/__support/FPUtil/cast.h"
+#include "src/__support/macros/properties/types.h"
+#include "test/UnitTest/Test.h"
+#include "src/__support/FPUtil/bfloat16.h"
+#include "src/__support/FPUtil/float128.h"
+
+using LIBC_NAMESPACE::fputil::cast;
+using LIBC_NAMESPACE::fputil::Float128;
+
+// Test: float128 is recognized as a floating-point type.
+TEST(LlvmLibcTypeTraitsTest, Float128IsFloatingPoint) {
+ using LIBC_NAMESPACE::cpp::is_floating_point_v;
+
+ EXPECT_TRUE(is_floating_point_v<float128>);
+}
+
+// Test: Basic FPBits usage with float128 default initialization.
+// Verifies zero initialization and basic classification APIs.
+TEST(LlvmLibcFPBitsTest, Float128BasicUsage) {
+ using LIBC_NAMESPACE::fputil::FPBits;
+
+ float128 x{}; // Default-initialized to zero
+ FPBits<float128> bits(x);
+
+ EXPECT_TRUE(bits.is_zero());
+ EXPECT_TRUE(bits.is_finite());
+ EXPECT_FALSE(bits.is_nan());
+ EXPECT_FALSE(bits.is_inf());
+}
+
+// Test: Construct FPBits<float128> directly from raw bits.
+// Verifies that zero bit pattern is interpreted correctly.
+TEST(LlvmLibcFPBitsTest, Float128FromBits) {
+ using LIBC_NAMESPACE::fputil::FPBits;
+ UInt128 raw = 0;
+ FPBits<float128> bits(raw);
+
+ EXPECT_TRUE(bits.is_zero());
+}
+
+// Test: Special values (infinity and NaN) for float128.
+// Ensures FPBits builders work correctly for float128.
+TEST(LlvmLibcFPBitsTest, Float128SpecialValues) {
+ using LIBC_NAMESPACE::fputil::FPBits;
+
+ auto inf = FPBits<float128>::inf();
+ EXPECT_TRUE(inf.is_inf());
+
+ auto nan = FPBits<float128>::quiet_nan();
+ EXPECT_TRUE(nan.is_nan());
+}
+
+//Test float to float128 casting
+TEST(LlvmLibcCastTest, FloatToFloat128ToFloat) {
+ float x = 1.25f;
+ float128 q = cast<float128>(x);
+ float y = cast<float>(q);
+ EXPECT_TRUE(x == y);
+}
+
+//Test double -> float128 -> double casting
+TEST(LlvmLibcCastTest, DoubleToFloat128ToDouble) {
+ double x = 1.5;
+ float128 q = cast<float128>(x);
+ double y = cast<double>(q);
+ EXPECT_TRUE(x == y);
+}
+
+//Test bfloat16 -> float128 casting
+TEST(LlvmLibcCastTest, bfloat16ToFloat128Tobfloat16) {
+ bfloat16 x = cast<bfloat16>(0.1);
+ float128 q = cast<float128>(x);
+ bfloat16 y = cast<bfloat16>(q);
+ EXPECT_TRUE(x == y);
+}
+
+TEST(LlvmLibcCastTest, RoundingBehavior) {
+ double x = 0.1;
+ float128 q = cast<float128>(x);
+ double y = cast<double>(q);
+ EXPECT_TRUE(x == y);
+}
+
+TEST(LlvmLibcCastTest, ZeroAndNegativeZero) {
+ using LIBC_NAMESPACE::fputil::cast;
+ double pos_zero = 0.0;
+ double neg_zero = -0.0;
+
+ float128 q1 = cast<float128>(pos_zero);
+ float128 q2 = cast<float128>(neg_zero);
+
+ double y1 = cast<double>(q1);
+ double y2 = cast<double>(q2);
+
+ EXPECT_TRUE(y1 == 0.0);
+ EXPECT_TRUE(y2 == 0.0);
+ EXPECT_TRUE(__builtin_signbit(y2) != 0);
+}
+
+TEST(LlvmLibcCastTest, SpecialValues) {
+ using LIBC_NAMESPACE::fputil::cast;
+
+ double inf = __builtin_inf();
+ double nan = __builtin_nan("");
+
+ float128 q_inf = cast<float128>(inf);
+ float128 q_nan = cast<float128>(nan);
+
+ double y_inf = cast<double>(q_inf);
+ double y_nan = cast<double>(q_nan);
+
+ EXPECT_TRUE(__builtin_isinf(y_inf) != 0);
+ EXPECT_TRUE(__builtin_isnan(y_nan) != 0);
+}
+
+//test operators
+TEST(LlvmLibcFloat128Test, BasicArithmetic) {
+ float128 a = cast<float128>(1.5);
+ float128 b = cast<float128>(2.0);
+
+ Float128 x(a);
+ Float128 y(b);
+
+ EXPECT_TRUE((x + y) == cast<float128>(3.5));
+ EXPECT_TRUE((x - y) == cast<float128>(-0.5));
+ EXPECT_TRUE((x * y) == cast<float128>(3.0));
+ EXPECT_TRUE((x / y) == cast<float128>(0.75));
+}
+
+TEST(LlvmLibcFloat128Test, ZeroBehavior) {
+ float128 pos_zero = cast<float128>(0.0);
+ float128 neg_zero = cast<float128>(-0.0);
+
+ Float128 x(pos_zero);
+ Float128 y(neg_zero);
+
+ float128 r1 = x + y;
+ float128 r2 = x - y;
+
+ EXPECT_TRUE(r1 == 0.0);
+ EXPECT_TRUE(r2 == 0.0);
+ EXPECT_TRUE(__builtin_signbit(r2) == 0);
+}
+
+TEST(LlvmLibcFloat128Test, SpecialValues) {
+ float128 inf = cast<float128>(__builtin_inf());
+ float128 nan = cast<float128>(__builtin_nan(""));
+
+ Float128 x(inf);
+ Float128 y(nan);
+
+ EXPECT_TRUE(__builtin_isinf(x + Float128(cast<float128>(1.0))) != 0);
+ EXPECT_TRUE(__builtin_isnan(y + Float128(cast<float128>(1.0))) != 0);
+}
+
+TEST(LlvmLibcFloat128Test, PrecisionSanity) {
+ float128 a = cast<float128>(0.1);
+ float128 b = cast<float128>(0.2);
+
+ Float128 x(a);
+ Float128 y(b);
+
+ float128 r = x + y;
+
+ EXPECT_TRUE(r == a + b);
+}
+
+TEST(LlvmLibcFloat128Test, RoundTripConsistency) {
+ float128 a = cast<float128>(1.25);
+
+ Float128 x(a);
+ float128 r = x + Float128(cast<float128>(0.0));
+
+ EXPECT_TRUE(r == a);
+}
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/187425
More information about the libc-commits
mailing list