[libc-commits] [libc] [libc][math] Fix incorrect logic in fputil::generic::add_or_sub (PR #116129)

via libc-commits libc-commits at lists.llvm.org
Mon Dec 30 10:17:52 PST 2024


https://github.com/overmighty updated https://github.com/llvm/llvm-project/pull/116129

>From 35cb1c494845352b68e14aea97a25b4ca97f85fb Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 14 Nov 2024 01:12:01 +0100
Subject: [PATCH 1/4] [libc][math] Fix incorrect logic in
 fputil::generic::add_or_sub

Fixes incorrect logic that went unnoticed until the function was tested
with output and input types having the same underlying floating-point
format. The resulting DyadicFloat's exponent was off by one when adding
two subnormal numbers, and the minimum operand's mantissa was misaligned
by one bit when adding a normal number with a subnormal number.
---
 libc/src/__support/FPUtil/generic/add_sub.h | 15 ++++++++-------
 libc/test/src/math/smoke/AddTest.h          | 13 ++++++++++++-
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/libc/src/__support/FPUtil/generic/add_sub.h b/libc/src/__support/FPUtil/generic/add_sub.h
index 6bc9dcd23bafad..5c503e752c8ecb 100644
--- a/libc/src/__support/FPUtil/generic/add_sub.h
+++ b/libc/src/__support/FPUtil/generic/add_sub.h
@@ -160,20 +160,21 @@ add_or_sub(InType x, InType y) {
   } else {
     InStorageType max_mant = max_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
     InStorageType min_mant = min_bits.get_explicit_mantissa() << GUARD_BITS_LEN;
-    int alignment =
-        max_bits.get_biased_exponent() - min_bits.get_biased_exponent();
+
+    int alignment = (max_bits.get_biased_exponent() - max_bits.is_normal()) -
+                    (min_bits.get_biased_exponent() - min_bits.is_normal());
 
     InStorageType aligned_min_mant =
         min_mant >> cpp::min(alignment, RESULT_MANTISSA_LEN);
     bool aligned_min_mant_sticky;
 
-    if (alignment <= 3)
+    if (alignment <= GUARD_BITS_LEN)
       aligned_min_mant_sticky = false;
-    else if (alignment <= InFPBits::FRACTION_LEN + 3)
+    else if (alignment > InFPBits::FRACTION_LEN + GUARD_BITS_LEN)
+      aligned_min_mant_sticky = true;
+    else
       aligned_min_mant_sticky =
           (min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
-    else
-      aligned_min_mant_sticky = true;
 
     InStorageType min_mant_sticky(static_cast<int>(aligned_min_mant_sticky));
 
@@ -183,7 +184,7 @@ add_or_sub(InType x, InType y) {
       result_mant = max_mant - (aligned_min_mant | min_mant_sticky);
   }
 
-  int result_exp = max_bits.get_exponent() - RESULT_FRACTION_LEN;
+  int result_exp = max_bits.get_explicit_exponent() - RESULT_FRACTION_LEN;
   DyadicFloat result(result_sign, result_exp, result_mant);
   return result.template as<OutType, /*ShouldSignalExceptions=*/true>();
 }
diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h
index 66b188f4fa7b31..26efff4efaf948 100644
--- a/libc/test/src/math/smoke/AddTest.h
+++ b/libc/test/src/math/smoke/AddTest.h
@@ -136,6 +136,16 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     func(InType(1.0), in.min_denormal);
     EXPECT_FP_EXCEPTION(FE_INEXACT);
   }
+
+  void test_mixed_normality(AddFunc func) {
+    if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() !=
+        LIBC_NAMESPACE::fputil::get_fp_type<InType>())
+      return;
+
+    EXPECT_FP_EQ(FPBits::create_value(Sign::POS, 2U, 0b1U).get_val(),
+                 func(InFPBits::create_value(Sign::POS, 2U, 0U).get_val(),
+                      InFPBits::create_value(Sign::POS, 2U, 0b10U).get_val()));
+  }
 };
 
 #define LIST_ADD_TESTS(OutType, InType, func)                                  \
@@ -145,6 +155,7 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     test_invalid_operations(&func);                                            \
   }                                                                            \
   TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); }           \
-  TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }
+  TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }     \
+  TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
 
 #endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H

>From 082978c607540dc88e8b6a23291f7e19518fbf71 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 20 Nov 2024 21:03:30 +0100
Subject: [PATCH 2/4] Add same type tests

---
 libc/test/src/math/AddTest.h                  | 10 +++---
 libc/test/src/math/CMakeLists.txt             | 27 ++++++++++++++++
 libc/test/src/math/SubTest.h                  | 10 +++---
 libc/test/src/math/add_same_type_test.cpp     | 24 ++++++++++++++
 libc/test/src/math/daddl_test.cpp             |  2 +-
 libc/test/src/math/f16add_test.cpp            |  2 +-
 libc/test/src/math/f16addf_test.cpp           |  2 +-
 libc/test/src/math/f16addl_test.cpp           |  2 +-
 libc/test/src/math/fadd_test.cpp              |  2 +-
 libc/test/src/math/faddl_test.cpp             |  2 +-
 libc/test/src/math/smoke/AddTest.h            | 21 +++++++-----
 libc/test/src/math/smoke/CMakeLists.txt       | 32 +++++++++++++++++++
 libc/test/src/math/smoke/SubTest.h            | 16 ++++++----
 .../src/math/smoke/add_same_type_test.cpp     | 24 ++++++++++++++
 libc/test/src/math/smoke/daddf128_test.cpp    |  2 +-
 libc/test/src/math/smoke/daddl_test.cpp       |  2 +-
 libc/test/src/math/smoke/f16add_test.cpp      |  2 +-
 libc/test/src/math/smoke/f16addf128_test.cpp  |  2 +-
 libc/test/src/math/smoke/f16addf_test.cpp     |  2 +-
 libc/test/src/math/smoke/f16addl_test.cpp     |  2 +-
 libc/test/src/math/smoke/fadd_test.cpp        |  2 +-
 libc/test/src/math/smoke/faddf128_test.cpp    |  2 +-
 libc/test/src/math/smoke/faddl_test.cpp       |  2 +-
 .../src/math/smoke/sub_same_type_test.cpp     | 24 ++++++++++++++
 libc/test/src/math/sub_same_type_test.cpp     | 24 ++++++++++++++
 25 files changed, 205 insertions(+), 37 deletions(-)
 create mode 100644 libc/test/src/math/add_same_type_test.cpp
 create mode 100644 libc/test/src/math/smoke/add_same_type_test.cpp
 create mode 100644 libc/test/src/math/smoke/sub_same_type_test.cpp
 create mode 100644 libc/test/src/math/sub_same_type_test.cpp

diff --git a/libc/test/src/math/AddTest.h b/libc/test/src/math/AddTest.h
index df0ef66cfeefac..09e44dc3c820f2 100644
--- a/libc/test/src/math/AddTest.h
+++ b/libc/test/src/math/AddTest.h
@@ -66,9 +66,11 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_ADD_TESTS(OutType, InType, func)                                  \
-  using LlvmLibcAddTest = AddTest<OutType, InType>;                            \
-  TEST_F(LlvmLibcAddTest, SubnormalRange) { test_subnormal_range(&func); }     \
-  TEST_F(LlvmLibcAddTest, NormalRange) { test_normal_range(&func); }
+#define LIST_ADD_TESTS(suffix, OutType, InType, func)                          \
+  using LlvmLibcAddTest##suffix = AddTest<OutType, InType>;                    \
+  TEST_F(LlvmLibcAddTest##suffix, SubnormalRange) {                            \
+    test_subnormal_range(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcAddTest##suffix, NormalRange) { test_normal_range(&func); }
 
 #endif // LLVM_LIBC_TEST_SRC_MATH_ADDTEST_H
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 16e7d4957ba114..bb6d4a44698bd4 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2767,6 +2767,33 @@ add_fp_unittest(
     libc.src.stdlib.srand
 )
 
+add_fp_unittest(
+  add_same_type_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    add_same_type_test.cpp
+  HDRS
+    AddTest.h
+  DEPENDS
+    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.macros.properties.types
+)
+
+add_fp_unittest(
+  sub_same_type_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    sub_same_type_test.cpp
+  HDRS
+    SubTest.h
+  DEPENDS
+    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.macros.properties.types
+)
 
 add_subdirectory(generic)
 add_subdirectory(smoke)
diff --git a/libc/test/src/math/SubTest.h b/libc/test/src/math/SubTest.h
index 9b4035344b4680..29ad83b796f3b3 100644
--- a/libc/test/src/math/SubTest.h
+++ b/libc/test/src/math/SubTest.h
@@ -66,9 +66,11 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_SUB_TESTS(OutType, InType, func)                                  \
-  using LlvmLibcSubTest = SubTest<OutType, InType>;                            \
-  TEST_F(LlvmLibcSubTest, SubnormalRange) { test_subnormal_range(&func); }     \
-  TEST_F(LlvmLibcSubTest, NormalRange) { test_normal_range(&func); }
+#define LIST_SUB_TESTS(suffix, OutType, InType, func)                          \
+  using LlvmLibcSubTest##suffix = SubTest<OutType, InType>;                    \
+  TEST_F(LlvmLibcSubTest##suffix, SubnormalRange) {                            \
+    test_subnormal_range(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcSubTest##suffix, NormalRange) { test_normal_range(&func); }
 
 #endif // LLVM_LIBC_TEST_SRC_MATH_SUBTEST_H
diff --git a/libc/test/src/math/add_same_type_test.cpp b/libc/test/src/math/add_same_type_test.cpp
new file mode 100644
index 00000000000000..e037fbf0e9c5c4
--- /dev/null
+++ b/libc/test/src/math/add_same_type_test.cpp
@@ -0,0 +1,24 @@
+//===-- Unittests for fputil::generic::add --------------------------------===//
+//
+// 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 "AddTest.h"
+
+#include "src/__support/FPUtil/generic/add_sub.h"
+#include "src/__support/macros/properties/types.h"
+
+#define ADD_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
+
+LIST_ADD_TESTS(Double, double, double, ADD_FUNC(double))
+LIST_ADD_TESTS(Float, float, float, ADD_FUNC(float))
+LIST_ADD_TESTS(LongDouble, long double, long double, ADD_FUNC(long double))
+#ifdef LIBC_TYPES_HAS_FLOAT16
+LIST_ADD_TESTS(Float16, float16, float16, ADD_FUNC(float16))
+#endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_ADD_TESTS(Float128, float128, float128, ADD_FUNC(float128))
+#endif
diff --git a/libc/test/src/math/daddl_test.cpp b/libc/test/src/math/daddl_test.cpp
index 7a34d962d52072..1746b488abc3fc 100644
--- a/libc/test/src/math/daddl_test.cpp
+++ b/libc/test/src/math/daddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddl.h"
 
-LIST_ADD_TESTS(double, long double, LIBC_NAMESPACE::daddl)
+LIST_ADD_TESTS(DoubleLongDouble, double, long double, LIBC_NAMESPACE::daddl)
diff --git a/libc/test/src/math/f16add_test.cpp b/libc/test/src/math/f16add_test.cpp
index c47ece2a925551..8e7a9a3f32ffc0 100644
--- a/libc/test/src/math/f16add_test.cpp
+++ b/libc/test/src/math/f16add_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16add.h"
 
-LIST_ADD_TESTS(float16, double, LIBC_NAMESPACE::f16add)
+LIST_ADD_TESTS(Float16Double, float16, double, LIBC_NAMESPACE::f16add)
diff --git a/libc/test/src/math/f16addf_test.cpp b/libc/test/src/math/f16addf_test.cpp
index 1e8b4323114adc..45d2bfbe491e1d 100644
--- a/libc/test/src/math/f16addf_test.cpp
+++ b/libc/test/src/math/f16addf_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf.h"
 
-LIST_ADD_TESTS(float16, float, LIBC_NAMESPACE::f16addf)
+LIST_ADD_TESTS(Float16Float, float16, float, LIBC_NAMESPACE::f16addf)
diff --git a/libc/test/src/math/f16addl_test.cpp b/libc/test/src/math/f16addl_test.cpp
index f8e0d9ba6b4dec..7737938fec26b2 100644
--- a/libc/test/src/math/f16addl_test.cpp
+++ b/libc/test/src/math/f16addl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addl.h"
 
-LIST_ADD_TESTS(float16, long double, LIBC_NAMESPACE::f16addl)
+LIST_ADD_TESTS(Float16LongDouble, float16, long double, LIBC_NAMESPACE::f16addl)
diff --git a/libc/test/src/math/fadd_test.cpp b/libc/test/src/math/fadd_test.cpp
index fe9ac8b252ed35..e11251cde78a22 100644
--- a/libc/test/src/math/fadd_test.cpp
+++ b/libc/test/src/math/fadd_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/fadd.h"
 
-LIST_ADD_TESTS(float, double, LIBC_NAMESPACE::fadd)
+LIST_ADD_TESTS(FloatDouble, float, double, LIBC_NAMESPACE::fadd)
diff --git a/libc/test/src/math/faddl_test.cpp b/libc/test/src/math/faddl_test.cpp
index 9c99b32ee7c422..c0a15048cd49fc 100644
--- a/libc/test/src/math/faddl_test.cpp
+++ b/libc/test/src/math/faddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddl.h"
 
-LIST_ADD_TESTS(float, long double, LIBC_NAMESPACE::faddl)
+LIST_ADD_TESTS(FloatLongDouble, float, long double, LIBC_NAMESPACE::faddl)
diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h
index 26efff4efaf948..670859fb410378 100644
--- a/libc/test/src/math/smoke/AddTest.h
+++ b/libc/test/src/math/smoke/AddTest.h
@@ -11,7 +11,6 @@
 
 #include "hdr/errno_macros.h"
 #include "hdr/fenv_macros.h"
-#include "src/__support/FPUtil/BasicOperations.h"
 #include "src/__support/macros/properties/os.h"
 #include "test/UnitTest/FEnvSafeTest.h"
 #include "test/UnitTest/FPMatcher.h"
@@ -148,14 +147,20 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_ADD_TESTS(OutType, InType, func)                                  \
-  using LlvmLibcAddTest = AddTest<OutType, InType>;                            \
-  TEST_F(LlvmLibcAddTest, SpecialNumbers) { test_special_numbers(&func); }     \
-  TEST_F(LlvmLibcAddTest, InvalidOperations) {                                 \
+#define LIST_ADD_TESTS(suffix, OutType, InType, func)                          \
+  using LlvmLibcAddTest##suffix = AddTest<OutType, InType>;                    \
+  TEST_F(LlvmLibcAddTest##suffix, SpecialNumbers) {                            \
+    test_special_numbers(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcAddTest##suffix, InvalidOperations) {                         \
     test_invalid_operations(&func);                                            \
   }                                                                            \
-  TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); }           \
-  TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }     \
-  TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
+  TEST_F(LlvmLibcAddTest##suffix, RangeErrors) { test_range_errors(&func); }   \
+  TEST_F(LlvmLibcAddTest##suffix, InexactResults) {                            \
+    test_inexact_results(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcAddTest##suffix, MixedNormality) {                            \
+    test_mixed_normality(&func);                                               \
+  }
 
 #endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ADDTEST_H
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 31f85a3ecfd27b..86576cc4d0be44 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -5124,3 +5124,35 @@ add_fp_unittest(
   DEPENDS
     libc.src.math.ddivf128
 )
+
+add_fp_unittest(
+  add_same_type_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    add_same_type_test.cpp
+  HDRS
+    AddTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.macros.properties.os
+    libc.src.__support.macros.properties.types
+)
+
+add_fp_unittest(
+  sub_same_type_test
+  SUITE
+    libc-math-smoke-tests
+  SRCS
+    sub_same_type_test.cpp
+  HDRS
+    SubTest.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.fenv_macros
+    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.macros.properties.os
+    libc.src.__support.macros.properties.types
+)
diff --git a/libc/test/src/math/smoke/SubTest.h b/libc/test/src/math/smoke/SubTest.h
index ca952009c87c6a..56173f6af157fe 100644
--- a/libc/test/src/math/smoke/SubTest.h
+++ b/libc/test/src/math/smoke/SubTest.h
@@ -138,13 +138,17 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_SUB_TESTS(OutType, InType, func)                                  \
-  using LlvmLibcSubTest = SubTest<OutType, InType>;                            \
-  TEST_F(LlvmLibcSubTest, SpecialNumbers) { test_special_numbers(&func); }     \
-  TEST_F(LlvmLibcSubTest, InvalidOperations) {                                 \
+#define LIST_SUB_TESTS(suffix, OutType, InType, func)                          \
+  using LlvmLibcSubTest##suffix = SubTest<OutType, InType>;                    \
+  TEST_F(LlvmLibcSubTest##suffix, SpecialNumbers) {                            \
+    test_special_numbers(&func);                                               \
+  }                                                                            \
+  TEST_F(LlvmLibcSubTest##suffix, InvalidOperations) {                         \
     test_invalid_operations(&func);                                            \
   }                                                                            \
-  TEST_F(LlvmLibcSubTest, RangeErrors) { test_range_errors(&func); }           \
-  TEST_F(LlvmLibcSubTest, InexactResults) { test_inexact_results(&func); }
+  TEST_F(LlvmLibcSubTest##suffix, RangeErrors) { test_range_errors(&func); }   \
+  TEST_F(LlvmLibcSubTest##suffix, InexactResults) {                            \
+    test_inexact_results(&func);                                               \
+  }
 
 #endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_SUBTEST_H
diff --git a/libc/test/src/math/smoke/add_same_type_test.cpp b/libc/test/src/math/smoke/add_same_type_test.cpp
new file mode 100644
index 00000000000000..e037fbf0e9c5c4
--- /dev/null
+++ b/libc/test/src/math/smoke/add_same_type_test.cpp
@@ -0,0 +1,24 @@
+//===-- Unittests for fputil::generic::add --------------------------------===//
+//
+// 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 "AddTest.h"
+
+#include "src/__support/FPUtil/generic/add_sub.h"
+#include "src/__support/macros/properties/types.h"
+
+#define ADD_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
+
+LIST_ADD_TESTS(Double, double, double, ADD_FUNC(double))
+LIST_ADD_TESTS(Float, float, float, ADD_FUNC(float))
+LIST_ADD_TESTS(LongDouble, long double, long double, ADD_FUNC(long double))
+#ifdef LIBC_TYPES_HAS_FLOAT16
+LIST_ADD_TESTS(Float16, float16, float16, ADD_FUNC(float16))
+#endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_ADD_TESTS(Float128, float128, float128, ADD_FUNC(float128))
+#endif
diff --git a/libc/test/src/math/smoke/daddf128_test.cpp b/libc/test/src/math/smoke/daddf128_test.cpp
index ca0bbffe734513..d6ab36aa9169d9 100644
--- a/libc/test/src/math/smoke/daddf128_test.cpp
+++ b/libc/test/src/math/smoke/daddf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddf128.h"
 
-LIST_ADD_TESTS(double, float128, LIBC_NAMESPACE::daddf128)
+LIST_ADD_TESTS(DoubleFloat128, double, float128, LIBC_NAMESPACE::daddf128)
diff --git a/libc/test/src/math/smoke/daddl_test.cpp b/libc/test/src/math/smoke/daddl_test.cpp
index 7a34d962d52072..1746b488abc3fc 100644
--- a/libc/test/src/math/smoke/daddl_test.cpp
+++ b/libc/test/src/math/smoke/daddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddl.h"
 
-LIST_ADD_TESTS(double, long double, LIBC_NAMESPACE::daddl)
+LIST_ADD_TESTS(DoubleLongDouble, double, long double, LIBC_NAMESPACE::daddl)
diff --git a/libc/test/src/math/smoke/f16add_test.cpp b/libc/test/src/math/smoke/f16add_test.cpp
index c47ece2a925551..8e7a9a3f32ffc0 100644
--- a/libc/test/src/math/smoke/f16add_test.cpp
+++ b/libc/test/src/math/smoke/f16add_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16add.h"
 
-LIST_ADD_TESTS(float16, double, LIBC_NAMESPACE::f16add)
+LIST_ADD_TESTS(Float16Double, float16, double, LIBC_NAMESPACE::f16add)
diff --git a/libc/test/src/math/smoke/f16addf128_test.cpp b/libc/test/src/math/smoke/f16addf128_test.cpp
index 8ed123b4ff1e85..f630854bcbaa9d 100644
--- a/libc/test/src/math/smoke/f16addf128_test.cpp
+++ b/libc/test/src/math/smoke/f16addf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf128.h"
 
-LIST_ADD_TESTS(float16, float128, LIBC_NAMESPACE::f16addf128)
+LIST_ADD_TESTS(Float16Float128, float16, float128, LIBC_NAMESPACE::f16addf128)
diff --git a/libc/test/src/math/smoke/f16addf_test.cpp b/libc/test/src/math/smoke/f16addf_test.cpp
index 1e8b4323114adc..45d2bfbe491e1d 100644
--- a/libc/test/src/math/smoke/f16addf_test.cpp
+++ b/libc/test/src/math/smoke/f16addf_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf.h"
 
-LIST_ADD_TESTS(float16, float, LIBC_NAMESPACE::f16addf)
+LIST_ADD_TESTS(Float16Float, float16, float, LIBC_NAMESPACE::f16addf)
diff --git a/libc/test/src/math/smoke/f16addl_test.cpp b/libc/test/src/math/smoke/f16addl_test.cpp
index f8e0d9ba6b4dec..7737938fec26b2 100644
--- a/libc/test/src/math/smoke/f16addl_test.cpp
+++ b/libc/test/src/math/smoke/f16addl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addl.h"
 
-LIST_ADD_TESTS(float16, long double, LIBC_NAMESPACE::f16addl)
+LIST_ADD_TESTS(Float16LongDouble, float16, long double, LIBC_NAMESPACE::f16addl)
diff --git a/libc/test/src/math/smoke/fadd_test.cpp b/libc/test/src/math/smoke/fadd_test.cpp
index fe9ac8b252ed35..e11251cde78a22 100644
--- a/libc/test/src/math/smoke/fadd_test.cpp
+++ b/libc/test/src/math/smoke/fadd_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/fadd.h"
 
-LIST_ADD_TESTS(float, double, LIBC_NAMESPACE::fadd)
+LIST_ADD_TESTS(FloatDouble, float, double, LIBC_NAMESPACE::fadd)
diff --git a/libc/test/src/math/smoke/faddf128_test.cpp b/libc/test/src/math/smoke/faddf128_test.cpp
index 5a11b5f419cad2..7a3f7fd3afe3c1 100644
--- a/libc/test/src/math/smoke/faddf128_test.cpp
+++ b/libc/test/src/math/smoke/faddf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddf128.h"
 
-LIST_ADD_TESTS(float, float128, LIBC_NAMESPACE::faddf128)
+LIST_ADD_TESTS(FloatFloat128, float, float128, LIBC_NAMESPACE::faddf128)
diff --git a/libc/test/src/math/smoke/faddl_test.cpp b/libc/test/src/math/smoke/faddl_test.cpp
index 9c99b32ee7c422..c0a15048cd49fc 100644
--- a/libc/test/src/math/smoke/faddl_test.cpp
+++ b/libc/test/src/math/smoke/faddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddl.h"
 
-LIST_ADD_TESTS(float, long double, LIBC_NAMESPACE::faddl)
+LIST_ADD_TESTS(FloatLongDouble, float, long double, LIBC_NAMESPACE::faddl)
diff --git a/libc/test/src/math/smoke/sub_same_type_test.cpp b/libc/test/src/math/smoke/sub_same_type_test.cpp
new file mode 100644
index 00000000000000..180493d8447446
--- /dev/null
+++ b/libc/test/src/math/smoke/sub_same_type_test.cpp
@@ -0,0 +1,24 @@
+//===-- Unittests for fputil::generic::sub --------------------------------===//
+//
+// 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 "SubTest.h"
+
+#include "src/__support/FPUtil/generic/add_sub.h"
+#include "src/__support/macros/properties/types.h"
+
+#define SUB_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
+
+LIST_SUB_TESTS(Double, double, double, SUB_FUNC(double))
+LIST_SUB_TESTS(Float, float, float, SUB_FUNC(float))
+LIST_SUB_TESTS(LongDouble, long double, long double, SUB_FUNC(long double))
+#ifdef LIBC_TYPES_HAS_FLOAT16
+LIST_SUB_TESTS(Float16, float16, float16, SUB_FUNC(float16))
+#endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_SUB_TESTS(Float128, float128, float128, SUB_FUNC(float128))
+#endif
diff --git a/libc/test/src/math/sub_same_type_test.cpp b/libc/test/src/math/sub_same_type_test.cpp
new file mode 100644
index 00000000000000..04e1cbedb83a64
--- /dev/null
+++ b/libc/test/src/math/sub_same_type_test.cpp
@@ -0,0 +1,24 @@
+//===-- Unittests for fputil::generic::sub --------------------------------===//
+//
+// 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 "SubTest.h"
+
+#include "src/__support/FPUtil/generic/add_sub.h"
+#include "src/__support/macros/properties/types.h"
+
+#define SUB_FUNC(T) (LIBC_NAMESPACE::fputil::generic::sub<T, T>)
+
+LIST_SUB_TESTS(Double, double, double, SUB_FUNC(double))
+LIST_SUB_TESTS(Float, float, float, SUB_FUNC(float))
+LIST_SUB_TESTS(LongDouble, long double, long double, SUB_FUNC(long double))
+#ifdef LIBC_TYPES_HAS_FLOAT16
+LIST_SUB_TESTS(Float16, float16, float16, SUB_FUNC(float16))
+#endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_SUB_TESTS(Float128, float128, float128, SUB_FUNC(float128))
+#endif

>From dd65a0b3a46d85a02d18f0014bf3903d8249be58 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Thu, 19 Dec 2024 20:31:04 +0100
Subject: [PATCH 3/4] Fix remaining issues

---
 .../__support/FPUtil/generic/CMakeLists.txt   |  1 -
 libc/src/__support/FPUtil/generic/add_sub.h   | 12 ++----
 libc/test/src/math/AddTest.h                  | 41 ++++++++++++-------
 libc/test/src/math/CMakeLists.txt             |  6 ++-
 libc/test/src/math/SubTest.h                  | 39 +++++++++++-------
 libc/test/src/math/add_same_type_test.cpp     | 12 +++---
 libc/test/src/math/daddl_test.cpp             |  2 +-
 libc/test/src/math/f16add_test.cpp            |  2 +-
 libc/test/src/math/f16addf_test.cpp           |  2 +-
 libc/test/src/math/f16addl_test.cpp           |  2 +-
 libc/test/src/math/fadd_test.cpp              |  2 +-
 libc/test/src/math/faddl_test.cpp             |  2 +-
 libc/test/src/math/smoke/AddTest.h            | 18 +++++++-
 libc/test/src/math/smoke/CMakeLists.txt       |  4 +-
 libc/test/src/math/smoke/SubTest.h            | 15 ++++++-
 .../src/math/smoke/add_same_type_test.cpp     | 11 ++---
 libc/test/src/math/smoke/daddf128_test.cpp    |  2 +-
 libc/test/src/math/smoke/daddl_test.cpp       |  2 +-
 libc/test/src/math/smoke/f16add_test.cpp      |  2 +-
 libc/test/src/math/smoke/f16addf128_test.cpp  |  2 +-
 libc/test/src/math/smoke/f16addf_test.cpp     |  2 +-
 libc/test/src/math/smoke/f16addl_test.cpp     |  2 +-
 libc/test/src/math/smoke/fadd_test.cpp        |  2 +-
 libc/test/src/math/smoke/faddf128_test.cpp    |  2 +-
 libc/test/src/math/smoke/faddl_test.cpp       |  2 +-
 .../src/math/smoke/sub_same_type_test.cpp     | 13 +++---
 libc/test/src/math/sub_same_type_test.cpp     | 12 +++---
 27 files changed, 129 insertions(+), 85 deletions(-)

diff --git a/libc/src/__support/FPUtil/generic/CMakeLists.txt b/libc/src/__support/FPUtil/generic/CMakeLists.txt
index 60434d6f6f11ab..117213fc2c59fa 100644
--- a/libc/src/__support/FPUtil/generic/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/generic/CMakeLists.txt
@@ -56,7 +56,6 @@ add_header_library(
   HDRS
     add_sub.h
   DEPENDS
-    libc.hdr.errno_macros
     libc.hdr.fenv_macros
     libc.src.__support.CPP.algorithm
     libc.src.__support.CPP.bit
diff --git a/libc/src/__support/FPUtil/generic/add_sub.h b/libc/src/__support/FPUtil/generic/add_sub.h
index 5c503e752c8ecb..fda702931ef6ff 100644
--- a/libc/src/__support/FPUtil/generic/add_sub.h
+++ b/libc/src/__support/FPUtil/generic/add_sub.h
@@ -9,7 +9,6 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_SUB_H
 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GENERIC_ADD_SUB_H
 
-#include "hdr/errno_macros.h"
 #include "hdr/fenv_macros.h"
 #include "src/__support/CPP/algorithm.h"
 #include "src/__support/CPP/bit.h"
@@ -110,12 +109,8 @@ add_or_sub(InType x, InType y) {
       return cast<OutType>(tmp);
     }
 
-    if (y_bits.is_zero()) {
-      volatile InType tmp = y;
-      if constexpr (IsSub)
-        tmp = -tmp;
-      return cast<OutType>(tmp);
-    }
+    if (y_bits.is_zero())
+      return cast<OutType>(x);
   }
 
   InType x_abs = x_bits.abs().get_val();
@@ -174,7 +169,8 @@ add_or_sub(InType x, InType y) {
       aligned_min_mant_sticky = true;
     else
       aligned_min_mant_sticky =
-          (min_mant << (InFPBits::STORAGE_LEN - alignment)) != 0;
+          (static_cast<InStorageType>(
+              min_mant << (InFPBits::STORAGE_LEN - alignment))) != 0;
 
     InStorageType min_mant_sticky(static_cast<int>(aligned_min_mant_sticky));
 
diff --git a/libc/test/src/math/AddTest.h b/libc/test/src/math/AddTest.h
index 09e44dc3c820f2..370cc2bbde8b37 100644
--- a/libc/test/src/math/AddTest.h
+++ b/libc/test/src/math/AddTest.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_ADDTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_ADDTEST_H
 
+#include "src/__support/CPP/algorithm.h"
 #include "test/UnitTest/FEnvSafeTest.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
@@ -36,16 +37,19 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
       InFPBits::min_subnormal().uintval();
 
 public:
-  typedef OutType (*AddFunc)(InType, InType);
+  using AddFunc = OutType (*)(InType, InType);
 
   void test_subnormal_range(AddFunc func) {
-    constexpr InStorageType COUNT = 100'001;
-    constexpr InStorageType STEP =
-        (IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT;
-    for (InStorageType i = 0, v = 0, w = IN_MAX_SUBNORMAL_U; i <= COUNT;
-         ++i, v += STEP, w -= STEP) {
-      InType x = InFPBits(v).get_val();
-      InType y = InFPBits(w).get_val();
+    constexpr int COUNT = 100'001;
+    constexpr InStorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<InStorageType>((IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) /
+                                   COUNT),
+        InStorageType(1));
+    for (InStorageType i = IN_MIN_SUBNORMAL_U; i <= IN_MAX_SUBNORMAL_U;
+         i += STEP) {
+      InType x = InFPBits(i).get_val();
+      InType y = InFPBits(static_cast<InStorageType>(IN_MAX_SUBNORMAL_U - i))
+                     .get_val();
       mpfr::BinaryInput<InType> input{x, y};
       EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Add, input, func(x, y),
                                      0.5);
@@ -53,12 +57,14 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 
   void test_normal_range(AddFunc func) {
-    constexpr InStorageType COUNT = 100'001;
-    constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT;
-    for (InStorageType i = 0, v = 0, w = IN_MAX_NORMAL_U; i <= COUNT;
-         ++i, v += STEP, w -= STEP) {
-      InType x = InFPBits(v).get_val();
-      InType y = InFPBits(w).get_val();
+    constexpr int COUNT = 100'001;
+    constexpr InStorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<InStorageType>((IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT),
+        InStorageType(1));
+    for (InStorageType i = IN_MIN_NORMAL_U; i <= IN_MAX_NORMAL_U; i += STEP) {
+      InType x = InFPBits(i).get_val();
+      InType y =
+          InFPBits(static_cast<InStorageType>(IN_MAX_NORMAL_U - i)).get_val();
       mpfr::BinaryInput<InType> input{x, y};
       EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Add, input, func(x, y),
                                      0.5);
@@ -66,7 +72,12 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_ADD_TESTS(suffix, OutType, InType, func)                          \
+#define LIST_ADD_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcAddTest = AddTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcAddTest, SubnormalRange) { test_subnormal_range(&func); }     \
+  TEST_F(LlvmLibcAddTest, NormalRange) { test_normal_range(&func); }
+
+#define LIST_ADD_SAME_TYPE_TESTS(suffix, OutType, InType, func)                \
   using LlvmLibcAddTest##suffix = AddTest<OutType, InType>;                    \
   TEST_F(LlvmLibcAddTest##suffix, SubnormalRange) {                            \
     test_subnormal_range(&func);                                               \
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index bb6d4a44698bd4..9f713635f19b0d 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2777,7 +2777,8 @@ add_fp_unittest(
   HDRS
     AddTest.h
   DEPENDS
-    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.generic.add_sub
     libc.src.__support.macros.properties.types
 )
 
@@ -2791,7 +2792,8 @@ add_fp_unittest(
   HDRS
     SubTest.h
   DEPENDS
-    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.generic.add_sub
     libc.src.__support.macros.properties.types
 )
 
diff --git a/libc/test/src/math/SubTest.h b/libc/test/src/math/SubTest.h
index 29ad83b796f3b3..b799d78515fa47 100644
--- a/libc/test/src/math/SubTest.h
+++ b/libc/test/src/math/SubTest.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_SUBTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_SUBTEST_H
 
+#include "src/__support/CPP/algorithm.h"
 #include "test/UnitTest/FEnvSafeTest.h"
 #include "test/UnitTest/FPMatcher.h"
 #include "test/UnitTest/Test.h"
@@ -39,13 +40,16 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   using SubFunc = OutType (*)(InType, InType);
 
   void test_subnormal_range(SubFunc func) {
-    constexpr InStorageType COUNT = 100'001;
-    constexpr InStorageType STEP =
-        (IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) / COUNT;
-    for (InStorageType i = 0, v = 0, w = IN_MAX_SUBNORMAL_U; i <= COUNT;
-         ++i, v += STEP, w -= STEP) {
-      InType x = InFPBits(v).get_val();
-      InType y = InFPBits(w).get_val();
+    constexpr int COUNT = 100'001;
+    constexpr InStorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<InStorageType>((IN_MAX_SUBNORMAL_U - IN_MIN_SUBNORMAL_U) /
+                                   COUNT),
+        InStorageType(1));
+    for (InStorageType i = IN_MIN_SUBNORMAL_U; i <= IN_MAX_SUBNORMAL_U;
+         i += STEP) {
+      InType x = InFPBits(i).get_val();
+      InType y = InFPBits(static_cast<InStorageType>(IN_MAX_SUBNORMAL_U - i))
+                     .get_val();
       mpfr::BinaryInput<InType> input{x, y};
       EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sub, input, func(x, y),
                                      0.5);
@@ -53,12 +57,14 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 
   void test_normal_range(SubFunc func) {
-    constexpr InStorageType COUNT = 100'001;
-    constexpr InStorageType STEP = (IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT;
-    for (InStorageType i = 0, v = 0, w = IN_MAX_NORMAL_U; i <= COUNT;
-         ++i, v += STEP, w -= STEP) {
-      InType x = InFPBits(v).get_val();
-      InType y = InFPBits(w).get_val();
+    constexpr int COUNT = 100'001;
+    constexpr InStorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<InStorageType>((IN_MAX_NORMAL_U - IN_MIN_NORMAL_U) / COUNT),
+        InStorageType(1));
+    for (InStorageType i = IN_MIN_NORMAL_U; i <= IN_MAX_NORMAL_U; i += STEP) {
+      InType x = InFPBits(i).get_val();
+      InType y =
+          InFPBits(static_cast<InStorageType>(IN_MAX_NORMAL_U - i)).get_val();
       mpfr::BinaryInput<InType> input{x, y};
       EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Sub, input, func(x, y),
                                      0.5);
@@ -66,7 +72,12 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_SUB_TESTS(suffix, OutType, InType, func)                          \
+#define LIST_SUB_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcSubTest = SubTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcSubTest, SubnormalRange) { test_subnormal_range(&func); }     \
+  TEST_F(LlvmLibcSubTest, NormalRange) { test_normal_range(&func); }
+
+#define LIST_SUB_SAME_TYPE_TESTS(suffix, OutType, InType, func)                \
   using LlvmLibcSubTest##suffix = SubTest<OutType, InType>;                    \
   TEST_F(LlvmLibcSubTest##suffix, SubnormalRange) {                            \
     test_subnormal_range(&func);                                               \
diff --git a/libc/test/src/math/add_same_type_test.cpp b/libc/test/src/math/add_same_type_test.cpp
index e037fbf0e9c5c4..7ef48ff0800ccc 100644
--- a/libc/test/src/math/add_same_type_test.cpp
+++ b/libc/test/src/math/add_same_type_test.cpp
@@ -13,12 +13,10 @@
 
 #define ADD_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
 
-LIST_ADD_TESTS(Double, double, double, ADD_FUNC(double))
-LIST_ADD_TESTS(Float, float, float, ADD_FUNC(float))
-LIST_ADD_TESTS(LongDouble, long double, long double, ADD_FUNC(long double))
+LIST_ADD_SAME_TYPE_TESTS(Double, double, double, ADD_FUNC(double))
+LIST_ADD_SAME_TYPE_TESTS(Float, float, float, ADD_FUNC(float))
+LIST_ADD_SAME_TYPE_TESTS(LongDouble, long double, long double,
+                         ADD_FUNC(long double))
 #ifdef LIBC_TYPES_HAS_FLOAT16
-LIST_ADD_TESTS(Float16, float16, float16, ADD_FUNC(float16))
-#endif
-#ifdef LIBC_TYPES_HAS_FLOAT128
-LIST_ADD_TESTS(Float128, float128, float128, ADD_FUNC(float128))
+LIST_ADD_SAME_TYPE_TESTS(Float16, float16, float16, ADD_FUNC(float16))
 #endif
diff --git a/libc/test/src/math/daddl_test.cpp b/libc/test/src/math/daddl_test.cpp
index 1746b488abc3fc..7a34d962d52072 100644
--- a/libc/test/src/math/daddl_test.cpp
+++ b/libc/test/src/math/daddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddl.h"
 
-LIST_ADD_TESTS(DoubleLongDouble, double, long double, LIBC_NAMESPACE::daddl)
+LIST_ADD_TESTS(double, long double, LIBC_NAMESPACE::daddl)
diff --git a/libc/test/src/math/f16add_test.cpp b/libc/test/src/math/f16add_test.cpp
index 8e7a9a3f32ffc0..c47ece2a925551 100644
--- a/libc/test/src/math/f16add_test.cpp
+++ b/libc/test/src/math/f16add_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16add.h"
 
-LIST_ADD_TESTS(Float16Double, float16, double, LIBC_NAMESPACE::f16add)
+LIST_ADD_TESTS(float16, double, LIBC_NAMESPACE::f16add)
diff --git a/libc/test/src/math/f16addf_test.cpp b/libc/test/src/math/f16addf_test.cpp
index 45d2bfbe491e1d..1e8b4323114adc 100644
--- a/libc/test/src/math/f16addf_test.cpp
+++ b/libc/test/src/math/f16addf_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf.h"
 
-LIST_ADD_TESTS(Float16Float, float16, float, LIBC_NAMESPACE::f16addf)
+LIST_ADD_TESTS(float16, float, LIBC_NAMESPACE::f16addf)
diff --git a/libc/test/src/math/f16addl_test.cpp b/libc/test/src/math/f16addl_test.cpp
index 7737938fec26b2..f8e0d9ba6b4dec 100644
--- a/libc/test/src/math/f16addl_test.cpp
+++ b/libc/test/src/math/f16addl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addl.h"
 
-LIST_ADD_TESTS(Float16LongDouble, float16, long double, LIBC_NAMESPACE::f16addl)
+LIST_ADD_TESTS(float16, long double, LIBC_NAMESPACE::f16addl)
diff --git a/libc/test/src/math/fadd_test.cpp b/libc/test/src/math/fadd_test.cpp
index e11251cde78a22..fe9ac8b252ed35 100644
--- a/libc/test/src/math/fadd_test.cpp
+++ b/libc/test/src/math/fadd_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/fadd.h"
 
-LIST_ADD_TESTS(FloatDouble, float, double, LIBC_NAMESPACE::fadd)
+LIST_ADD_TESTS(float, double, LIBC_NAMESPACE::fadd)
diff --git a/libc/test/src/math/faddl_test.cpp b/libc/test/src/math/faddl_test.cpp
index c0a15048cd49fc..9c99b32ee7c422 100644
--- a/libc/test/src/math/faddl_test.cpp
+++ b/libc/test/src/math/faddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddl.h"
 
-LIST_ADD_TESTS(FloatLongDouble, float, long double, LIBC_NAMESPACE::faddl)
+LIST_ADD_TESTS(float, long double, LIBC_NAMESPACE::faddl)
diff --git a/libc/test/src/math/smoke/AddTest.h b/libc/test/src/math/smoke/AddTest.h
index 670859fb410378..68a4bbef01a2e9 100644
--- a/libc/test/src/math/smoke/AddTest.h
+++ b/libc/test/src/math/smoke/AddTest.h
@@ -58,6 +58,10 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 #ifndef LIBC_TARGET_OS_IS_WINDOWS
     using namespace LIBC_NAMESPACE::fputil::testing;
 
+    if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() ==
+        LIBC_NAMESPACE::fputil::get_fp_type<InType>())
+      return;
+
     if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
       EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.max_normal),
                                   FE_OVERFLOW | FE_INEXACT);
@@ -143,11 +147,21 @@ class AddTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 
     EXPECT_FP_EQ(FPBits::create_value(Sign::POS, 2U, 0b1U).get_val(),
                  func(InFPBits::create_value(Sign::POS, 2U, 0U).get_val(),
-                      InFPBits::create_value(Sign::POS, 2U, 0b10U).get_val()));
+                      InFPBits::create_value(Sign::POS, 0U, 0b10U).get_val()));
   }
 };
 
-#define LIST_ADD_TESTS(suffix, OutType, InType, func)                          \
+#define LIST_ADD_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcAddTest = AddTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcAddTest, SpecialNumbers) { test_special_numbers(&func); }     \
+  TEST_F(LlvmLibcAddTest, InvalidOperations) {                                 \
+    test_invalid_operations(&func);                                            \
+  }                                                                            \
+  TEST_F(LlvmLibcAddTest, RangeErrors) { test_range_errors(&func); }           \
+  TEST_F(LlvmLibcAddTest, InexactResults) { test_inexact_results(&func); }     \
+  TEST_F(LlvmLibcAddTest, MixedNormality) { test_mixed_normality(&func); }
+
+#define LIST_ADD_SAME_TYPE_TESTS(suffix, OutType, InType, func)                \
   using LlvmLibcAddTest##suffix = AddTest<OutType, InType>;                    \
   TEST_F(LlvmLibcAddTest##suffix, SpecialNumbers) {                            \
     test_special_numbers(&func);                                               \
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 86576cc4d0be44..8f22d0df34100f 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -5136,7 +5136,7 @@ add_fp_unittest(
   DEPENDS
     libc.hdr.errno_macros
     libc.hdr.fenv_macros
-    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.FPUtil.generic.add_sub
     libc.src.__support.macros.properties.os
     libc.src.__support.macros.properties.types
 )
@@ -5152,7 +5152,7 @@ add_fp_unittest(
   DEPENDS
     libc.hdr.errno_macros
     libc.hdr.fenv_macros
-    libc.src.__support.FPUtil.generic.add_or_sub
+    libc.src.__support.FPUtil.generic.add_sub
     libc.src.__support.macros.properties.os
     libc.src.__support.macros.properties.types
 )
diff --git a/libc/test/src/math/smoke/SubTest.h b/libc/test/src/math/smoke/SubTest.h
index 56173f6af157fe..c344db28b7fc65 100644
--- a/libc/test/src/math/smoke/SubTest.h
+++ b/libc/test/src/math/smoke/SubTest.h
@@ -58,6 +58,10 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
 #ifndef LIBC_TARGET_OS_IS_WINDOWS
     using namespace LIBC_NAMESPACE::fputil::testing;
 
+    if (LIBC_NAMESPACE::fputil::get_fp_type<OutType>() ==
+        LIBC_NAMESPACE::fputil::get_fp_type<InType>())
+      return;
+
     if (ForceRoundingMode r(RoundingMode::Nearest); r.success) {
       EXPECT_FP_EQ_WITH_EXCEPTION(inf, func(in.max_normal, in.neg_max_normal),
                                   FE_OVERFLOW | FE_INEXACT);
@@ -138,7 +142,16 @@ class SubTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 };
 
-#define LIST_SUB_TESTS(suffix, OutType, InType, func)                          \
+#define LIST_SUB_TESTS(OutType, InType, func)                                  \
+  using LlvmLibcSubTest = SubTest<OutType, InType>;                            \
+  TEST_F(LlvmLibcSubTest, SpecialNumbers) { test_special_numbers(&func); }     \
+  TEST_F(LlvmLibcSubTest, InvalidOperations) {                                 \
+    test_invalid_operations(&func);                                            \
+  }                                                                            \
+  TEST_F(LlvmLibcSubTest, RangeErrors) { test_range_errors(&func); }           \
+  TEST_F(LlvmLibcSubTest, InexactResults) { test_inexact_results(&func); }
+
+#define LIST_SUB_SAME_TYPE_TESTS(suffix, OutType, InType, func)                \
   using LlvmLibcSubTest##suffix = SubTest<OutType, InType>;                    \
   TEST_F(LlvmLibcSubTest##suffix, SpecialNumbers) {                            \
     test_special_numbers(&func);                                               \
diff --git a/libc/test/src/math/smoke/add_same_type_test.cpp b/libc/test/src/math/smoke/add_same_type_test.cpp
index e037fbf0e9c5c4..13e1e3cbe27713 100644
--- a/libc/test/src/math/smoke/add_same_type_test.cpp
+++ b/libc/test/src/math/smoke/add_same_type_test.cpp
@@ -13,12 +13,13 @@
 
 #define ADD_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
 
-LIST_ADD_TESTS(Double, double, double, ADD_FUNC(double))
-LIST_ADD_TESTS(Float, float, float, ADD_FUNC(float))
-LIST_ADD_TESTS(LongDouble, long double, long double, ADD_FUNC(long double))
+LIST_ADD_SAME_TYPE_TESTS(Double, double, double, ADD_FUNC(double))
+LIST_ADD_SAME_TYPE_TESTS(Float, float, float, ADD_FUNC(float))
+LIST_ADD_SAME_TYPE_TESTS(LongDouble, long double, long double,
+                         ADD_FUNC(long double))
 #ifdef LIBC_TYPES_HAS_FLOAT16
-LIST_ADD_TESTS(Float16, float16, float16, ADD_FUNC(float16))
+LIST_ADD_SAME_TYPE_TESTS(Float16, float16, float16, ADD_FUNC(float16))
 #endif
 #ifdef LIBC_TYPES_HAS_FLOAT128
-LIST_ADD_TESTS(Float128, float128, float128, ADD_FUNC(float128))
+LIST_ADD_SAME_TYPE_TESTS(Float128, float128, float128, ADD_FUNC(float128))
 #endif
diff --git a/libc/test/src/math/smoke/daddf128_test.cpp b/libc/test/src/math/smoke/daddf128_test.cpp
index d6ab36aa9169d9..ca0bbffe734513 100644
--- a/libc/test/src/math/smoke/daddf128_test.cpp
+++ b/libc/test/src/math/smoke/daddf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddf128.h"
 
-LIST_ADD_TESTS(DoubleFloat128, double, float128, LIBC_NAMESPACE::daddf128)
+LIST_ADD_TESTS(double, float128, LIBC_NAMESPACE::daddf128)
diff --git a/libc/test/src/math/smoke/daddl_test.cpp b/libc/test/src/math/smoke/daddl_test.cpp
index 1746b488abc3fc..7a34d962d52072 100644
--- a/libc/test/src/math/smoke/daddl_test.cpp
+++ b/libc/test/src/math/smoke/daddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/daddl.h"
 
-LIST_ADD_TESTS(DoubleLongDouble, double, long double, LIBC_NAMESPACE::daddl)
+LIST_ADD_TESTS(double, long double, LIBC_NAMESPACE::daddl)
diff --git a/libc/test/src/math/smoke/f16add_test.cpp b/libc/test/src/math/smoke/f16add_test.cpp
index 8e7a9a3f32ffc0..c47ece2a925551 100644
--- a/libc/test/src/math/smoke/f16add_test.cpp
+++ b/libc/test/src/math/smoke/f16add_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16add.h"
 
-LIST_ADD_TESTS(Float16Double, float16, double, LIBC_NAMESPACE::f16add)
+LIST_ADD_TESTS(float16, double, LIBC_NAMESPACE::f16add)
diff --git a/libc/test/src/math/smoke/f16addf128_test.cpp b/libc/test/src/math/smoke/f16addf128_test.cpp
index f630854bcbaa9d..8ed123b4ff1e85 100644
--- a/libc/test/src/math/smoke/f16addf128_test.cpp
+++ b/libc/test/src/math/smoke/f16addf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf128.h"
 
-LIST_ADD_TESTS(Float16Float128, float16, float128, LIBC_NAMESPACE::f16addf128)
+LIST_ADD_TESTS(float16, float128, LIBC_NAMESPACE::f16addf128)
diff --git a/libc/test/src/math/smoke/f16addf_test.cpp b/libc/test/src/math/smoke/f16addf_test.cpp
index 45d2bfbe491e1d..1e8b4323114adc 100644
--- a/libc/test/src/math/smoke/f16addf_test.cpp
+++ b/libc/test/src/math/smoke/f16addf_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addf.h"
 
-LIST_ADD_TESTS(Float16Float, float16, float, LIBC_NAMESPACE::f16addf)
+LIST_ADD_TESTS(float16, float, LIBC_NAMESPACE::f16addf)
diff --git a/libc/test/src/math/smoke/f16addl_test.cpp b/libc/test/src/math/smoke/f16addl_test.cpp
index 7737938fec26b2..f8e0d9ba6b4dec 100644
--- a/libc/test/src/math/smoke/f16addl_test.cpp
+++ b/libc/test/src/math/smoke/f16addl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/f16addl.h"
 
-LIST_ADD_TESTS(Float16LongDouble, float16, long double, LIBC_NAMESPACE::f16addl)
+LIST_ADD_TESTS(float16, long double, LIBC_NAMESPACE::f16addl)
diff --git a/libc/test/src/math/smoke/fadd_test.cpp b/libc/test/src/math/smoke/fadd_test.cpp
index e11251cde78a22..fe9ac8b252ed35 100644
--- a/libc/test/src/math/smoke/fadd_test.cpp
+++ b/libc/test/src/math/smoke/fadd_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/fadd.h"
 
-LIST_ADD_TESTS(FloatDouble, float, double, LIBC_NAMESPACE::fadd)
+LIST_ADD_TESTS(float, double, LIBC_NAMESPACE::fadd)
diff --git a/libc/test/src/math/smoke/faddf128_test.cpp b/libc/test/src/math/smoke/faddf128_test.cpp
index 7a3f7fd3afe3c1..5a11b5f419cad2 100644
--- a/libc/test/src/math/smoke/faddf128_test.cpp
+++ b/libc/test/src/math/smoke/faddf128_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddf128.h"
 
-LIST_ADD_TESTS(FloatFloat128, float, float128, LIBC_NAMESPACE::faddf128)
+LIST_ADD_TESTS(float, float128, LIBC_NAMESPACE::faddf128)
diff --git a/libc/test/src/math/smoke/faddl_test.cpp b/libc/test/src/math/smoke/faddl_test.cpp
index c0a15048cd49fc..9c99b32ee7c422 100644
--- a/libc/test/src/math/smoke/faddl_test.cpp
+++ b/libc/test/src/math/smoke/faddl_test.cpp
@@ -10,4 +10,4 @@
 
 #include "src/math/faddl.h"
 
-LIST_ADD_TESTS(FloatLongDouble, float, long double, LIBC_NAMESPACE::faddl)
+LIST_ADD_TESTS(float, long double, LIBC_NAMESPACE::faddl)
diff --git a/libc/test/src/math/smoke/sub_same_type_test.cpp b/libc/test/src/math/smoke/sub_same_type_test.cpp
index 180493d8447446..016f2b5652e7af 100644
--- a/libc/test/src/math/smoke/sub_same_type_test.cpp
+++ b/libc/test/src/math/smoke/sub_same_type_test.cpp
@@ -11,14 +11,15 @@
 #include "src/__support/FPUtil/generic/add_sub.h"
 #include "src/__support/macros/properties/types.h"
 
-#define SUB_FUNC(T) (LIBC_NAMESPACE::fputil::generic::add<T, T>)
+#define SUB_FUNC(T) (LIBC_NAMESPACE::fputil::generic::sub<T, T>)
 
-LIST_SUB_TESTS(Double, double, double, SUB_FUNC(double))
-LIST_SUB_TESTS(Float, float, float, SUB_FUNC(float))
-LIST_SUB_TESTS(LongDouble, long double, long double, SUB_FUNC(long double))
+LIST_SUB_SAME_TYPE_TESTS(Double, double, double, SUB_FUNC(double))
+LIST_SUB_SAME_TYPE_TESTS(Float, float, float, SUB_FUNC(float))
+LIST_SUB_SAME_TYPE_TESTS(LongDouble, long double, long double,
+                         SUB_FUNC(long double))
 #ifdef LIBC_TYPES_HAS_FLOAT16
-LIST_SUB_TESTS(Float16, float16, float16, SUB_FUNC(float16))
+LIST_SUB_SAME_TYPE_TESTS(Float16, float16, float16, SUB_FUNC(float16))
 #endif
 #ifdef LIBC_TYPES_HAS_FLOAT128
-LIST_SUB_TESTS(Float128, float128, float128, SUB_FUNC(float128))
+LIST_SUB_SAME_TYPE_TESTS(Float128, float128, float128, SUB_FUNC(float128))
 #endif
diff --git a/libc/test/src/math/sub_same_type_test.cpp b/libc/test/src/math/sub_same_type_test.cpp
index 04e1cbedb83a64..7d6db5f8662aee 100644
--- a/libc/test/src/math/sub_same_type_test.cpp
+++ b/libc/test/src/math/sub_same_type_test.cpp
@@ -13,12 +13,10 @@
 
 #define SUB_FUNC(T) (LIBC_NAMESPACE::fputil::generic::sub<T, T>)
 
-LIST_SUB_TESTS(Double, double, double, SUB_FUNC(double))
-LIST_SUB_TESTS(Float, float, float, SUB_FUNC(float))
-LIST_SUB_TESTS(LongDouble, long double, long double, SUB_FUNC(long double))
+LIST_SUB_SAME_TYPE_TESTS(Double, double, double, SUB_FUNC(double))
+LIST_SUB_SAME_TYPE_TESTS(Float, float, float, SUB_FUNC(float))
+LIST_SUB_SAME_TYPE_TESTS(LongDouble, long double, long double,
+                         SUB_FUNC(long double))
 #ifdef LIBC_TYPES_HAS_FLOAT16
-LIST_SUB_TESTS(Float16, float16, float16, SUB_FUNC(float16))
-#endif
-#ifdef LIBC_TYPES_HAS_FLOAT128
-LIST_SUB_TESTS(Float128, float128, float128, SUB_FUNC(float128))
+LIST_SUB_SAME_TYPE_TESTS(Float16, float16, float16, SUB_FUNC(float16))
 #endif

>From 80b1addfea953d6f4133296c213767018b275528 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Mon, 30 Dec 2024 19:17:05 +0100
Subject: [PATCH 4/4] Add float128 same-type MPFR tests

---
 libc/test/src/math/add_same_type_test.cpp |  3 +++
 libc/test/src/math/sub_same_type_test.cpp |  3 +++
 libc/utils/MPFRWrapper/MPFRUtils.cpp      | 10 ++++++++++
 3 files changed, 16 insertions(+)

diff --git a/libc/test/src/math/add_same_type_test.cpp b/libc/test/src/math/add_same_type_test.cpp
index 7ef48ff0800ccc..13e1e3cbe27713 100644
--- a/libc/test/src/math/add_same_type_test.cpp
+++ b/libc/test/src/math/add_same_type_test.cpp
@@ -20,3 +20,6 @@ LIST_ADD_SAME_TYPE_TESTS(LongDouble, long double, long double,
 #ifdef LIBC_TYPES_HAS_FLOAT16
 LIST_ADD_SAME_TYPE_TESTS(Float16, float16, float16, ADD_FUNC(float16))
 #endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_ADD_SAME_TYPE_TESTS(Float128, float128, float128, ADD_FUNC(float128))
+#endif
diff --git a/libc/test/src/math/sub_same_type_test.cpp b/libc/test/src/math/sub_same_type_test.cpp
index 7d6db5f8662aee..016f2b5652e7af 100644
--- a/libc/test/src/math/sub_same_type_test.cpp
+++ b/libc/test/src/math/sub_same_type_test.cpp
@@ -20,3 +20,6 @@ LIST_SUB_SAME_TYPE_TESTS(LongDouble, long double, long double,
 #ifdef LIBC_TYPES_HAS_FLOAT16
 LIST_SUB_SAME_TYPE_TESTS(Float16, float16, float16, SUB_FUNC(float16))
 #endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+LIST_SUB_SAME_TYPE_TESTS(Float128, float128, float128, SUB_FUNC(float128))
+#endif
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 0dac497bb779af..61383924c186d2 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -1190,6 +1190,10 @@ template void explain_binary_operation_one_output_error(
 template void explain_binary_operation_one_output_error(
     Operation, const BinaryInput<long double> &, float16, double, RoundingMode);
 #endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+template void explain_binary_operation_one_output_error(
+    Operation, const BinaryInput<float128> &, float128, double, RoundingMode);
+#endif
 
 template <typename InputType, typename OutputType>
 void explain_ternary_operation_one_output_error(
@@ -1414,6 +1418,12 @@ template bool
 compare_binary_operation_one_output(Operation, const BinaryInput<long double> &,
                                     float16, double, RoundingMode);
 #endif
+#ifdef LIBC_TYPES_HAS_FLOAT128
+template bool compare_binary_operation_one_output(Operation,
+                                                  const BinaryInput<float128> &,
+                                                  float128, double,
+                                                  RoundingMode);
+#endif
 
 template <typename InputType, typename OutputType>
 bool compare_ternary_operation_one_output(Operation op,



More information about the libc-commits mailing list