[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