[flang-commits] [flang] 45b5c79 - [flang] Extend & fix per-I/O-statement state (ext. I/O work part 7)
peter klausler via flang-commits
flang-commits at lists.llvm.org
Sat Jul 4 10:49:38 PDT 2020
Author: peter klausler
Date: 2020-07-04T10:49:00-07:00
New Revision: 45b5c79a31d05edb179efeda9305e6c42be4f818
URL: https://github.com/llvm/llvm-project/commit/45b5c79a31d05edb179efeda9305e6c42be4f818
DIFF: https://github.com/llvm/llvm-project/commit/45b5c79a31d05edb179efeda9305e6c42be4f818.diff
LOG: [flang] Extend & fix per-I/O-statement state (ext. I/O work part 7)
The per-I/O-statement state structures need to support missing
external I/O statements, and some bugs found in testing with
formatted input and record advancement are fixed. The effects
of these changes will not be visible until further patches to
the I/O API handlers are pushed.
Reviewed By: tskeith
Differential Revision: https://reviews.llvm.org/D83151
Added:
Modified:
flang/runtime/io-stmt.cpp
flang/runtime/io-stmt.h
flang/runtime/unit.h
Removed:
################################################################################
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 1e2e5f5ec5c8..a4d8af4f7211 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -13,6 +13,7 @@
#include "tools.h"
#include "unit.h"
#include <algorithm>
+#include <cstdio>
#include <cstring>
#include <limits>
@@ -182,10 +183,10 @@ int NoopCloseStatementState::EndIoStatement() {
}
template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
+ if (!unit().nonAdvancing) {
+ unit().AdvanceRecord(*this);
+ }
if constexpr (DIR == Direction::Output) {
- if (!unit().nonAdvancing) {
- unit().AdvanceRecord(*this);
- }
unit().FlushIfTerminal(*this);
}
return ExternalIoStatementBase::EndIoStatement();
@@ -291,7 +292,7 @@ void IoStatementState::BackspaceRecord() {
}
void IoStatementState::HandleRelativePosition(std::int64_t n) {
- return std::visit([=](auto &x) { x.get().HandleRelativePosition(n); }, u_);
+ std::visit([=](auto &x) { x.get().HandleRelativePosition(n); }, u_);
}
int IoStatementState::EndIoStatement() {
@@ -347,15 +348,22 @@ bool IoStatementState::EmitField(
}
}
-void IoStatementState::SkipSpaces(std::optional<int> &remaining) {
- if (!remaining || *remaining > 0) {
- for (auto ch{GetCurrentChar()}; ch && ch == ' '; ch = GetCurrentChar()) {
+std::optional<char32_t> IoStatementState::SkipSpaces(
+ std::optional<int> &remaining) {
+ while (!remaining || *remaining > 0) {
+ if (auto ch{GetCurrentChar()}) {
+ if (*ch != ' ') {
+ return ch;
+ }
HandleRelativePosition(1);
- if (remaining && !--*remaining) {
- break;
+ if (remaining) {
+ --*remaining;
}
+ } else {
+ break;
}
}
+ return std::nullopt;
}
std::optional<char32_t> IoStatementState::NextInField(
@@ -372,6 +380,7 @@ std::optional<char32_t> IoStatementState::NextInField(
case '\'':
case '"':
case '*':
+ case '\n': // for stream access
break;
default:
HandleRelativePosition(1);
@@ -385,7 +394,8 @@ std::optional<char32_t> IoStatementState::NextInField(
return next;
}
const ConnectionState &connection{GetConnectionState()};
- if (!connection.IsAtEOF() && connection.recordLength &&
+ if (!connection.IsAtEOF() && connection.isFixedRecordLength &&
+ connection.recordLength &&
connection.positionInRecord >= *connection.recordLength) {
if (connection.modes.pad) { // PAD='YES'
--*remaining;
@@ -553,29 +563,39 @@ ListDirectedStatementState<Direction::Input>::GetNextDataEdit(
return edit;
}
+template <Direction DIR>
+bool UnformattedIoStatementState<DIR>::Receive(char *data, std::size_t bytes) {
+ if constexpr (DIR == Direction::Output) {
+ this->Crash(
+ "UnformattedIoStatementState::Receive() called for output statement");
+ }
+ return this->unit().Receive(data, bytes, *this);
+}
+
template <Direction DIR>
int UnformattedIoStatementState<DIR>::EndIoStatement() {
- auto &ext{static_cast<ExternalIoStatementState<DIR> &>(*this)};
- ExternalFileUnit &unit{ext.unit()};
- if (unit.access == Access::Sequential && !unit.recordLength.has_value()) {
- // Overwrite the first four bytes of the record with its length,
- // and also append the length. These four bytes were skipped over
- // in BeginUnformattedOutput().
- // TODO: Break very large records up into subrecords with negative
- // headers &/or footers
- union {
- std::uint32_t u;
- char c[sizeof u];
- } u;
- u.u = unit.furthestPositionInRecord - sizeof u.c;
- // TODO: Convert record length to little-endian on big-endian host?
- if (!(ext.Emit(u.c, sizeof u.c) &&
- (ext.HandleAbsolutePosition(0), ext.Emit(u.c, sizeof u.c)) &&
- ext.AdvanceRecord())) {
- return false;
+ ExternalFileUnit &unit{this->unit()};
+ if constexpr (DIR == Direction::Output) {
+ if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
+ // Append the length of a sequential unformatted variable-length record
+ // as its footer, then overwrite the reserved first four bytes of the
+ // record with its length as its header. These four bytes were skipped
+ // over in BeginUnformattedOutput().
+ // TODO: Break very large records up into subrecords with negative
+ // headers &/or footers
+ union {
+ std::uint32_t u;
+ char c[sizeof u];
+ } u;
+ u.u = unit.furthestPositionInRecord - sizeof u;
+ // TODO: Convert record length to little-endian on big-endian host?
+ if (!(this->Emit(u.c, sizeof u) &&
+ (this->HandleAbsolutePosition(0), this->Emit(u.c, sizeof u)))) {
+ return false;
+ }
}
}
- return ext.EndIoStatement();
+ return ExternalIoStatementState<DIR>::EndIoStatement();
}
template class InternalIoStatementState<Direction::Output>;
@@ -592,4 +612,25 @@ template class ExternalListIoStatementState<Direction::Output>;
template class ExternalListIoStatementState<Direction::Input>;
template class UnformattedIoStatementState<Direction::Output>;
template class UnformattedIoStatementState<Direction::Input>;
+
+int ExternalMiscIoStatementState::EndIoStatement() {
+ ExternalFileUnit &ext{unit()};
+ switch (which_) {
+ case Flush:
+ ext.Flush(*this);
+ std::fflush(nullptr); // flushes C stdio output streams (12.9(2))
+ break;
+ case Backspace:
+ ext.BackspaceRecord(*this);
+ break;
+ case Endfile:
+ ext.Endfile(*this);
+ break;
+ case Rewind:
+ ext.Rewind(*this);
+ break;
+ }
+ return ExternalIoStatementBase::EndIoStatement();
+}
+
} // namespace Fortran::runtime::io
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index b8145d79a96a..066391bd1566 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -36,6 +36,7 @@ template <Direction, typename CHAR = char>
class ExternalFormattedIoStatementState;
template <Direction> class ExternalListIoStatementState;
template <Direction> class UnformattedIoStatementState;
+class ExternalMiscIoStatementState;
// The Cookie type in the I/O API is a pointer (for C) to this class.
class IoStatementState {
@@ -73,7 +74,8 @@ class IoStatementState {
bool EmitRepeated(char, std::size_t);
bool EmitField(const char *, std::size_t length, std::size_t width);
- void SkipSpaces(std::optional<int> &remaining);
+
+ std::optional<char32_t> SkipSpaces(std::optional<int> &remaining);
std::optional<char32_t> NextInField(std::optional<int> &remaining);
std::optional<char32_t> GetNextNonBlank(); // can advance record
@@ -94,7 +96,8 @@ class IoStatementState {
std::reference_wrapper<ExternalListIoStatementState<Direction::Output>>,
std::reference_wrapper<ExternalListIoStatementState<Direction::Input>>,
std::reference_wrapper<UnformattedIoStatementState<Direction::Output>>,
- std::reference_wrapper<UnformattedIoStatementState<Direction::Input>>>
+ std::reference_wrapper<UnformattedIoStatementState<Direction::Input>>,
+ std::reference_wrapper<ExternalMiscIoStatementState>>
u_;
};
@@ -235,7 +238,7 @@ class ExternalIoStatementState : public ExternalIoStatementBase,
public:
using ExternalIoStatementBase::ExternalIoStatementBase;
int EndIoStatement();
- bool Emit(const char *, std::size_t chars /* not bytes */);
+ bool Emit(const char *, std::size_t);
bool Emit(const char16_t *, std::size_t chars /* not bytes */);
bool Emit(const char32_t *, std::size_t chars /* not bytes */);
std::optional<char32_t> GetCurrentChar();
@@ -280,6 +283,7 @@ template <Direction DIR>
class UnformattedIoStatementState : public ExternalIoStatementState<DIR> {
public:
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
+ bool Receive(char *, std::size_t);
int EndIoStatement();
};
@@ -353,5 +357,17 @@ extern template class FormatControl<
extern template class FormatControl<
ExternalFormattedIoStatementState<Direction::Input>>;
+class ExternalMiscIoStatementState : public ExternalIoStatementBase {
+public:
+ enum Which { Flush, Backspace, Endfile, Rewind };
+ ExternalMiscIoStatementState(ExternalFileUnit &unit, Which which,
+ const char *sourceFile = nullptr, int sourceLine = 0)
+ : ExternalIoStatementBase{unit, sourceFile, sourceLine}, which_{which} {}
+ int EndIoStatement();
+
+private:
+ Which which_;
+};
+
} // namespace Fortran::runtime::io
#endif // FORTRAN_RUNTIME_IO_STMT_H_
diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index bdc7a94e0a1a..c54625413b87 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -106,7 +106,8 @@ class ExternalFileUnit : public ConnectionState,
ExternalListIoStatementState<Direction::Output>,
ExternalListIoStatementState<Direction::Input>,
UnformattedIoStatementState<Direction::Output>,
- UnformattedIoStatementState<Direction::Input>>
+ UnformattedIoStatementState<Direction::Input>,
+ ExternalMiscIoStatementState>
u_;
// Points to the active alternative (if any) in u_ for use as a Cookie
More information about the flang-commits
mailing list