[flang-commits] [flang] ef7f6f7 - [flang] Use faster path for default formatted character input

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Mon Mar 7 13:01:15 PST 2022


Author: Peter Klausler
Date: 2022-03-07T13:01:08-08:00
New Revision: ef7f6f7cd7f7956c8bebaf8b29a9895ebbd35af2

URL: https://github.com/llvm/llvm-project/commit/ef7f6f7cd7f7956c8bebaf8b29a9895ebbd35af2
DIFF: https://github.com/llvm/llvm-project/commit/ef7f6f7cd7f7956c8bebaf8b29a9895ebbd35af2.diff

LOG: [flang] Use faster path for default formatted character input

Rather than reading default character variables in formatted
input one byte at a time via NextInField(), skip and read
them via blocks of available buffer data.  This eliminates
a bottleneck that affected reads of large character values.
(It also exposed a problem with sequential reads with RECL=
set on the OPEN statement, so that's fixed too.)

Differential Revision: https://reviews.llvm.org/D121144

Added: 
    

Modified: 
    flang/runtime/edit-input.cpp
    flang/runtime/io-stmt.cpp
    flang/runtime/io-stmt.h
    flang/runtime/unit.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 2e9cd80aa6f9a..ee35bd4c76cde 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -567,24 +567,60 @@ bool EditDefaultCharacterInput(
   if (io.GetConnectionState().IsAtEOF()) {
     return false;
   }
-  std::optional<int> remaining{length};
+  std::size_t remaining{length};
   if (edit.width && *edit.width > 0) {
     remaining = *edit.width;
   }
   // When the field is wider than the variable, we drop the leading
   // characters.  When the variable is wider than the field, there's
   // trailing padding.
-  std::int64_t skip{*remaining - static_cast<std::int64_t>(length)};
-  while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) {
-    if (skip > 0) {
-      --skip;
-      io.GotChar(-1);
-    } else {
-      *x++ = *next;
-      --length;
+  const char *input{nullptr};
+  std::size_t ready{0};
+  bool hitEnd{false};
+  if (remaining > length) {
+    // Discard leading bytes.
+    // These bytes don't count towards INQUIRE(IOLENGTH=).
+    std::size_t skip{remaining - length};
+    do {
+      if (ready == 0) {
+        ready = io.GetNextInputBytes(input);
+        if (ready == 0) {
+          hitEnd = true;
+          break;
+        }
+      }
+      std::size_t chunk{std::min<std::size_t>(skip, ready)};
+      io.HandleRelativePosition(chunk);
+      ready -= chunk;
+      input += chunk;
+      skip -= chunk;
+    } while (skip > 0);
+    remaining = length;
+  }
+  // Transfer payload bytes; these do count.
+  while (remaining > 0) {
+    if (ready == 0) {
+      ready = io.GetNextInputBytes(input);
+      if (ready == 0) {
+        hitEnd = true;
+        break;
+      }
     }
+    std::size_t chunk{std::min<std::size_t>(remaining, ready)};
+    std::memcpy(x, input, chunk);
+    x += chunk;
+    input += chunk;
+    io.GotChar(chunk);
+    io.HandleRelativePosition(chunk);
+    ready -= chunk;
+    remaining -= chunk;
+    length -= chunk;
+  }
+  // Pad the remainder of the input variable, if any.
+  std::memset(x, ' ', length);
+  if (hitEnd) {
+    io.CheckForEndOfRecord(); // signal any needed error
   }
-  std::fill_n(x, length, ' ');
   return true;
 }
 

diff  --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 4f47e36fe78f7..b86559631d1db 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -544,25 +544,30 @@ std::optional<char32_t> IoStatementState::NextInField(
       GotChar();
       return next;
     }
-    const ConnectionState &connection{GetConnectionState()};
-    if (!connection.IsAtEOF()) {
-      if (auto length{connection.EffectiveRecordLength()}) {
-        if (connection.positionInRecord >= *length) {
-          IoErrorHandler &handler{GetIoErrorHandler()};
-          if (mutableModes().nonAdvancing) {
-            handler.SignalEor();
-          } else if (connection.openRecl && !connection.modes.pad) {
-            handler.SignalError(IostatRecordReadOverrun);
-          }
-          if (connection.modes.pad) { // PAD='YES'
-            --*remaining;
-            return std::optional<char32_t>{' '};
-          }
+    if (CheckForEndOfRecord()) { // do padding
+      --*remaining;
+      return std::optional<char32_t>{' '};
+    }
+  }
+  return std::nullopt;
+}
+
+bool IoStatementState::CheckForEndOfRecord() {
+  const ConnectionState &connection{GetConnectionState()};
+  if (!connection.IsAtEOF()) {
+    if (auto length{connection.EffectiveRecordLength()}) {
+      if (connection.positionInRecord >= *length) {
+        IoErrorHandler &handler{GetIoErrorHandler()};
+        if (mutableModes().nonAdvancing) {
+          handler.SignalEor();
+        } else if (connection.openRecl && !connection.modes.pad) {
+          handler.SignalError(IostatRecordReadOverrun);
         }
+        return connection.modes.pad; // PAD='YES'
       }
     }
   }
-  return std::nullopt;
+  return false;
 }
 
 bool IoStatementState::Inquire(

diff  --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 75cf327f05d7c..fef1e261cde29 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -169,6 +169,10 @@ class IoStatementState {
   std::optional<char32_t> NextInField(
       std::optional<int> &remaining, const DataEdit &);
 
+  // Detect and signal any end-of-record condition after input.
+  // Returns true if at EOR and remaining input should be padded with blanks.
+  bool CheckForEndOfRecord();
+
   // Skips spaces, advances records, and ignores NAMELIST comments
   std::optional<char32_t> GetNextNonBlank() {
     auto ch{GetCurrentChar()};

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 6e6db78592783..cef971d00c740 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -299,7 +299,8 @@ bool ExternalFileUnit::Emit(const char *data, std::size_t bytes,
           static_cast<std::intmax_t>(*openRecl));
       return false;
     }
-  } else if (recordLength) {
+  }
+  if (recordLength) {
     // It is possible for recordLength to have a value now for a
     // variable-length output record if the previous operation
     // was a BACKSPACE or non advancing input statement.


        


More information about the flang-commits mailing list