[llvm] APFloat: fix wrong result status for large floats (PR #189925)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 1 02:51:13 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-llvm-adt

Author: Luca Ciucci (LucaCiucci)

<details>
<summary>Changes</summary>

For large float literals such as `10384593717069655257060992658440193.0`, [`FloatingLiteral::isExact`](https://github.com/llvm/llvm-project/blob/6b2b0da40de1495ace2b100799a35711f7ad7b21/clang/include/clang/AST/Expr.h#L1702) was incorrectly returning `true`.

The issue has been tracked down to `IEEEFloat::roundSignificandWithExponent` incorrectly reporting `opOK`.




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


2 Files Affected:

- (modified) llvm/lib/Support/APFloat.cpp (+7-1) 
- (modified) llvm/unittests/ADT/APFloatTest.cpp (+21) 


``````````diff
diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp
index 47c712125f044..dcf503ec7779c 100644
--- a/llvm/lib/Support/APFloat.cpp
+++ b/llvm/lib/Support/APFloat.cpp
@@ -2858,6 +2858,7 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
   for (;; parts *= 2) {
     opStatus sigStatus, powStatus;
     unsigned int excessPrecision, truncatedBits;
+    opStatus conversionStatus = opOK;
 
     calcSemantics.precision = parts * integerPartWidth - 1;
     excessPrecision = calcSemantics.precision - semantics->precision;
@@ -2869,8 +2870,12 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
 
     sigStatus = decSig.convertFromUnsignedParts(decSigParts, sigPartCount,
                                                 rmNearestTiesToEven);
+    conversionStatus =
+        static_cast<opStatus>(conversionStatus | (sigStatus & opInexact));
     powStatus = pow5.convertFromUnsignedParts(pow5Parts, pow5PartCount,
                                               rmNearestTiesToEven);
+    conversionStatus =
+        static_cast<opStatus>(conversionStatus | (powStatus & opInexact));
     /* Add exp, as 10^n = 5^n * 2^n.  */
     decSig.exponent += exp;
 
@@ -2917,7 +2922,8 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
       calcLostFraction = lostFractionThroughTruncation(decSig.significandParts(),
                                                        decSig.partCount(),
                                                        truncatedBits);
-      return normalize(rounding_mode, calcLostFraction);
+      return static_cast<opStatus>(normalize(rounding_mode, calcLostFraction) |
+                                   conversionStatus);
     }
   }
 }
diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp
index 8ff3efe64c29b..1cf015c07e10f 100644
--- a/llvm/unittests/ADT/APFloatTest.cpp
+++ b/llvm/unittests/ADT/APFloatTest.cpp
@@ -10206,4 +10206,25 @@ TEST(APFloatTest, isValidArbitraryFPFormat) {
   EXPECT_FALSE(APFloat::isValidArbitraryFPFormat("unknown"));
 }
 
+TEST(APFloatTest, DecimalStringPreservesInexactStatus) {
+  APFloat F(APFloat::IEEEsingle());
+
+  auto StatusOr = F.convertFromString("10384593717069655257060992658440193.0",
+                                      APFloat::rmNearestTiesToEven);
+  ASSERT_TRUE(!!StatusOr);
+
+  APFloat::opStatus Status = *StatusOr;
+
+  // The value is 2^113 + 1, not exactly representable in float.
+  EXPECT_TRUE(Status & APFloat::opInexact);
+
+  // But it should round to exactly 2^113.
+  APFloat Expected(APFloat::IEEEsingle());
+  auto ExpectedStatus =
+      Expected.convertFromString("0x1p113", APFloat::rmNearestTiesToEven);
+  ASSERT_TRUE(!!ExpectedStatus);
+
+  EXPECT_EQ(F.bitcastToAPInt(), Expected.bitcastToAPInt());
+}
+
 } // namespace

``````````

</details>


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


More information about the llvm-commits mailing list