[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