[libc-commits] [libc] [libc][math] Use exact exclusive upper bounds for fromfp conversions (PR #236477)

via libc-commits libc-commits at lists.llvm.org
Wed Oct 28 20:25:21 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: sriramshastry

<details>
<summary>Changes</summary>

Use exactly representable exclusive upper power-of-two bounds in the shared 
fromfp range check. Avoid accepting the rounded-up endpoint or raising FE_INEXACT
 during bound construction. Add wide-width regressions for the signed and
 unsigned fromfp and fromfpx families.

## Validation

Tested independently at ea08830d976fbe61384695d33e0acafee8d88737 on x86-64 Linux,
Release, GCC 13 and Clang 18. With only the revised tests, 28/28 smoke target
configurations fail per compiler; with the repair, 28/28 pass. All four families check
that zero does not acquire inexact while constructing the bound, and that the exact
exclusive upper bound is invalid. Changed-hunk formatting and whitespace checks
pass. No ABI or return-type change is proposed.

## Scope and Review

Check exact exclusive signed/unsigned bounds and exception-free bound construction
across all four families. No public ABI or return-type change is proposed.

## Updated submission base

Submission base: 10c142fa799e258285b6cfb8fce153864586152d.
The standalone baseline/patched results above remain recorded at their original
tested snapshot. At this newer base, the fourteen-only combined suite passes
150 native configurations per compiler and twelve four-mode numerical runs,
with zero value or scoped-reporting mismatches.

Signed-off-by: sriramshastry <sriramshastry@<!-- -->gmail.com>


---
Full diff: https://github.com/llvm/llvm-project/pull/236477.diff


5 Files Affected:

- (modified) libc/src/__support/FPUtil/NearestIntegerOperations.h (+7-8) 
- (modified) libc/test/src/math/smoke/FromfpTest.h (+20) 
- (modified) libc/test/src/math/smoke/FromfpxTest.h (+20) 
- (modified) libc/test/src/math/smoke/UfromfpTest.h (+20) 
- (modified) libc/test/src/math/smoke/UfromfpxTest.h (+20) 


``````````diff
diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h
index 156a6de255621b..d322d7d9df0b87 100644
--- a/libc/src/__support/FPUtil/NearestIntegerOperations.h
+++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h
@@ -298,11 +298,11 @@ fromfp(T x, int rnd, unsigned int width) {
       raise_except_if_required(FE_INVALID);
       return FPBits<T>::quiet_nan().get_val();
     }
-    // rounded_value > 2^(width - 1) - 1
+    // Use the exclusive upper bound: subtracting one can round back up to
+    // the bound when width exceeds the precision of T.
     T range_max =
-        FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val() -
-        T(1.0);
-    if (rounded_value > range_max) {
+        FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val();
+    if (rounded_value >= range_max) {
       raise_except_if_required(FE_INVALID);
       return FPBits<T>::quiet_nan().get_val();
     }
@@ -320,11 +320,10 @@ fromfp(T x, int rnd, unsigned int width) {
     return rounded_value;
 
   StorageType range_exp = static_cast<StorageType>(width + FPBits<T>::EXP_BIAS);
-  // rounded_value > 2^width - 1
+  // Check the exactly representable exclusive upper bound.
   T range_max =
-      FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val() -
-      T(1.0);
-  if (rounded_value > range_max) {
+      FPBits<T>::create_value(Sign::POS, range_exp, EXPLICIT_BIT).get_val();
+  if (rounded_value >= range_max) {
     raise_except_if_required(FE_INVALID);
     return FPBits<T>::quiet_nan().get_val();
   }
diff --git a/libc/test/src/math/smoke/FromfpTest.h b/libc/test/src/math/smoke/FromfpTest.h
index fe78c9050a7fe6..8dd9ae422cbdbb 100644
--- a/libc/test/src/math/smoke/FromfpTest.h
+++ b/libc/test/src/math/smoke/FromfpTest.h
@@ -469,10 +469,30 @@ class FromfpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     EXPECT_FP_EQ_WITH_EXCEPTION(
         aNaN, func(T(-5.75), UNKNOWN_MATH_ROUNDING_DIRECTION, 3U), FE_INVALID);
   }
+  void testWideRangeBoundary(FromfpFunc func) {
+    using namespace LIBC_NAMESPACE::fputil::testing;
+    ForceRoundingMode rounding(RoundingMode::Nearest);
+    if (!rounding.success)
+      return;
+    constexpr unsigned EXPONENT = FPBits::FRACTION_LEN + 3;
+    constexpr unsigned WIDTH = EXPONENT + 1;
+    FPBits limit = FPBits::one();
+    limit.set_biased_exponent(FPBits::EXP_BIAS + EXPONENT);
+    T boundary = limit.get_val();
+    // Computing a range bound must not raise inexact for an exact zero input.
+    EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(zero, FP_INT_TOWARDZERO, WIDTH), 0);
+    EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(boundary, FP_INT_TOWARDZERO, WIDTH),
+                                FE_INVALID);
+    EXPECT_MATH_ERRNO(0);
+  }
 };
 
 #define LIST_FROMFP_TESTS(Name, T, func)                                       \
   using LlvmLibc##Name##Test = FromfpTestTemplate<T>;                          \
+  TEST_F(LlvmLibc##Name##Test, WideRangeBoundary) {                            \
+    testWideRangeBoundary(&func);                                              \
+  }                                                                            \
   TEST_F(LlvmLibc##Name##Test, SpecialNumbersNonzeroWidth) {                   \
     testSpecialNumbersNonzeroWidth(&func);                                     \
   }                                                                            \
diff --git a/libc/test/src/math/smoke/FromfpxTest.h b/libc/test/src/math/smoke/FromfpxTest.h
index 5696ad16520a73..8fad473370c6f1 100644
--- a/libc/test/src/math/smoke/FromfpxTest.h
+++ b/libc/test/src/math/smoke/FromfpxTest.h
@@ -631,10 +631,30 @@ class FromfpxTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     EXPECT_FP_EQ_WITH_EXCEPTION(
         aNaN, func(T(-5.75), UNKNOWN_MATH_ROUNDING_DIRECTION, 3U), FE_INVALID);
   }
+  void testWideRangeBoundary(FromfpxFunc func) {
+    using namespace LIBC_NAMESPACE::fputil::testing;
+    ForceRoundingMode rounding(RoundingMode::Nearest);
+    if (!rounding.success)
+      return;
+    constexpr unsigned EXPONENT = FPBits::FRACTION_LEN + 3;
+    constexpr unsigned WIDTH = EXPONENT + 1;
+    FPBits limit = FPBits::one();
+    limit.set_biased_exponent(FPBits::EXP_BIAS + EXPONENT);
+    T boundary = limit.get_val();
+    // Computing a range bound must not raise inexact for an exact zero input.
+    EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(zero, FP_INT_TOWARDZERO, WIDTH), 0);
+    EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(boundary, FP_INT_TOWARDZERO, WIDTH),
+                                FE_INVALID);
+    EXPECT_MATH_ERRNO(0);
+  }
 };
 
 #define LIST_FROMFPX_TESTS(Name, T, func)                                      \
   using LlvmLibc##Name##Test = FromfpxTestTemplate<T>;                         \
+  TEST_F(LlvmLibc##Name##Test, WideRangeBoundary) {                            \
+    testWideRangeBoundary(&func);                                              \
+  }                                                                            \
   TEST_F(LlvmLibc##Name##Test, SpecialNumbersNonzeroWidth) {                   \
     testSpecialNumbersNonzeroWidth(&func);                                     \
   }                                                                            \
diff --git a/libc/test/src/math/smoke/UfromfpTest.h b/libc/test/src/math/smoke/UfromfpTest.h
index 6ec720e0fa6c46..8775e1e9e5f1c6 100644
--- a/libc/test/src/math/smoke/UfromfpTest.h
+++ b/libc/test/src/math/smoke/UfromfpTest.h
@@ -403,10 +403,30 @@ class UfromfpTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     EXPECT_FP_EQ_WITH_EXCEPTION(
         aNaN, func(T(-5.75), UNKNOWN_MATH_ROUNDING_DIRECTION, 32U), FE_INVALID);
   }
+  void testWideRangeBoundary(UfromfpFunc func) {
+    using namespace LIBC_NAMESPACE::fputil::testing;
+    ForceRoundingMode rounding(RoundingMode::Nearest);
+    if (!rounding.success)
+      return;
+    constexpr unsigned EXPONENT = FPBits::FRACTION_LEN + 3;
+    constexpr unsigned WIDTH = EXPONENT;
+    FPBits limit = FPBits::one();
+    limit.set_biased_exponent(FPBits::EXP_BIAS + EXPONENT);
+    T boundary = limit.get_val();
+    // Computing a range bound must not raise inexact for an exact zero input.
+    EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(zero, FP_INT_TOWARDZERO, WIDTH), 0);
+    EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(boundary, FP_INT_TOWARDZERO, WIDTH),
+                                FE_INVALID);
+    EXPECT_MATH_ERRNO(0);
+  }
 };
 
 #define LIST_UFROMFP_TESTS(Name, T, func)                                      \
   using LlvmLibc##Name##Test = UfromfpTestTemplate<T>;                         \
+  TEST_F(LlvmLibc##Name##Test, WideRangeBoundary) {                            \
+    testWideRangeBoundary(&func);                                              \
+  }                                                                            \
   TEST_F(LlvmLibc##Name##Test, SpecialNumbersNonzeroWidth) {                   \
     testSpecialNumbersNonzeroWidth(&func);                                     \
   }                                                                            \
diff --git a/libc/test/src/math/smoke/UfromfpxTest.h b/libc/test/src/math/smoke/UfromfpxTest.h
index 689ff543c7a8dc..0a1e69f1d681e9 100644
--- a/libc/test/src/math/smoke/UfromfpxTest.h
+++ b/libc/test/src/math/smoke/UfromfpxTest.h
@@ -494,10 +494,30 @@ class UfromfpxTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     EXPECT_FP_EQ_WITH_EXCEPTION(
         aNaN, func(T(-5.75), UNKNOWN_MATH_ROUNDING_DIRECTION, 32U), FE_INVALID);
   }
+  void testWideRangeBoundary(UfromfpxFunc func) {
+    using namespace LIBC_NAMESPACE::fputil::testing;
+    ForceRoundingMode rounding(RoundingMode::Nearest);
+    if (!rounding.success)
+      return;
+    constexpr unsigned EXPONENT = FPBits::FRACTION_LEN + 3;
+    constexpr unsigned WIDTH = EXPONENT;
+    FPBits limit = FPBits::one();
+    limit.set_biased_exponent(FPBits::EXP_BIAS + EXPONENT);
+    T boundary = limit.get_val();
+    // Computing a range bound must not raise inexact for an exact zero input.
+    EXPECT_FP_EQ_WITH_EXCEPTION(zero, func(zero, FP_INT_TOWARDZERO, WIDTH), 0);
+    EXPECT_MATH_ERRNO(0);
+    EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, func(boundary, FP_INT_TOWARDZERO, WIDTH),
+                                FE_INVALID);
+    EXPECT_MATH_ERRNO(0);
+  }
 };
 
 #define LIST_UFROMFPX_TESTS(Name, T, func)                                     \
   using LlvmLibc##Name##Test = UfromfpxTestTemplate<T>;                        \
+  TEST_F(LlvmLibc##Name##Test, WideRangeBoundary) {                            \
+    testWideRangeBoundary(&func);                                              \
+  }                                                                            \
   TEST_F(LlvmLibc##Name##Test, SpecialNumbersNonzeroWidth) {                   \
     testSpecialNumbersNonzeroWidth(&func);                                     \
   }                                                                            \

``````````

</details>


https://github.com/llvm/llvm-project/pull/236477


More information about the libc-commits mailing list