diff --git a/flang-rt/lib/runtime/edit-output.cpp b/flang-rt/lib/runtime/edit-output.cpp index 73dba35ff08d..78fb2499cc59 100644 --- a/flang-rt/lib/runtime/edit-output.cpp +++ b/flang-rt/lib/runtime/edit-output.cpp @@ -266,10 +266,23 @@ RT_API_ATTRS bool RealOutputEditingBase::EmitSuffix(const DataEdit &edit) { } } +static RT_API_ATTRS char IsInfOrNaN(const char *p, std::size_t length) { + if (!p || length < 1) { + return '\0'; + } + if (*p == '-' || *p == '+') { + if (length == 1) { + return '\0'; + } + ++p; + } + return *p == 'I' || *p == 'N' ? *p : '\0'; +} + template RT_API_ATTRS decimal::ConversionToDecimalResult -RealOutputEditing::ConvertToDecimal( - int significantDigits, enum decimal::FortranRounding rounding, int flags) { +RealOutputEditing::ConvertToDecimal(int significantDigits, + enum decimal::FortranRounding rounding, int width, int flags) { auto converted{decimal::ConvertToDecimal(buffer_, sizeof buffer_, static_cast(flags), significantDigits, rounding, x_)}; @@ -277,23 +290,18 @@ RealOutputEditing::ConvertToDecimal( io_.GetIoErrorHandler().Crash( "RealOutputEditing::ConvertToDecimal: buffer size %zd was insufficient", sizeof buffer_); + } else if (IsInfOrNaN(converted.str, converted.length) == 'I' && + converted.length <= 4 && + static_cast(converted.length + 5) <= width) { + // Emit "Infinity" rather than "Inf" (F'2023 13.7.2.3.2 p9), possibly signed + std::memcpy(buffer_, converted.str, converted.length); + std::memcpy(buffer_ + converted.length, "inity", 5); + converted.str = buffer_; + converted.length += 5; } return converted; } -static RT_API_ATTRS bool IsInfOrNaN(const char *p, int length) { - if (!p || length < 1) { - return false; - } - if (*p == '-' || *p == '+') { - if (length == 1) { - return false; - } - ++p; - } - return *p == 'I' || *p == 'N'; -} - // 13.7.2.3.3 in F'2018 template RT_API_ATTRS bool RealOutputEditing::EditEorDOutput( @@ -353,9 +361,9 @@ RT_API_ATTRS bool RealOutputEditing::EditEorDOutput( } // In EN editing, multiple attempts may be necessary, so this is a loop. while (true) { - decimal::ConversionToDecimalResult converted{ - ConvertToDecimal(significantDigits, edit.modes.round, flags)}; - if (IsInfOrNaN(converted.str, static_cast(converted.length))) { + decimal::ConversionToDecimalResult converted{ConvertToDecimal( + significantDigits, edit.modes.round, editWidth, flags)}; + if (IsInfOrNaN(converted.str, converted.length)) { return editWidth > 0 && converted.length + trailingBlanks_ > static_cast(editWidth) @@ -454,9 +462,9 @@ RT_API_ATTRS bool RealOutputEditing::EditFOutput(const DataEdit &edit) { bool canIncrease{true}; for (int extraDigits{fracDigits == 0 ? 1 : 0};;) { decimal::ConversionToDecimalResult converted{ - ConvertToDecimal(extraDigits + fracDigits, rounding, flags)}; + ConvertToDecimal(extraDigits + fracDigits, rounding, editWidth, flags)}; const char *convertedStr{converted.str}; - if (IsInfOrNaN(convertedStr, static_cast(converted.length))) { + if (IsInfOrNaN(converted.str, converted.length)) { return editWidth > 0 && converted.length > static_cast(editWidth) ? EmitRepeated(io_, '*', editWidth) @@ -585,8 +593,8 @@ RT_API_ATTRS DataEdit RealOutputEditing::EditForGOutput(DataEdit edit) { flags |= decimal::AlwaysSign; } decimal::ConversionToDecimalResult converted{ - ConvertToDecimal(significantDigits, edit.modes.round, flags)}; - if (IsInfOrNaN(converted.str, static_cast(converted.length))) { + ConvertToDecimal(significantDigits, edit.modes.round, editWidth, flags)}; + if (IsInfOrNaN(converted.str, converted.length)) { return edit; // Inf/Nan -> Ew.d (same as Fw.d) } int expo{IsZero() ? 1 : converted.decimalExponent}; // 's' @@ -619,7 +627,7 @@ RT_API_ATTRS bool RealOutputEditing::EditListDirectedOutput( const DataEdit &edit) { decimal::ConversionToDecimalResult converted{ ConvertToDecimal(1, edit.modes.round)}; - if (IsInfOrNaN(converted.str, static_cast(converted.length))) { + if (IsInfOrNaN(converted.str, converted.length)) { DataEdit copy{edit}; copy.variation = DataEdit::ListDirected; return EditEorDOutput(copy); @@ -652,15 +660,17 @@ RT_API_ATTRS bool RealOutputEditing::EditListDirectedOutput( template RT_API_ATTRS auto RealOutputEditing::ConvertToHexadecimal( int significantDigits, enum decimal::FortranRounding rounding, - int flags) -> ConvertToHexadecimalResult { + int editWidth, int flags) -> ConvertToHexadecimalResult { if (x_.IsNaN() || x_.IsInfinite()) { - auto converted{ConvertToDecimal(significantDigits, rounding, flags)}; - return {converted.str, static_cast(converted.length), 0}; + auto converted{ + ConvertToDecimal(significantDigits, rounding, editWidth, flags)}; + return {converted.str, static_cast(converted.length), /*exponent=*/0}; } x_.RoundToBits(4 * significantDigits, rounding); if (x_.IsInfinite()) { // rounded away to +/-Inf - auto converted{ConvertToDecimal(significantDigits, rounding, flags)}; - return {converted.str, static_cast(converted.length), 0}; + auto converted{ + ConvertToDecimal(significantDigits, rounding, editWidth, flags)}; + return {converted.str, static_cast(converted.length), /*exponent=*/0}; } int len{0}; if (x_.IsNegative()) { @@ -724,8 +734,8 @@ RT_API_ATTRS bool RealOutputEditing::EditEXOutput(const DataEdit &edit) { (common::PrecisionOfRealKind(16) + 3) / 4}; significantDigits = maxSigHexDigits; } - auto converted{ - ConvertToHexadecimal(significantDigits, edit.modes.round, flags)}; + auto converted{ConvertToHexadecimal( + significantDigits, edit.modes.round, editWidth, flags)}; if (IsInfOrNaN(converted.str, converted.length)) { return editWidth > 0 && converted.length > editWidth ? EmitRepeated(io_, '*', editWidth) diff --git a/flang-rt/lib/runtime/edit-output.h b/flang-rt/lib/runtime/edit-output.h index dbeccb291d36..5df31b4dc76d 100644 --- a/flang-rt/lib/runtime/edit-output.h +++ b/flang-rt/lib/runtime/edit-output.h @@ -77,7 +77,8 @@ private: RT_API_ATTRS bool IsZero() const { return x_.IsZero(); } RT_API_ATTRS decimal::ConversionToDecimalResult ConvertToDecimal( - int significantDigits, enum decimal::FortranRounding, int flags = 0); + int significantDigits, enum decimal::FortranRounding, + int width = 3 /*len("Inf")*/, int flags = 0); struct ConvertToHexadecimalResult { const char *str; @@ -85,7 +86,8 @@ private: int exponent; }; RT_API_ATTRS ConvertToHexadecimalResult ConvertToHexadecimal( - int significantDigits, enum decimal::FortranRounding, int flags = 0); + int significantDigits, enum decimal::FortranRounding, int width, + int flags); BinaryFloatingPoint x_; char buffer_[BinaryFloatingPoint::maxDecimalConversionDigits + diff --git a/flang-rt/unittests/Runtime/NumericalFormatTest.cpp b/flang-rt/unittests/Runtime/NumericalFormatTest.cpp index dbde52dee6ee..bfabf160658e 100644 --- a/flang-rt/unittests/Runtime/NumericalFormatTest.cpp +++ b/flang-rt/unittests/Runtime/NumericalFormatTest.cpp @@ -406,23 +406,23 @@ TEST(IOApiTests, FormatDoubleValues) { {// +Inf 0x7ff0000000000000, { - {"(E9.1,';')", " Inf;"}, - {"(F9.1,';')", " Inf;"}, - {"(G9.1,';')", " Inf;"}, - {"(EX9.1,';')", " Inf;"}, - {"(SP,E9.1,';')", " +Inf;"}, - {"(SP,F9.1,';')", " +Inf;"}, - {"(SP,G9.1,';')", " +Inf;"}, - {"(SP,EX9.1,';')", " +Inf;"}, + {"(E9.1,';')", " Infinity;"}, + {"(F9.1,';')", " Infinity;"}, + {"(G9.1,';')", " Infinity;"}, + {"(EX9.1,';')", " Infinity;"}, + {"(SP,E9.1,';')", "+Infinity;"}, + {"(SP,F9.1,';')", "+Infinity;"}, + {"(SP,G9.1,';')", "+Infinity;"}, + {"(SP,EX9.1,';')", "+Infinity;"}, {"(G0,';')", "Inf;"}, }}, {// -Inf 0xfff0000000000000, { - {"(E9.1,';')", " -Inf;"}, - {"(F9.1,';')", " -Inf;"}, - {"(G9.1,';')", " -Inf;"}, - {"(EX9.1,';')", " -Inf;"}, + {"(E9.1,';')", "-Infinity;"}, + {"(F9.1,';')", "-Infinity;"}, + {"(G9.1,';')", "-Infinity;"}, + {"(EX9.1,';')", "-Infinity;"}, {"(G0,';')", "-Inf;"}, }}, {// NaN