[libc-commits] [libc] [libc] Fix float128-to-integer conversion UB (PR #211593)

via libc-commits libc-commits at lists.llvm.org
Fri Jul 31 05:13:27 PDT 2026


https://github.com/Sukumarsawant updated https://github.com/llvm/llvm-project/pull/211593

>From accfc9c9dc8f35e78f7927c28fd880a085896cf3 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 23 Jul 2026 21:08:19 +0530
Subject: [PATCH 01/13] initial test commit

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index b4ee0439ba0f5..c971b01925867 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -87,6 +87,8 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
   ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
+  int a = static_cast<int>(Float128(1e300));
+  (void)a;
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);

>From 79699cd9f7fd1557f92178093b6ed64735278391 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 23 Jul 2026 21:23:37 +0530
Subject: [PATCH 02/13] sanitizer

---
 libc/test/src/__support/FPUtil/CMakeLists.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index cab95df0e709c..ee2bbf688b1cb 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -49,6 +49,8 @@ add_fp_unittest(
     libc.hdr.limits_macros
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.float128
+  COMPILE_OPTIONS
+    "-fsanitize=address"
 )
 
 # TODO: Temporally disable bfloat16 test until MPCommon target is updated

>From 9caa9b763dc8c40cb8cc3fa196403d61fb1db5f9 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 23 Jul 2026 21:27:34 +0530
Subject: [PATCH 03/13] chore:add volatile

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index c971b01925867..664f32f1d74c5 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -87,8 +87,7 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
   ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
-  int a = static_cast<int>(Float128(1e300));
-  (void)a;
+  volatile int a = static_cast<int>(Float128(1e300));
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);

>From 3745d968e089d7988aca442033f22bff5a02522b Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Wed, 29 Jul 2026 01:52:54 +0530
Subject: [PATCH 04/13] add missing numeric_limits check and modification to
 handle very small and very large values

---
 libc/src/__support/FPUtil/CMakeLists.txt      |  1 +
 libc/src/__support/FPUtil/dyadic_float.h      |  4 +++-
 libc/src/__support/FPUtil/float128.h          | 21 +++++++++++++++++--
 libc/test/src/__support/FPUtil/CMakeLists.txt |  2 --
 .../src/__support/FPUtil/float128_test.cpp    |  3 ++-
 5 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index 8b6ac8027b52d..ab423a2622e5f 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -310,6 +310,7 @@ add_header_library(
     libc.src.__support.macros.attributes
     libc.src.__support.macros.config
     libc.src.__support.uint128
+    libc.src.__support.CPP.limits
 )
 
 add_subdirectory(generic)
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index c218632131934..d548ee2b14561 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -471,7 +471,9 @@ template <size_t Bits> struct DyadicFloat {
       // to avoid undefined behavior negating INT_MIN as an integer (although
       // exponents coming in to this function _shouldn't_ be that large). The
       // result should always end up as a positive size_t.
-      size_t shift = -static_cast<size_t>(exponent);
+      size_t shift = cpp::min(
+          -static_cast<size_t>(exponent),
+          static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits));
       new_mant >>= shift;
     }
 
diff --git a/libc/src/__support/FPUtil/float128.h b/libc/src/__support/FPUtil/float128.h
index b1bcafefd61a4..e7db3594b4e9e 100644
--- a/libc/src/__support/FPUtil/float128.h
+++ b/libc/src/__support/FPUtil/float128.h
@@ -10,6 +10,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOAT128_H
 
 #include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/FPUtil/cast.h"
 #include "src/__support/FPUtil/comparison_operations.h"
@@ -69,13 +70,29 @@ struct Float128 {
 
   template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
   LIBC_INLINE constexpr explicit operator T() const {
+    constexpr T MIN_T = cpp::numeric_limits<T>::min();
+    constexpr T MAX_T = cpp::numeric_limits<T>::max();
     FPBits<Float128> x_bits(*this);
     // Raise FE_INVALID for inf and NaN
     if (x_bits.is_inf_or_nan()) {
       raise_except_if_required(FE_INVALID);
+      return x_bits.is_neg() ? MIN_T : MAX_T;
     }
-    int x_bits_exp =
-        x_bits.get_explicit_exponent() - FPBits<Float128>::FRACTION_LEN;
+    int exponent = x_bits.get_explicit_exponent();
+    constexpr int EXPONENT_LIMIT = cpp::is_signed_v<T>
+                                       ? static_cast<int>(sizeof(T) * 8) - 1
+                                       : static_cast<int>(sizeof(T) * 8);
+    if (exponent > EXPONENT_LIMIT) {
+      raise_except_if_required(FE_INVALID);
+      return x_bits.is_neg() ? MIN_T : MAX_T;
+    } else if (exponent == EXPONENT_LIMIT) {
+      if (x_bits.is_pos() || x_bits.get_mantissa() != 0) {
+        raise_except_if_required(FE_INVALID);
+        return x_bits.is_neg() ? MIN_T : MAX_T;
+      }
+    }
+
+    int x_bits_exp = exponent - FPBits<Float128>::FRACTION_LEN;
     // sign * 2^(exp-bias) * mantissa
     DyadicFloat<FPBits<Float128>::STORAGE_LEN> xd(
         x_bits.sign(), x_bits_exp, x_bits.get_explicit_mantissa());
diff --git a/libc/test/src/__support/FPUtil/CMakeLists.txt b/libc/test/src/__support/FPUtil/CMakeLists.txt
index ee2bbf688b1cb..cab95df0e709c 100644
--- a/libc/test/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/test/src/__support/FPUtil/CMakeLists.txt
@@ -49,8 +49,6 @@ add_fp_unittest(
     libc.hdr.limits_macros
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.float128
-  COMPILE_OPTIONS
-    "-fsanitize=address"
 )
 
 # TODO: Temporally disable bfloat16 test until MPCommon target is updated
diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index 664f32f1d74c5..4982f2a61fdc1 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -87,7 +87,8 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
   ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
-  volatile int a = static_cast<int>(Float128(1e300));
+  volatile int a = static_cast<int>(Float128(
+      1e300)); // This might not give any error but gives a wrong value for now
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);

>From 6e4487ac06c6e85d4e15b558949fc94a7ae981f1 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Wed, 29 Jul 2026 02:09:28 +0530
Subject: [PATCH 05/13] Add temp tests

nit

nit
---
 libc/src/__support/FPUtil/dyadic_float.h      |  8 ++--
 .../src/__support/FPUtil/float128_test.cpp    | 45 ++++++++++++++++---
 2 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index d548ee2b14561..a1321e151c535 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -471,9 +471,11 @@ template <size_t Bits> struct DyadicFloat {
       // to avoid undefined behavior negating INT_MIN as an integer (although
       // exponents coming in to this function _shouldn't_ be that large). The
       // result should always end up as a positive size_t.
-      size_t shift = cpp::min(
-          -static_cast<size_t>(exponent),
-          static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits));
+      size_t exp = -static_cast<size_t>(exponent);
+      size_t limit = static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
+      size_t shift = exp < limit ? exp : limit;
+      new_mant >>= shift;
+
       new_mant >>= shift;
     }
 
diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index 4982f2a61fdc1..fbd7700d8abae 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -80,24 +80,50 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<int>(Float128(-1.9)), -1);
   ASSERT_EQ(static_cast<int>(Float128(1.9f)), 1);
 
-  // Extreme values
+  // Border values
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<int>(Float128(INT_MAX)), INT_MAX);
   ASSERT_EQ(static_cast<int>(Float128(INT_MIN)), INT_MIN);
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MAX)), LLONG_MAX);
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
   ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
-  volatile int a = static_cast<int>(Float128(
-      1e300)); // This might not give any error but gives a wrong value for now
+  EXPECT_FP_EXCEPTION(0);
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
-  ASSERT_EQ(static_cast<int>(FPBits::quiet_nan().get_val()), 0);
+  ASSERT_EQ(static_cast<int>(FPBits::quiet_nan().get_val()), INT_MAX);
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(FPBits::inf().get_val()), INT_MAX);
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  // Extreme values
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(Float128(1e300)), INT_MAX);
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(Float128(-1e300)), INT_MIN);
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(FPBits::inf(Sign::NEG).get_val()), INT_MIN);
   EXPECT_FP_EXCEPTION(FE_INVALID);
 
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
-  ASSERT_EQ(static_cast<int>(FPBits::inf().get_val()), 0);
+  ASSERT_EQ(static_cast<int>(FPBits::inf(Sign::POS).get_val()), INT_MAX);
   EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  // Small values
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(Float128(1e-300)), 0);
+  ASSERT_EQ(static_cast<int>(Float128(-1e-300)), 0);
+  ASSERT_EQ(static_cast<long long>(Float128(1e-300)), 0LL);
+  ASSERT_EQ(static_cast<int>(Float128(0.5)), 0);
+  ASSERT_EQ(static_cast<int>(Float128(-0.5)), 0);
+  EXPECT_FP_EXCEPTION(0);
 }
 
 TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
@@ -108,4 +134,13 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
   ASSERT_TRUE(Float128(7U) == Float128(7.0f));
   ASSERT_TRUE(Float128(-7LL) == Float128(-7.0));
   ASSERT_TRUE(Float128(123456789LL) == Float128(123456789.0));
+
+  // 2147483648.0 or 2^31 is out of bound in signed and not in unsigned
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<int>(Float128(2147483648.0)), INT_MAX);
+  EXPECT_FP_EXCEPTION(FE_INVALID);
+
+  LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
+  ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
+  EXPECT_FP_EXCEPTION(0);
 }

>From c445aeb08293030eef88302d6d37230c94da29b0 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Wed, 29 Jul 2026 14:37:23 +0530
Subject: [PATCH 06/13] nit

---
 libc/src/__support/FPUtil/dyadic_float.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index a1321e151c535..a6e2a47779144 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -472,11 +472,10 @@ template <size_t Bits> struct DyadicFloat {
       // exponents coming in to this function _shouldn't_ be that large). The
       // result should always end up as a positive size_t.
       size_t exp = -static_cast<size_t>(exponent);
-      size_t limit = static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
+      size_t limit =
+          static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
       size_t shift = exp < limit ? exp : limit;
       new_mant >>= shift;
-
-      new_mant >>= shift;
     }
 
     if (sign.is_neg()) {

>From 95eff267ad2e457bb8744dbd2d9be7e248ac8daa Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Wed, 29 Jul 2026 15:05:52 +0530
Subject: [PATCH 07/13] test: temp remomve fe_invalid not raised flag check

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index fbd7700d8abae..69a1fd414ffbb 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -88,7 +88,6 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
   ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
-  EXPECT_FP_EXCEPTION(0);
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
@@ -123,7 +122,6 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(1e-300)), 0LL);
   ASSERT_EQ(static_cast<int>(Float128(0.5)), 0);
   ASSERT_EQ(static_cast<int>(Float128(-0.5)), 0);
-  EXPECT_FP_EXCEPTION(0);
 }
 
 TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
@@ -142,5 +140,4 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
 
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
-  EXPECT_FP_EXCEPTION(0);
 }

>From cb02d3a4f2ff233ee314a8e523174b2a6658bf0b Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Wed, 29 Jul 2026 15:14:30 +0530
Subject: [PATCH 08/13] nit

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index 69a1fd414ffbb..a249e117a2d68 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -119,7 +119,6 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<int>(Float128(1e-300)), 0);
   ASSERT_EQ(static_cast<int>(Float128(-1e-300)), 0);
-  ASSERT_EQ(static_cast<long long>(Float128(1e-300)), 0LL);
   ASSERT_EQ(static_cast<int>(Float128(0.5)), 0);
   ASSERT_EQ(static_cast<int>(Float128(-0.5)), 0);
 }

>From eb6fb22a4d54028250b5c5566dfc04d4fc581d00 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 30 Jul 2026 00:40:47 +0530
Subject: [PATCH 09/13] test: try returning 0 instead of limit

---
 libc/src/__support/FPUtil/dyadic_float.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index a6e2a47779144..4d32724f51b2c 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -471,11 +471,13 @@ template <size_t Bits> struct DyadicFloat {
       // to avoid undefined behavior negating INT_MIN as an integer (although
       // exponents coming in to this function _shouldn't_ be that large). The
       // result should always end up as a positive size_t.
-      size_t exp = -static_cast<size_t>(exponent);
+      size_t shift = -static_cast<size_t>(exponent);
       size_t limit =
           static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
-      size_t shift = exp < limit ? exp : limit;
-      new_mant >>= shift;
+      if (shift >= limit)
+        new_mant = 0;
+      else
+        new_mant >>= shift;
     }
 
     if (sign.is_neg()) {

>From 011a1a4eb443b3fa83de1ce00c743f875afb87dd Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 30 Jul 2026 21:18:24 +0530
Subject: [PATCH 10/13] float128_ub

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index a249e117a2d68..a792a1f567b0a 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -87,7 +87,7 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MAX)), LLONG_MAX);
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
-  ASSERT_EQ(static_cast<unsigned>(Float128(0U)), 0U);
+  ASSERT_FP_EXCEPTION(0);
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
@@ -139,4 +139,5 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
 
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
+  ASSERT_FP_EXCEPTION(0);
 }

>From d76c13a9c8f888409e9f243c8b15ff22087ab4d9 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 30 Jul 2026 21:34:56 +0530
Subject: [PATCH 11/13] test check flag

---
 libc/test/src/__support/FPUtil/float128_test.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index a792a1f567b0a..3a46c95abc588 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -87,7 +87,7 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MAX)), LLONG_MAX);
   ASSERT_EQ(static_cast<long long>(Float128(LLONG_MIN)), LLONG_MIN);
   ASSERT_EQ(static_cast<unsigned>(Float128(UINT_MAX)), UINT_MAX);
-  ASSERT_FP_EXCEPTION(0);
+  EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_INVALID), 0);
 
   // FP exceptions
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
@@ -139,5 +139,4 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
 
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
-  ASSERT_FP_EXCEPTION(0);
 }

>From 40156eb8965b6980879106ff306c9887e93bb9c6 Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Thu, 30 Jul 2026 21:56:02 +0530
Subject: [PATCH 12/13] nits

---
 libc/src/__support/FPUtil/dyadic_float.h | 3 +--
 libc/src/__support/FPUtil/float128.h     | 4 +---
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 4d32724f51b2c..80892701e689a 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -472,8 +472,7 @@ template <size_t Bits> struct DyadicFloat {
       // exponents coming in to this function _shouldn't_ be that large). The
       // result should always end up as a positive size_t.
       size_t shift = -static_cast<size_t>(exponent);
-      size_t limit =
-          static_cast<size_t>(cpp::numeric_limits<MantissaType>::digits);
+      size_t limit = cpp::numeric_limits<MantissaType>::digits;
       if (shift >= limit)
         new_mant = 0;
       else
diff --git a/libc/src/__support/FPUtil/float128.h b/libc/src/__support/FPUtil/float128.h
index e7db3594b4e9e..1dd1abd417737 100644
--- a/libc/src/__support/FPUtil/float128.h
+++ b/libc/src/__support/FPUtil/float128.h
@@ -79,9 +79,7 @@ struct Float128 {
       return x_bits.is_neg() ? MIN_T : MAX_T;
     }
     int exponent = x_bits.get_explicit_exponent();
-    constexpr int EXPONENT_LIMIT = cpp::is_signed_v<T>
-                                       ? static_cast<int>(sizeof(T) * 8) - 1
-                                       : static_cast<int>(sizeof(T) * 8);
+    constexpr int EXPONENT_LIMIT = cpp::numeric_limits<T>::digits;
     if (exponent > EXPONENT_LIMIT) {
       raise_except_if_required(FE_INVALID);
       return x_bits.is_neg() ? MIN_T : MAX_T;

>From d0de7c0d85d6a0569f7740a22187bf49171e0f1d Mon Sep 17 00:00:00 2001
From: Sukumarsawant <sawantsukumar at gmail.com>
Date: Fri, 31 Jul 2026 17:42:54 +0530
Subject: [PATCH 13/13] final cleanup and nits

---
 libc/src/__support/FPUtil/CMakeLists.txt         | 2 +-
 libc/test/src/__support/FPUtil/float128_test.cpp | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/libc/src/__support/FPUtil/CMakeLists.txt b/libc/src/__support/FPUtil/CMakeLists.txt
index ab423a2622e5f..4673ef794c80b 100644
--- a/libc/src/__support/FPUtil/CMakeLists.txt
+++ b/libc/src/__support/FPUtil/CMakeLists.txt
@@ -303,6 +303,7 @@ add_header_library(
     .comparison_operations
     .dyadic_float
     libc.hdr.stdint_proxy
+    libc.src.__support.CPP.limits
     libc.src.__support.CPP.type_traits
     libc.src.__support.FPUtil.generic.add_sub
     libc.src.__support.FPUtil.generic.div
@@ -310,7 +311,6 @@ add_header_library(
     libc.src.__support.macros.attributes
     libc.src.__support.macros.config
     libc.src.__support.uint128
-    libc.src.__support.CPP.limits
 )
 
 add_subdirectory(generic)
diff --git a/libc/test/src/__support/FPUtil/float128_test.cpp b/libc/test/src/__support/FPUtil/float128_test.cpp
index 3a46c95abc588..5ca7e0e5a7d90 100644
--- a/libc/test/src/__support/FPUtil/float128_test.cpp
+++ b/libc/test/src/__support/FPUtil/float128_test.cpp
@@ -121,6 +121,7 @@ TEST(LlvmLibcFloat128Test, IntegerConversion) {
   ASSERT_EQ(static_cast<int>(Float128(-1e-300)), 0);
   ASSERT_EQ(static_cast<int>(Float128(0.5)), 0);
   ASSERT_EQ(static_cast<int>(Float128(-0.5)), 0);
+  EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_INVALID), 0);
 }
 
 TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
@@ -139,4 +140,5 @@ TEST(LlvmLibcFloat128Test, FromIntegralTypes) {
 
   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
   ASSERT_EQ(static_cast<unsigned>(Float128(2147483648.0)), 2147483648U);
+  EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_INVALID), 0);
 }



More information about the libc-commits mailing list