From bba451366f7bbb3ff653f4bcda56f586cece03cb Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Wed, 9 Apr 2025 09:33:46 -0700 Subject: [PATCH] [flang][runtime] Tweak width-free I/G formatted I&O For Fujitsu test case 0561/0561_0168.f90, adjust both input and output sides of the extension I (and G) edit descriptors with no width (as distinct from I0/G0). On input, be sure to halt on a separator character rather than complaining about an invalid character; on output, be sure to emit a leading space. --- flang-rt/lib/runtime/edit-output.cpp | 49 +++++++++++++++------------- flang-rt/lib/runtime/io-stmt.cpp | 7 ++-- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/flang-rt/lib/runtime/edit-output.cpp b/flang-rt/lib/runtime/edit-output.cpp index 36bbc638ff5fc..3699213e1f7b7 100644 --- a/flang-rt/lib/runtime/edit-output.cpp +++ b/flang-rt/lib/runtime/edit-output.cpp @@ -17,7 +17,7 @@ namespace Fortran::runtime::io { RT_OFFLOAD_API_GROUP_BEGIN // In output statement, add a space between numbers and characters. -static RT_API_ATTRS void addSpaceBeforeCharacter(IoStatementState &io) { +static RT_API_ATTRS void AddSpaceBeforeCharacter(IoStatementState &io) { if (auto *list{io.get_if>()}) { list->set_lastWasUndelimitedCharacter(false); } @@ -29,7 +29,7 @@ static RT_API_ATTRS void addSpaceBeforeCharacter(IoStatementState &io) { template static RT_API_ATTRS bool EditBOZOutput(IoStatementState &io, const DataEdit &edit, const unsigned char *data0, std::size_t bytes) { - addSpaceBeforeCharacter(io); + AddSpaceBeforeCharacter(io); int digits{static_cast((bytes * 8) / LOG2_BASE)}; int get{static_cast(bytes * 8) - digits * LOG2_BASE}; if (get > 0) { @@ -110,27 +110,11 @@ static RT_API_ATTRS bool EditBOZOutput(IoStatementState &io, template bool RT_API_ATTRS EditIntegerOutput(IoStatementState &io, const DataEdit &edit, common::HostSignedIntType<8 * KIND> n, bool isSigned) { - addSpaceBeforeCharacter(io); - char buffer[130], *end{&buffer[sizeof buffer]}, *p{end}; - bool isNegative{isSigned && n < 0}; - using Unsigned = common::HostUnsignedIntType<8 * KIND>; - Unsigned un{static_cast(n)}; - int signChars{0}; + AddSpaceBeforeCharacter(io); switch (edit.descriptor) { case DataEdit::ListDirected: case 'G': case 'I': - if (isNegative) { - un = -un; - } - if (isNegative || (edit.modes.editingFlags & signPlus)) { - signChars = 1; // '-' or '+' - } - while (un > 0) { - auto quotient{un / 10u}; - *--p = '0' + static_cast(un - Unsigned{10} * quotient); - un = quotient; - } break; case 'B': return EditBOZOutput<1>( @@ -152,7 +136,22 @@ bool RT_API_ATTRS EditIntegerOutput(IoStatementState &io, const DataEdit &edit, edit.descriptor); return false; } - + char buffer[130], *end{&buffer[sizeof buffer]}, *p{end}; + bool isNegative{isSigned && n < 0}; + using Unsigned = common::HostUnsignedIntType<8 * KIND>; + Unsigned un{static_cast(n)}; + int signChars{0}; + if (isNegative) { + un = -un; + } + if (isNegative || (edit.modes.editingFlags & signPlus)) { + signChars = 1; // '-' or '+' + } + while (un > 0) { + auto quotient{un / 10u}; + *--p = '0' + static_cast(un - Unsigned{10} * quotient); + un = quotient; + } int digits = end - p; int leadingZeroes{0}; int editWidth{edit.width.value_or(0)}; @@ -181,6 +180,10 @@ bool RT_API_ATTRS EditIntegerOutput(IoStatementState &io, const DataEdit &edit, return false; } leadingSpaces = 1; + } else if (!edit.width) { + // Bare 'I' and 'G' are interpreted with various default widths in the + // compilers that support them, so there's always some leading space. + leadingSpaces = std::max(1, leadingSpaces); } return EmitRepeated(io, ' ', leadingSpaces) && EmitAscii(io, n < 0 ? "-" : "+", signChars) && @@ -291,7 +294,7 @@ static RT_API_ATTRS bool IsInfOrNaN(const char *p, int length) { template RT_API_ATTRS bool RealOutputEditing::EditEorDOutput( const DataEdit &edit) { - addSpaceBeforeCharacter(io_); + AddSpaceBeforeCharacter(io_); int editDigits{edit.digits.value_or(0)}; // 'd' field int editWidth{edit.width.value_or(0)}; // 'w' field int significantDigits{editDigits}; @@ -427,7 +430,7 @@ RT_API_ATTRS bool RealOutputEditing::EditEorDOutput( // 13.7.2.3.2 in F'2018 template RT_API_ATTRS bool RealOutputEditing::EditFOutput(const DataEdit &edit) { - addSpaceBeforeCharacter(io_); + AddSpaceBeforeCharacter(io_); int fracDigits{edit.digits.value_or(0)}; // 'd' field const int editWidth{edit.width.value_or(0)}; // 'w' field enum decimal::FortranRounding rounding{edit.modes.round}; @@ -702,7 +705,7 @@ RT_API_ATTRS auto RealOutputEditing::ConvertToHexadecimal( template RT_API_ATTRS bool RealOutputEditing::EditEXOutput(const DataEdit &edit) { - addSpaceBeforeCharacter(io_); + AddSpaceBeforeCharacter(io_); int editDigits{edit.digits.value_or(0)}; // 'd' field int significantDigits{editDigits + 1}; int flags{0}; diff --git a/flang-rt/lib/runtime/io-stmt.cpp b/flang-rt/lib/runtime/io-stmt.cpp index 636351f560b0a..19b13c128b196 100644 --- a/flang-rt/lib/runtime/io-stmt.cpp +++ b/flang-rt/lib/runtime/io-stmt.cpp @@ -631,10 +631,11 @@ Fortran::common::optional IoStatementState::GetCurrentChar( Fortran::common::optional IoStatementState::NextInField( Fortran::common::optional &remaining, const DataEdit &edit) { std::size_t byteCount{0}; - if (!remaining) { // Stream, list-directed, or NAMELIST + if (!remaining) { // Stream, list-directed, NAMELIST, &c. if (auto next{GetCurrentChar(byteCount)}) { - if (edit.IsListDirected()) { - // list-directed or NAMELIST: check for separators + if (edit.width.value_or(0) == 0) { + // list-directed, NAMELIST, I0 &c., or width-free I/G: + // check for separator character switch (*next) { case ' ': case '\t':