Commit bd43fa29 authored by peter klausler's avatar peter klausler
Browse files

[flang] Implement anonymous units in the runtime

I/O from/to an unopened unit number needs to open &/or create
a "fort.$UNIT" file.

Fixes FCVS test fm401.f.

Reviewed By: tskeith

Differential Revision: https://reviews.llvm.org/D83809
parent 4c22f5f8
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -111,8 +111,8 @@ Cookie BeginExternalListIO(
  if (unitNumber == DefaultUnit) {
    unitNumber = DIR == Direction::Input ? 5 : 6;
  }
  ExternalFileUnit &unit{
      ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)};
  ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
      unitNumber, DIR, false /*formatted*/, terminator)};
  if (unit.access == Access::Direct) {
    terminator.Crash("List-directed I/O attempted on direct access file");
    return nullptr;
@@ -150,8 +150,8 @@ Cookie BeginExternalFormattedIO(const char *format, std::size_t formatLength,
  if (unitNumber == DefaultUnit) {
    unitNumber = DIR == Direction::Input ? 5 : 6;
  }
  ExternalFileUnit &unit{
      ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)};
  ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
      unitNumber, DIR, false /*formatted*/, terminator)};
  if (unit.isUnformatted) {
    terminator.Crash("Formatted I/O attempted on unformatted file");
    return nullptr;
@@ -185,8 +185,8 @@ template <Direction DIR>
Cookie BeginUnformattedIO(
    ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
  Terminator terminator{sourceFile, sourceLine};
  ExternalFileUnit &unit{
      ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)};
  ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous(
      unitNumber, DIR, true /*unformatted*/, terminator)};
  if (!unit.isUnformatted) {
    terminator.Crash("Unformatted output attempted on formatted file");
  }
@@ -223,7 +223,7 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
  bool wasExtant{false};
  Terminator terminator{sourceFile, sourceLine};
  ExternalFileUnit &unit{
      ExternalFileUnit::LookUpOrCreate(unitNumber, terminator, &wasExtant)};
      ExternalFileUnit::LookUpOrCreate(unitNumber, terminator, wasExtant)};
  return &unit.BeginIoStatement<OpenStatementState>(
      unit, wasExtant, sourceFile, sourceLine);
}
@@ -231,10 +231,11 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
    const char *sourceFile, int sourceLine) {
  Terminator terminator{sourceFile, sourceLine};
  bool ignored{false};
  ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreate(
      ExternalFileUnit::NewUnit(terminator), terminator)};
      ExternalFileUnit::NewUnit(terminator), terminator, ignored)};
  return &unit.BeginIoStatement<OpenStatementState>(
      unit, false /*wasExtant*/, sourceFile, sourceLine);
      unit, false /*was an existing file*/, sourceFile, sourceLine);
}

Cookie IONAME(BeginClose)(
+3 −8
Original line number Diff line number Diff line
@@ -27,16 +27,11 @@ public:
  }

  ExternalFileUnit &LookUpOrCreate(
      int n, const Terminator &terminator, bool *wasExtant) {
      int n, const Terminator &terminator, bool &wasExtant) {
    CriticalSection critical{lock_};
    auto *p{Find(n)};
    if (wasExtant) {
      *wasExtant = p != nullptr;
    }
    if (p) {
      return *p;
    }
    return Create(n, terminator);
    wasExtant = p != nullptr;
    return p ? *p : Create(n, terminator);
  }

  ExternalFileUnit &NewUnit(const Terminator &terminator) {
+32 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include "io-error.h"
#include "lock.h"
#include "unit-map.h"
#include <cstdio>

namespace Fortran::runtime::io {

@@ -46,10 +47,38 @@ ExternalFileUnit &ExternalFileUnit::LookUpOrCrash(
}

ExternalFileUnit &ExternalFileUnit::LookUpOrCreate(
    int unit, const Terminator &terminator, bool *wasExtant) {
    int unit, const Terminator &terminator, bool &wasExtant) {
  return GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant);
}

ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous(
    int unit, Direction dir, bool isUnformatted, const Terminator &terminator) {
  bool exists{false};
  ExternalFileUnit &result{
      GetUnitMap().LookUpOrCreate(unit, terminator, exists)};
  if (!exists) {
    // I/O to an unconnected unit reads/creates a local file, e.g. fort.7
    std::size_t pathMaxLen{32};
    auto path{SizedNew<char>{terminator}(pathMaxLen)};
    std::snprintf(path.get(), pathMaxLen, "fort.%d", unit);
    IoErrorHandler handler{terminator};
    result.OpenUnit(
        dir == Direction::Input ? OpenStatus::Old : OpenStatus::Replace,
        Position::Rewind, std::move(path), std::strlen(path.get()), handler);
    result.isUnformatted = isUnformatted;
  }
  return result;
}

ExternalFileUnit &ExternalFileUnit::CreateNew(
    int unit, const Terminator &terminator) {
  bool wasExtant{false};
  ExternalFileUnit &result{
      GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant)};
  RUNTIME_CHECK(terminator, !wasExtant);
  return result;
}

ExternalFileUnit *ExternalFileUnit::LookUpForClose(int unit) {
  return GetUnitMap().LookUpForClose(unit);
}
@@ -155,14 +184,14 @@ UnitMap &ExternalFileUnit::GetUnitMap() {
  Terminator terminator{__FILE__, __LINE__};
  IoErrorHandler handler{terminator};
  unitMap = New<UnitMap>{terminator}().release();
  ExternalFileUnit &out{ExternalFileUnit::LookUpOrCreate(6, terminator)};
  ExternalFileUnit &out{ExternalFileUnit::CreateNew(6, terminator)};
  out.Predefine(1);
  out.set_mayRead(false);
  out.set_mayWrite(true);
  out.set_mayPosition(false);
  out.SetDirection(Direction::Output, handler);
  defaultOutput = &out;
  ExternalFileUnit &in{ExternalFileUnit::LookUpOrCreate(5, terminator)};
  ExternalFileUnit &in{ExternalFileUnit::CreateNew(5, terminator)};
  in.Predefine(0);
  in.set_mayRead(true);
  in.set_mayWrite(false);
+4 −1
Original line number Diff line number Diff line
@@ -39,7 +39,10 @@ public:
  static ExternalFileUnit *LookUp(int unit);
  static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &);
  static ExternalFileUnit &LookUpOrCreate(
      int unit, const Terminator &, bool *wasExtant = nullptr);
      int unit, const Terminator &, bool &wasExtant);
  static ExternalFileUnit &LookUpOrCreateAnonymous(
      int unit, Direction, bool isUnformatted, const Terminator &);
  static ExternalFileUnit &CreateNew(int unit, const Terminator &);
  static ExternalFileUnit *LookUpForClose(int unit);
  static int NewUnit(const Terminator &);
  static void CloseAll(IoErrorHandler &);