[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