[llvm] [flang][runtime] Tweak width-free I/G formatted I&O (PR #135047)
Peter Klausler via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 9 09:48:37 PDT 2025
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/135047
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.
>From bba451366f7bbb3ff653f4bcda56f586cece03cb Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
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<ListDirectedStatementState<Direction::Output>>()}) {
list->set_lastWasUndelimitedCharacter(false);
}
@@ -29,7 +29,7 @@ static RT_API_ATTRS void addSpaceBeforeCharacter(IoStatementState &io) {
template <int LOG2_BASE>
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<int>((bytes * 8) / LOG2_BASE)};
int get{static_cast<int>(bytes * 8) - digits * LOG2_BASE};
if (get > 0) {
@@ -110,27 +110,11 @@ static RT_API_ATTRS bool EditBOZOutput(IoStatementState &io,
template <int KIND>
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<Unsigned>(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<int>(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<Unsigned>(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<int>(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 <int KIND>
RT_API_ATTRS bool RealOutputEditing<KIND>::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<KIND>::EditEorDOutput(
// 13.7.2.3.2 in F'2018
template <int KIND>
RT_API_ATTRS bool RealOutputEditing<KIND>::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<KIND>::ConvertToHexadecimal(
template <int KIND>
RT_API_ATTRS bool RealOutputEditing<KIND>::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<char32_t> IoStatementState::GetCurrentChar(
Fortran::common::optional<char32_t> IoStatementState::NextInField(
Fortran::common::optional<int> &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':
More information about the llvm-commits
mailing list