[flang-commits] [flang] [flang][runtime] Implement EX editing for input & output (PR #67208)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Sep 25 10:01:19 PDT 2023


================
@@ -567,11 +587,119 @@ bool RealOutputEditing<KIND>::EditListDirectedOutput(const DataEdit &edit) {
   return EditFOutput(edit);
 }
 
-// 13.7.5.2.6 in F'2018
+// 13.7.2.3.6 in F'2023
+// The specification for hexadecimal output, unfortunately for implementors,
+// leaves as "implementation dependent" the choice of how to emit values
+// with multiple hexadecimal output possibilities that are numerically
+// equivalent.  The one working implementation of EX output that I can find
+// apparently chooses to frame the nybbles from most to least significant,
+// rather than trying to minimize the magnitude of the binary exponent.
+// E.g., 2. is edited into 0X8.0P-2 rather than 0X2.0P0.  This implementation
+// follows that precedent so as to avoid a gratuitous incompatibility.
 template <int KIND>
-bool RealOutputEditing<KIND>::EditEXOutput(const DataEdit &) {
-  io_.GetIoErrorHandler().Crash(
-      "not yet implemented: EX output editing"); // TODO
+auto RealOutputEditing<KIND>::ConvertToHexadecimal(
+    int significantDigits, enum decimal::FortranRounding rounding, int flags)
+    -> ConvertToHexadecimalResult {
+  if (x_.IsNaN() || x_.IsInfinite()) {
+    auto converted{ConvertToDecimal(significantDigits, rounding, flags)};
+    return {converted.str, static_cast<int>(converted.length), 0};
+  }
+  x_.RoundToBits(4 * significantDigits, rounding);
+  if (x_.IsInfinite()) { // rounded away to +/-Inf
+    auto converted{ConvertToDecimal(significantDigits, rounding, flags)};
+    return {converted.str, static_cast<int>(converted.length), 0};
+  }
+  int len{0};
+  if (x_.IsNegative()) {
+    buffer_[len++] = '-';
+  } else if (flags & decimal::AlwaysSign) {
+    buffer_[len++] = '+';
+  }
+  auto fraction{x_.Fraction()};
+  if (fraction == 0) {
+    buffer_[len++] = '0';
+    return {buffer_, len, 0};
+  } else {
+    // Ensure that the MSB is set.
+    int expo{x_.UnbiasedExponent() - 3};
+    while (!(fraction >> (x_.binaryPrecision - 1))) {
+      fraction <<= 1;
+      --expo;
+    }
+    // This is initially the right shift count needed to bring the
+    // most-significant hexadecimal digit's bits into the LSBs.
+    // x_.binaryPrecision is constant, so / can be used for readability.
+    int shift{x_.binaryPrecision - 4};
+    typename BinaryFloatingPoint::RawType one{1};
+    auto remaining{(one << shift) - one};
+    for (int digits{0}; digits < significantDigits; ++digits) {
+      if ((flags & decimal::Minimize) && !(fraction & remaining)) {
+        break;
+      }
+      int hexDigit{0};
+      if (shift >= 0) {
+        hexDigit = (fraction >> shift) & 0xf;
----------------
klausler wrote:

Fixed.

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


More information about the flang-commits mailing list