[flang-commits] [flang] 199a623 - [flang] Runtime must defer formatted/unformatted determination
peter klausler via flang-commits
flang-commits at lists.llvm.org
Thu May 6 11:06:54 PDT 2021
Author: peter klausler
Date: 2021-05-06T11:06:43-07:00
New Revision: 199a623ebf808a01e920ebd9904c99e633c33a1f
URL: https://github.com/llvm/llvm-project/commit/199a623ebf808a01e920ebd9904c99e633c33a1f
DIFF: https://github.com/llvm/llvm-project/commit/199a623ebf808a01e920ebd9904c99e633c33a1f.diff
LOG: [flang] Runtime must defer formatted/unformatted determination
What the Fortran standard calls "preconnected" external I/O units
might not be known to be connected to unformatted or formatted files
until the first I/O data transfer statement is executed.
Support this deferred determination by representing the flag as
a tri-state Boolean and adapting its points of use.
Differential Revision: https://reviews.llvm.org/D101929
Added:
Modified:
flang/runtime/connection.h
flang/runtime/io-api.cpp
flang/runtime/io-stmt.cpp
flang/runtime/unit.cpp
flang/runtime/unit.h
Removed:
################################################################################
diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index ba1e27c0cad2..24aae6588aa6 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -26,7 +26,7 @@ inline bool IsRecordFile(Access a) { return a != Access::Stream; }
// established in an OPEN statement.
struct ConnectionAttributes {
Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM'
- bool isUnformatted{false}; // FORM='UNFORMATTED'
+ std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true
bool isUTF8{false}; // ENCODING='UTF-8'
bool isFixedRecordLength{false}; // RECL= on OPEN
std::optional<std::int64_t> recordLength; // RECL= or current record
diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index c9cfb20b07b2..1fa2fb91b779 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -155,12 +155,15 @@ Cookie BeginExternalListIO(
unitNumber = DIR == Direction::Input ? 5 : 6;
}
ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
- unitNumber, DIR, false /*formatted*/, terminator)};
+ unitNumber, DIR, false /*!unformatted*/, terminator)};
if (unit.access == Access::Direct) {
terminator.Crash("List-directed I/O attempted on direct access file");
return nullptr;
}
- if (unit.isUnformatted) {
+ if (!unit.isUnformatted.has_value()) {
+ unit.isUnformatted = false;
+ }
+ if (*unit.isUnformatted) {
terminator.Crash("List-directed I/O attempted on unformatted file");
return nullptr;
}
@@ -191,8 +194,11 @@ Cookie BeginExternalFormattedIO(const char *format, std::size_t formatLength,
unitNumber = DIR == Direction::Input ? 5 : 6;
}
ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
- unitNumber, DIR, false /*formatted*/, terminator)};
- if (unit.isUnformatted) {
+ unitNumber, DIR, false /*!unformatted*/, terminator)};
+ if (!unit.isUnformatted.has_value()) {
+ unit.isUnformatted = false;
+ }
+ if (*unit.isUnformatted) {
terminator.Crash("Formatted I/O attempted on unformatted file");
return nullptr;
}
@@ -224,8 +230,11 @@ Cookie BeginUnformattedIO(
Terminator terminator{sourceFile, sourceLine};
ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
unitNumber, DIR, true /*unformatted*/, terminator)};
- if (!unit.isUnformatted) {
- terminator.Crash("Unformatted output attempted on formatted file");
+ if (!unit.isUnformatted.has_value()) {
+ unit.isUnformatted = true;
+ }
+ if (!*unit.isUnformatted) {
+ terminator.Crash("Unformatted I/O attempted on formatted file");
}
IoStatementState &io{unit.BeginIoStatement<UnformattedIoStatementState<DIR>>(
unit, sourceFile, sourceLine)};
@@ -310,7 +319,7 @@ Cookie IONAME(BeginEndfile)(
ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Terminator terminator{sourceFile, sourceLine};
ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
- unitNumber, Direction::Output, false /*formatted*/, terminator)};
+ unitNumber, Direction::Output, std::nullopt, terminator)};
return &unit.BeginIoStatement<ExternalMiscIoStatementState>(
unit, ExternalMiscIoStatementState::Endfile, sourceFile, sourceLine);
}
@@ -319,7 +328,7 @@ Cookie IONAME(BeginRewind)(
ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
Terminator terminator{sourceFile, sourceLine};
ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
- unitNumber, Direction::Input, false /*formatted*/, terminator)};
+ unitNumber, Direction::Input, std::nullopt, terminator)};
return &unit.BeginIoStatement<ExternalMiscIoStatementState>(
unit, ExternalMiscIoStatementState::Rewind, sourceFile, sourceLine);
}
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 2fd60903a7da..89279b3bcc1b 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -203,10 +203,10 @@ int OpenStatementState::EndIoStatement() {
}
unit().access = *access_;
}
- if (!isUnformatted_) {
- isUnformatted_ = unit().access != Access::Sequential;
+ if (!unit().isUnformatted) {
+ unit().isUnformatted = isUnformatted_;
}
- if (*isUnformatted_ != unit().isUnformatted) {
+ if (isUnformatted_ && *isUnformatted_ != *unit().isUnformatted) {
if (wasExtant_) {
SignalError("FORM= may not be changed on an open unit");
}
@@ -757,7 +757,7 @@ bool InquireUnitState::Inquire(
str = unit().mayAsynchronous() ? "YES" : "NO";
break;
case HashInquiryKeyword("BLANK"):
- str = unit().isUnformatted ? "UNDEFINED"
+ str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
: unit().modes.editingFlags & blankZero ? "ZERO"
: "NULL";
break;
@@ -768,12 +768,12 @@ bool InquireUnitState::Inquire(
str = unit().swapEndianness() ? "SWAP" : "NATIVE";
break;
case HashInquiryKeyword("DECIMAL"):
- str = unit().isUnformatted ? "UNDEFINED"
+ str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
: unit().modes.editingFlags & decimalComma ? "COMMA"
: "POINT";
break;
case HashInquiryKeyword("DELIM"):
- if (unit().isUnformatted) {
+ if (unit().isUnformatted.value_or(true)) {
str = "UNDEFINED";
} else {
switch (unit().modes.delim) {
@@ -796,15 +796,19 @@ bool InquireUnitState::Inquire(
: "NO";
break;
case HashInquiryKeyword("ENCODING"):
- str = unit().isUnformatted ? "UNDEFINED"
- : unit().isUTF8 ? "UTF-8"
- : "ASCII";
+ str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
+ : unit().isUTF8 ? "UTF-8"
+ : "ASCII";
break;
case HashInquiryKeyword("FORM"):
- str = unit().isUnformatted ? "UNFORMATTED" : "FORMATTED";
+ str = !unit().isUnformatted ? "UNKNOWN"
+ : *unit().isUnformatted ? "UNFORMATTED"
+ : "FORMATTED";
break;
case HashInquiryKeyword("FORMATTED"):
- str = !unit().isUnformatted ? "YES" : "NO";
+ str = !unit().isUnformatted ? "UNKNOWN"
+ : *unit().isUnformatted ? "NO"
+ : "YES";
break;
case HashInquiryKeyword("NAME"):
str = unit().path();
@@ -813,7 +817,9 @@ bool InquireUnitState::Inquire(
}
break;
case HashInquiryKeyword("PAD"):
- str = unit().isUnformatted ? "UNDEFINED" : unit().modes.pad ? "YES" : "NO";
+ str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
+ : unit().modes.pad ? "YES"
+ : "NO";
break;
case HashInquiryKeyword("POSITION"):
if (unit().access == Access::Direct) {
@@ -837,7 +843,7 @@ bool InquireUnitState::Inquire(
str = unit().mayRead() && unit().mayWrite() ? "YES" : "NO";
break;
case HashInquiryKeyword("ROUND"):
- if (unit().isUnformatted) {
+ if (unit().isUnformatted.value_or(true)) {
str = "UNDEFINED";
} else {
switch (unit().modes.round) {
@@ -865,7 +871,7 @@ bool InquireUnitState::Inquire(
str = unit().access == Access::Sequential ? "YES" : "NO";
break;
case HashInquiryKeyword("SIGN"):
- str = unit().isUnformatted ? "UNDEFINED"
+ str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
: unit().modes.editingFlags & signPlus ? "PLUS"
: "SUPPRESS";
break;
@@ -876,7 +882,9 @@ bool InquireUnitState::Inquire(
str = unit().mayWrite() ? "YES" : "NO";
break;
case HashInquiryKeyword("UNFORMATTED"):
- str = unit().isUnformatted ? "YES" : "NO";
+ str = !unit().isUnformatted ? "UNKNOWN"
+ : *unit().isUnformatted ? "YES"
+ : "NO";
break;
}
if (str) {
diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index e84385d4e267..78fa216b4099 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -53,8 +53,9 @@ ExternalFileUnit &ExternalFileUnit::LookUpOrCreate(
return GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant);
}
-ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(
- int unit, Direction dir, bool isUnformatted, const Terminator &terminator) {
+ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
+ Direction dir, std::optional<bool> isUnformatted,
+ const Terminator &terminator) {
bool exists{false};
ExternalFileUnit &result{
GetUnitMap().LookUpOrCreate(unit, terminator, exists)};
@@ -313,7 +314,7 @@ std::optional<char32_t> ExternalFileUnit::GetCurrentChar(
const char *ExternalFileUnit::FrameNextInput(
IoErrorHandler &handler, std::size_t bytes) {
- RUNTIME_CHECK(handler, !isUnformatted);
+ RUNTIME_CHECK(handler, isUnformatted.has_value() && !*isUnformatted);
if (static_cast<std::int64_t>(positionInRecord + bytes) <=
recordLength.value_or(positionInRecord + bytes)) {
auto at{recordOffsetInFrame_ + positionInRecord};
@@ -367,10 +368,13 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
if (got < need) {
handler.SignalEnd();
}
- } else if (isUnformatted) {
- BeginSequentialVariableUnformattedInputRecord(handler);
- } else { // formatted
- BeginSequentialVariableFormattedInputRecord(handler);
+ } else {
+ RUNTIME_CHECK(handler, isUnformatted.has_value());
+ if (isUnformatted.value_or(false)) {
+ BeginSequentialVariableUnformattedInputRecord(handler);
+ } else { // formatted
+ BeginSequentialVariableFormattedInputRecord(handler);
+ }
}
}
}
@@ -390,18 +394,21 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
if (isFixedRecordLength) {
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
recordOffsetInFrame_ = 0;
- } else if (isUnformatted) {
- // Retain footer in frame for more efficient BACKSPACE
- frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
- recordOffsetInFrame_ = sizeof(std::uint32_t);
- recordLength.reset();
- } else { // formatted
- if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') {
- ++recordOffsetInFrame_;
+ } else {
+ RUNTIME_CHECK(handler, isUnformatted.has_value());
+ if (isUnformatted.value_or(false)) {
+ // Retain footer in frame for more efficient BACKSPACE
+ frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
+ recordOffsetInFrame_ = sizeof(std::uint32_t);
+ recordLength.reset();
+ } else { // formatted
+ if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') {
+ ++recordOffsetInFrame_;
+ }
+ recordOffsetInFrame_ += *recordLength + 1;
+ RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n');
+ recordLength.reset();
}
- recordOffsetInFrame_ += *recordLength + 1;
- RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n');
- recordLength.reset();
}
}
++currentRecordNumber;
@@ -414,17 +421,19 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
return BeginReadingRecord(handler);
} else { // Direction::Output
bool ok{true};
+ RUNTIME_CHECK(handler, isUnformatted.has_value());
if (isFixedRecordLength && recordLength) {
// Pad remainder of fixed length record
if (furthestPositionInRecord < *recordLength) {
WriteFrame(
frameOffsetInFile_, recordOffsetInFrame_ + *recordLength, handler);
std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord,
- isUnformatted ? 0 : ' ', *recordLength - furthestPositionInRecord);
+ isUnformatted.value_or(false) ? 0 : ' ',
+ *recordLength - furthestPositionInRecord);
}
} else {
positionInRecord = furthestPositionInRecord;
- if (isUnformatted) {
+ if (isUnformatted.value_or(false)) {
// 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
@@ -466,10 +475,13 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
--currentRecordNumber;
if (isFixedRecordLength) {
BackspaceFixedRecord(handler);
- } else if (isUnformatted) {
- BackspaceVariableUnformattedRecord(handler);
} else {
- BackspaceVariableFormattedRecord(handler);
+ RUNTIME_CHECK(handler, isUnformatted.has_value());
+ if (isUnformatted.value_or(false)) {
+ BackspaceVariableUnformattedRecord(handler);
+ } else {
+ BackspaceVariableFormattedRecord(handler);
+ }
}
}
}
diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index c9db5fceac5b..9634f1a95804 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -41,8 +41,8 @@ class ExternalFileUnit : public ConnectionState,
static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &);
static ExternalFileUnit &LookUpOrCreate(
int unit, const Terminator &, bool &wasExtant);
- static ExternalFileUnit &LookUpOrCreateAnonymous(
- int unit, Direction, bool isUnformatted, const Terminator &);
+ static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction,
+ std::optional<bool> isUnformatted, const Terminator &);
static ExternalFileUnit *LookUp(const char *path);
static ExternalFileUnit &CreateNew(int unit, const Terminator &);
static ExternalFileUnit *LookUpForClose(int unit);
More information about the flang-commits
mailing list