[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