[flang-commits] [flang] [flang][runtime] Fix edge cases with ROUND=UP/DOWN (PR #67508)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Oct 16 10:21:08 PDT 2023


https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/67508

>From eaed58cf5f24f069c73e842cba3e692da74168e9 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Tue, 26 Sep 2023 17:20:04 -0700
Subject: [PATCH] [flang][runtime] Fix edge cases with ROUND=UP/DOWN

When an unrepresentable nonzero real input value with a
very small exponent is currently being read in as zero,
don't neglect ROUND=UP/DOWN; return the least nonzero
subnormal value instead when appropriate.
---
 flang/lib/Decimal/binary-to-decimal.cpp |  3 ++-
 flang/lib/Decimal/decimal-to-binary.cpp | 30 +++++++++++++++++--------
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/flang/lib/Decimal/binary-to-decimal.cpp b/flang/lib/Decimal/binary-to-decimal.cpp
index 7b31d02b292e48a..55fc548a6979bd3 100644
--- a/flang/lib/Decimal/binary-to-decimal.cpp
+++ b/flang/lib/Decimal/binary-to-decimal.cpp
@@ -373,7 +373,8 @@ STREAM &BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Dump(STREAM &o) const {
   if (isNegative_) {
     o << '-';
   }
-  o << "10**(" << exponent_ << ") * ...\n";
+  o << "10**(" << exponent_ << ") * ...  (rounding "
+    << static_cast<int>(rounding_) << ")\n";
   for (int j{digits_}; --j >= 0;) {
     std::string str{std::to_string(digit_[j])};
     o << std::string(20 - str.size(), ' ') << str << " [" << j << ']';
diff --git a/flang/lib/Decimal/decimal-to-binary.cpp b/flang/lib/Decimal/decimal-to-binary.cpp
index c8c7b23329e00ce..d5b66b9fb933888 100644
--- a/flang/lib/Decimal/decimal-to-binary.cpp
+++ b/flang/lib/Decimal/decimal-to-binary.cpp
@@ -257,13 +257,20 @@ ConversionToBinaryResult<PREC> IntermediateFloat<PREC>::ToBinary(
     flags |= Inexact;
   }
   if (fraction == 0 && guard <= oneHalf) {
-    return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
-  }
-  // The value is nonzero; normalize it.
-  while (fraction < topBit && expo > 1) {
-    --expo;
-    fraction = fraction * 2 + (guard >> (guardBits - 2));
-    guard = (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
+    if ((!isNegative && rounding == RoundUp) ||
+        (isNegative && rounding == RoundDown)) {
+      // round to minimum nonzero value
+    } else {
+      return {Binary{}, static_cast<enum ConversionResultFlags>(flags)};
+    }
+  } else {
+    // The value is nonzero; normalize it.
+    while (fraction < topBit && expo > 1) {
+      --expo;
+      fraction = fraction * 2 + (guard >> (guardBits - 2));
+      guard =
+          (((guard >> (guardBits - 2)) & 1) << (guardBits - 1)) | (guard & 1);
+    }
   }
   // Apply rounding
   bool incr{false};
@@ -330,8 +337,13 @@ BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToBinary() {
   exponent_ += digits_ * log10Radix;
   // Sanity checks for ridiculous exponents
   static constexpr int crazy{2 * Real::decimalRange + log10Radix};
-  if (exponent_ < -crazy) { // underflow to +/-0.
-    return {Real{SignBit()}, Inexact};
+  if (exponent_ < -crazy) {
+    if ((!isNegative_ && rounding_ == RoundUp) ||
+        (isNegative_ && rounding_ == RoundDown)) {
+      return {Real{Raw{1} | SignBit()}}; // return least nonzero value
+    } else { // underflow to +/-0.
+      return {Real{SignBit()}, Inexact};
+    }
   } else if (exponent_ > crazy) { // overflow to +/-Inf.
     return {Real{Infinity()}, Overflow};
   }



More information about the flang-commits mailing list