[flang-commits] [flang] cc01194 - [flang] Descriptor-based I/O data item transfers

peter klausler via flang-commits flang-commits at lists.llvm.org
Fri Aug 7 13:12:11 PDT 2020


Author: peter klausler
Date: 2020-08-07T13:09:09-07:00
New Revision: cc01194c2fac5ad400b862463c473f3ef924c932

URL: https://github.com/llvm/llvm-project/commit/cc01194c2fac5ad400b862463c473f3ef924c932
DIFF: https://github.com/llvm/llvm-project/commit/cc01194c2fac5ad400b862463c473f3ef924c932.diff

LOG: [flang] Descriptor-based I/O data item transfers

Add support for OutputDescriptor() and InputDescriptor()
in the I/O runtime.  Change existing scalar formatted I/O
functions to drive descriptor-based I/O routines internally.

Differential Revision: https://reviews.llvm.org/D85491

Added: 
    flang/runtime/descriptor-io.h

Modified: 
    flang/runtime/io-api.cpp
    flang/runtime/type-code.cpp
    flang/runtime/type-code.h

Removed: 
    


################################################################################
diff  --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h
new file mode 100644
index 000000000000..22ae4f9917ab
--- /dev/null
+++ b/flang/runtime/descriptor-io.h
@@ -0,0 +1,354 @@
+//===-- runtime/descriptor-io.h ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
+#define FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
+
+// Implementation of I/O data list item transfers based on descriptors.
+
+#include "descriptor.h"
+#include "edit-input.h"
+#include "edit-output.h"
+#include "io-stmt.h"
+#include "terminator.h"
+#include "flang/Common/uint128.h"
+
+namespace Fortran::runtime::io::descr {
+template <typename A>
+inline A &ExtractElement(IoStatementState &io, const Descriptor &descriptor,
+    const SubscriptValue subscripts[]) {
+  A *p{descriptor.Element<A>(subscripts)};
+  if (!p) {
+    io.GetIoErrorHandler().Crash("ExtractElement: subscripts out of range");
+  }
+  return *p;
+}
+
+// Per-category descriptor-based I/O templates
+
+template <typename A, Direction DIR>
+inline bool FormattedIntegerIO(
+    IoStatementState &io, const Descriptor &descriptor) {
+  std::size_t numElements{descriptor.Elements()};
+  SubscriptValue subscripts[maxRank];
+  descriptor.GetLowerBounds(subscripts);
+  for (std::size_t j{0}; j < numElements; ++j) {
+    if (auto edit{io.GetNextDataEdit()}) {
+      A &x{ExtractElement<A>(io, descriptor, subscripts)};
+      if constexpr (DIR == Direction::Output) {
+        if (!EditIntegerOutput(io, *edit, static_cast<std::int64_t>(x))) {
+          return false;
+        }
+      } else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
+        if (!EditIntegerInput(io, *edit, reinterpret_cast<void *>(&x),
+                static_cast<int>(sizeof(A)))) {
+          return false;
+        }
+      }
+      if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
+        io.GetIoErrorHandler().Crash(
+            "FormattedIntegerIO: subscripts out of bounds");
+      }
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <int PREC, typename A, Direction DIR>
+inline bool FormattedRealIO(
+    IoStatementState &io, const Descriptor &descriptor) {
+  std::size_t numElements{descriptor.Elements()};
+  SubscriptValue subscripts[maxRank];
+  descriptor.GetLowerBounds(subscripts);
+  for (std::size_t j{0}; j < numElements; ++j) {
+    if (auto edit{io.GetNextDataEdit()}) {
+      A &x{ExtractElement<A>(io, descriptor, subscripts)};
+      if constexpr (DIR == Direction::Output) {
+        if (!RealOutputEditing<PREC>{io, x}.Edit(*edit)) {
+          return false;
+        }
+      } else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
+        if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x))) {
+          return false;
+        }
+      }
+      if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
+        io.GetIoErrorHandler().Crash(
+            "FormattedRealIO: subscripts out of bounds");
+      }
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <int PREC, typename A, Direction DIR>
+inline bool FormattedComplexIO(
+    IoStatementState &io, const Descriptor &descriptor) {
+  std::size_t numElements{descriptor.Elements()};
+  SubscriptValue subscripts[maxRank];
+  descriptor.GetLowerBounds(subscripts);
+  bool isListOutput{
+      io.get_if<ListDirectedStatementState<Direction::Output>>() != nullptr};
+  for (std::size_t j{0}; j < numElements; ++j) {
+    A *x{&ExtractElement<A>(io, descriptor, subscripts)};
+    if (isListOutput) {
+      DataEdit rEdit, iEdit;
+      rEdit.descriptor = DataEdit::ListDirectedRealPart;
+      iEdit.descriptor = DataEdit::ListDirectedImaginaryPart;
+      if (!RealOutputEditing<PREC>{io, x[0]}.Edit(rEdit) ||
+          !RealOutputEditing<PREC>{io, x[1]}.Edit(iEdit)) {
+        return false;
+      }
+    } else {
+      for (int k{0}; k < 2; ++k, ++x) {
+        auto edit{io.GetNextDataEdit()};
+        if (!edit) {
+          return false;
+        } else if constexpr (DIR == Direction::Output) {
+          if (!RealOutputEditing<PREC>{io, *x}.Edit(*edit)) {
+            return false;
+          }
+        } else if (edit->descriptor == DataEdit::ListDirectedNullValue) {
+          break;
+        } else if (!EditRealInput<PREC>(
+                       io, *edit, reinterpret_cast<void *>(x))) {
+          return false;
+        }
+      }
+    }
+    if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
+      io.GetIoErrorHandler().Crash(
+          "FormattedComplexIO: subscripts out of bounds");
+    }
+  }
+  return true;
+}
+
+template <typename A, Direction DIR>
+inline bool FormattedCharacterIO(
+    IoStatementState &io, const Descriptor &descriptor) {
+  std::size_t numElements{descriptor.Elements()};
+  SubscriptValue subscripts[maxRank];
+  descriptor.GetLowerBounds(subscripts);
+  std::size_t length{descriptor.ElementBytes() / sizeof(A)};
+  auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
+  for (std::size_t j{0}; j < numElements; ++j) {
+    A *x{&ExtractElement<A>(io, descriptor, subscripts)};
+    if (listOutput) {
+      if (!ListDirectedDefaultCharacterOutput(io, *listOutput, x, length)) {
+        return false;
+      }
+    } else if (auto edit{io.GetNextDataEdit()}) {
+      if constexpr (DIR == Direction::Output) {
+        if (!EditDefaultCharacterOutput(io, *edit, x, length)) {
+          return false;
+        }
+      } else {
+        if (edit->descriptor != DataEdit::ListDirectedNullValue) {
+          if (!EditDefaultCharacterInput(io, *edit, x, length)) {
+            return false;
+          }
+        }
+      }
+      if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
+        io.GetIoErrorHandler().Crash(
+            "FormattedCharacterIO: subscripts out of bounds");
+      }
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename A, Direction DIR>
+inline bool FormattedLogicalIO(
+    IoStatementState &io, const Descriptor &descriptor) {
+  std::size_t numElements{descriptor.Elements()};
+  SubscriptValue subscripts[maxRank];
+  descriptor.GetLowerBounds(subscripts);
+  auto *listOutput{io.get_if<ListDirectedStatementState<Direction::Output>>()};
+  for (std::size_t j{0}; j < numElements; ++j) {
+    A &x{ExtractElement<A>(io, descriptor, subscripts)};
+    if (listOutput) {
+      if (!ListDirectedLogicalOutput(io, *listOutput, x != 0)) {
+        return false;
+      }
+    } else if (auto edit{io.GetNextDataEdit()}) {
+      if constexpr (DIR == Direction::Output) {
+        if (!EditLogicalOutput(io, *edit, x != 0)) {
+          return false;
+        }
+      } else {
+        if (edit->descriptor != DataEdit::ListDirectedNullValue) {
+          bool truth{};
+          if (EditLogicalInput(io, *edit, truth)) {
+            x = truth;
+          } else {
+            return false;
+          }
+        }
+      }
+      if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
+        io.GetIoErrorHandler().Crash(
+            "FormattedLogicalIO: subscripts out of bounds");
+      }
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <Direction DIR>
+static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) {
+  if (!io.get_if<IoDirectionState<DIR>>()) {
+    io.GetIoErrorHandler().Crash(
+        "DescriptorIO() called for wrong I/O direction");
+    return false;
+  }
+  if constexpr (DIR == Direction::Input) {
+    io.BeginReadingRecord();
+  }
+  if (auto *unf{io.get_if<UnformattedIoStatementState<DIR>>()}) {
+    std::size_t elementBytes{descriptor.ElementBytes()};
+    SubscriptValue subscripts[maxRank];
+    descriptor.GetLowerBounds(subscripts);
+    if (descriptor.IsContiguous()) { // contiguous unformatted I/O
+      char &x{ExtractElement<char>(io, descriptor, subscripts)};
+      auto totalBytes{descriptor.SizeInBytes()};
+      if constexpr (DIR == Direction::Output) {
+        return unf->Emit(&x, totalBytes, elementBytes);
+      } else {
+        return unf->Receive(&x, totalBytes, elementBytes);
+      }
+    } else { // non-contiguous unformatted I/O
+      std::size_t numElements{descriptor.Elements()};
+      for (std::size_t j{0}; j < numElements; ++j) {
+        char &x{ExtractElement<char>(io, descriptor, subscripts)};
+        if constexpr (DIR == Direction::Output) {
+          if (!unf->Emit(&x, elementBytes, elementBytes)) {
+            return false;
+          }
+        } else {
+          if (!unf->Receive(&x, elementBytes, elementBytes)) {
+            return false;
+          }
+        }
+        if (!descriptor.IncrementSubscripts(subscripts) &&
+            j + 1 < numElements) {
+          io.GetIoErrorHandler().Crash(
+              "DescriptorIO: subscripts out of bounds");
+        }
+      }
+      return true;
+    }
+  } else if (auto catAndKind{descriptor.type().GetCategoryAndKind()}) {
+    int kind{catAndKind->second};
+    switch (catAndKind->first) {
+    case TypeCategory::Integer:
+      switch (kind) {
+      case 1:
+        return FormattedIntegerIO<std::int8_t, DIR>(io, descriptor);
+      case 2:
+        return FormattedIntegerIO<std::int16_t, DIR>(io, descriptor);
+      case 4:
+        return FormattedIntegerIO<std::int32_t, DIR>(io, descriptor);
+      case 8:
+        return FormattedIntegerIO<std::int64_t, DIR>(io, descriptor);
+      case 16:
+        return FormattedIntegerIO<common::uint128_t, DIR>(io, descriptor);
+      default:
+        io.GetIoErrorHandler().Crash(
+            "DescriptorIO: Unimplemented INTEGER kind (%d) in descriptor",
+            kind);
+        return false;
+      }
+    case TypeCategory::Real:
+      switch (kind) {
+      case 4:
+        return FormattedRealIO<24, float, DIR>(io, descriptor);
+      case 8:
+        return FormattedRealIO<53, double, DIR>(io, descriptor);
+#if __x86_64__
+      case 10:
+        return FormattedRealIO<64, long double, DIR>(io, descriptor);
+#else
+      case 16:
+        return FormattedRealIO<113, long double, DIR>(io, descriptor);
+#endif
+      // TODO cases 2, 3
+      default:
+        io.GetIoErrorHandler().Crash(
+            "DescriptorIO: Unimplemented REAL kind (%d) in descriptor", kind);
+        return false;
+      }
+    case TypeCategory::Complex:
+      switch (kind) {
+      case 4:
+        return FormattedComplexIO<24, float, DIR>(io, descriptor);
+      case 8:
+        return FormattedComplexIO<53, double, DIR>(io, descriptor);
+#if __x86_64__
+      case 10:
+        return FormattedComplexIO<64, long double, DIR>(io, descriptor);
+#else
+      case 16:
+        return FormattedComplexIO<113, long double, DIR>(io, descriptor);
+#endif
+      // TODO cases 2, 3
+      default:
+        io.GetIoErrorHandler().Crash(
+            "DescriptorIO: Unimplemented COMPLEX kind (%d) in descriptor",
+            kind);
+        return false;
+      }
+    case TypeCategory::Character:
+      switch (kind) {
+      case 1:
+        return FormattedCharacterIO<char, DIR>(io, descriptor);
+      // TODO cases 2, 4
+      default:
+        io.GetIoErrorHandler().Crash(
+            "DescriptorIO: Unimplemented CHARACTER kind (%d) in descriptor",
+            kind);
+        return false;
+      }
+    case TypeCategory::Logical:
+      switch (kind) {
+      case 1:
+        return FormattedLogicalIO<std::int8_t, DIR>(io, descriptor);
+      case 2:
+        return FormattedLogicalIO<std::int16_t, DIR>(io, descriptor);
+      case 4:
+        return FormattedLogicalIO<std::int32_t, DIR>(io, descriptor);
+      case 8:
+        return FormattedLogicalIO<std::int64_t, DIR>(io, descriptor);
+      default:
+        io.GetIoErrorHandler().Crash(
+            "DescriptorIO: Unimplemented LOGICAL kind (%d) in descriptor",
+            kind);
+        return false;
+      }
+    case TypeCategory::Derived:
+      io.GetIoErrorHandler().Crash(
+          "DescriptorIO: Unimplemented: derived type I/O",
+          static_cast<int>(descriptor.type().raw()));
+      return false;
+    }
+  }
+  io.GetIoErrorHandler().Crash("DescriptorIO: Bad type code (%d) in descriptor",
+      static_cast<int>(descriptor.type().raw()));
+  return false;
+}
+} // namespace Fortran::runtime::io::descr
+#endif // FORTRAN_RUNTIME_DESCRIPTOR_IO_H_

diff  --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index f64fe97b2d23..30f343773f90 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -9,6 +9,8 @@
 // Implements the I/O statement API
 
 #include "io-api.h"
+#include "descriptor-io.h"
+#include "descriptor.h"
 #include "edit-input.h"
 #include "edit-output.h"
 #include "environment.h"
@@ -863,15 +865,12 @@ bool IONAME(GetNewUnit)(Cookie cookie, int &unit, int kind) {
 
 // Data transfers
 
-bool IONAME(OutputDescriptor)(Cookie cookie, const Descriptor &) {
-  IoStatementState &io{*cookie};
-  io.GetIoErrorHandler().Crash("OutputDescriptor: not yet implemented"); // TODO
+bool IONAME(OutputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
-bool IONAME(InputDescriptor)(Cookie cookie, const Descriptor &) {
-  IoStatementState &io{*cookie};
-  io.BeginReadingRecord();
-  io.GetIoErrorHandler().Crash("InputDescriptor: not yet implemented"); // TODO
+bool IONAME(InputDescriptor)(Cookie cookie, const Descriptor &descriptor) {
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 bool IONAME(OutputUnformattedBlock)(Cookie cookie, const char *x,
@@ -898,198 +897,112 @@ bool IONAME(InputUnformattedBlock)(
 }
 
 bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<OutputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "OutputInteger64() called for a non-output I/O statement");
-    return false;
-  }
-  if (auto edit{io.GetNextDataEdit()}) {
-    return EditIntegerOutput(io, *edit, n);
-  }
-  return false;
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Integer, 8, reinterpret_cast<void *>(&n), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
 bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<InputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "InputInteger64() called for a non-input I/O statement");
-    return false;
-  }
-  io.BeginReadingRecord();
-  if (auto edit{io.GetNextDataEdit()}) {
-    if (edit->descriptor == DataEdit::ListDirectedNullValue) {
-      return true;
-    }
-    return EditIntegerInput(io, *edit, reinterpret_cast<void *>(&n), kind);
-  }
-  return false;
-}
-
-template <int PREC, typename REAL>
-static bool OutputReal(Cookie cookie, REAL x) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<OutputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "OutputReal() called for a non-output I/O statement");
-    return false;
-  }
-  if (auto edit{io.GetNextDataEdit()}) {
-    return RealOutputEditing<PREC>{io, x}.Edit(*edit);
-  }
-  return false;
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Integer, kind, reinterpret_cast<void *>(&n), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 bool IONAME(OutputReal32)(Cookie cookie, float x) {
-  return OutputReal<24, float>(cookie, x);
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
 bool IONAME(OutputReal64)(Cookie cookie, double x) {
-  return OutputReal<53, double>(cookie, x);
-}
-
-template <int PREC, typename REAL>
-static bool InputReal(Cookie cookie, REAL &x) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<InputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "InputReal() called for a non-input I/O statement");
-    return false;
-  }
-  io.BeginReadingRecord();
-  if (auto edit{io.GetNextDataEdit()}) {
-    if (edit->descriptor == DataEdit::ListDirectedNullValue) {
-      return true;
-    }
-    return EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x));
-  }
-  return false;
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
 bool IONAME(InputReal32)(Cookie cookie, float &x) {
-  return InputReal<24, float>(cookie, x);
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(TypeCategory::Real, 4, reinterpret_cast<void *>(&x), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 bool IONAME(InputReal64)(Cookie cookie, double &x) {
-  return InputReal<53, double>(cookie, x);
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast<void *>(&x), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
-template <int PREC, typename REAL>
-static bool OutputComplex(Cookie cookie, REAL r, REAL z) {
-  IoStatementState &io{*cookie};
-  if (io.get_if<ListDirectedStatementState<Direction::Output>>()) {
-    DataEdit real, imaginary;
-    real.descriptor = DataEdit::ListDirectedRealPart;
-    imaginary.descriptor = DataEdit::ListDirectedImaginaryPart;
-    return RealOutputEditing<PREC>{io, r}.Edit(real) &&
-        RealOutputEditing<PREC>{io, z}.Edit(imaginary);
-  }
-  return OutputReal<PREC, REAL>(cookie, r) && OutputReal<PREC, REAL>(cookie, z);
+bool IONAME(OutputComplex32)(Cookie cookie, float r, float i) {
+  float z[2]{r, i};
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Complex, 4, reinterpret_cast<void *>(&z), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
-bool IONAME(OutputComplex32)(Cookie cookie, float r, float z) {
-  return OutputComplex<24, float>(cookie, r, z);
+bool IONAME(OutputComplex64)(Cookie cookie, double r, double i) {
+  double z[2]{r, i};
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Complex, 8, reinterpret_cast<void *>(&z), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
-bool IONAME(OutputComplex64)(Cookie cookie, double r, double z) {
-  return OutputComplex<53, double>(cookie, r, z);
+bool IONAME(InputComplex32)(Cookie cookie, float z[2]) {
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Complex, 4, reinterpret_cast<void *>(z), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
-template <int PREC, typename REAL>
-static bool InputComplex(Cookie cookie, REAL x[2]) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<InputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "InputComplex() called for a non-input I/O statement");
-    return false;
-  }
-  io.BeginReadingRecord();
-  for (int j{0}; j < 2; ++j) {
-    if (auto edit{io.GetNextDataEdit()}) {
-      if (edit->descriptor == DataEdit::ListDirectedNullValue) {
-        return true;
-      }
-      if (!EditRealInput<PREC>(io, *edit, reinterpret_cast<void *>(&x[j]))) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool IONAME(InputComplex32)(Cookie cookie, float x[2]) {
-  return InputComplex<24, float>(cookie, x);
-}
-
-bool IONAME(InputComplex64)(Cookie cookie, double x[2]) {
-  return InputComplex<53, double>(cookie, x);
+bool IONAME(InputComplex64)(Cookie cookie, double z[2]) {
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Complex, 8, reinterpret_cast<void *>(z), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<OutputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "OutputAscii() called for a non-output I/O statement");
-    return false;
-  }
-  if (auto *list{io.get_if<ListDirectedStatementState<Direction::Output>>()}) {
-    return ListDirectedDefaultCharacterOutput(io, *list, x, length);
-  } else if (auto edit{io.GetNextDataEdit()}) {
-    return EditDefaultCharacterOutput(io, *edit, x, length);
-  } else {
-    return false;
-  }
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      1, length, reinterpret_cast<void *>(const_cast<char *>(x)), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
 bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<InputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "InputAscii() called for a non-input I/O statement");
-    return false;
-  }
-  io.BeginReadingRecord();
-  if (auto edit{io.GetNextDataEdit()}) {
-    if (edit->descriptor == DataEdit::ListDirectedNullValue) {
-      return true;
-    }
-    return EditDefaultCharacterInput(io, *edit, x, length);
-  }
-  return false;
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(1, length, reinterpret_cast<void *>(x), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 bool IONAME(OutputLogical)(Cookie cookie, bool truth) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<OutputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "OutputLogical() called for a non-output I/O statement");
-    return false;
-  }
-  if (auto *list{io.get_if<ListDirectedStatementState<Direction::Output>>()}) {
-    return ListDirectedLogicalOutput(io, *list, truth);
-  } else if (auto edit{io.GetNextDataEdit()}) {
-    return EditLogicalOutput(io, *edit, truth);
-  } else {
-    return false;
-  }
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Logical, 1, reinterpret_cast<void *>(&truth), 0);
+  return descr::DescriptorIO<Direction::Output>(*cookie, descriptor);
 }
 
 bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
-  IoStatementState &io{*cookie};
-  if (!io.get_if<InputStatementState>()) {
-    io.GetIoErrorHandler().Crash(
-        "InputLogical() called for a non-input I/O statement");
-    return false;
-  }
-  io.BeginReadingRecord();
-  if (auto edit{io.GetNextDataEdit()}) {
-    if (edit->descriptor == DataEdit::ListDirectedNullValue) {
-      return true;
-    }
-    return EditLogicalInput(io, *edit, truth);
-  }
-  return false;
+  StaticDescriptor staticDescriptor;
+  Descriptor &descriptor{staticDescriptor.descriptor()};
+  descriptor.Establish(
+      TypeCategory::Logical, 1, reinterpret_cast<void *>(&truth), 0);
+  return descr::DescriptorIO<Direction::Input>(*cookie, descriptor);
 }
 
 void IONAME(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) {

diff  --git a/flang/runtime/type-code.cpp b/flang/runtime/type-code.cpp
index 13cc834fd4e9..3fda906516ed 100644
--- a/flang/runtime/type-code.cpp
+++ b/flang/runtime/type-code.cpp
@@ -93,4 +93,60 @@ TypeCode::TypeCode(TypeCategory f, int kind) {
     break;
   }
 }
+
+std::optional<std::pair<TypeCategory, int>>
+TypeCode::GetCategoryAndKind() const {
+  switch (raw_) {
+  case CFI_type_int8_t:
+    return std::make_pair(TypeCategory::Integer, 1);
+  case CFI_type_int16_t:
+    return std::make_pair(TypeCategory::Integer, 2);
+  case CFI_type_int32_t:
+    return std::make_pair(TypeCategory::Integer, 4);
+  case CFI_type_int64_t:
+    return std::make_pair(TypeCategory::Integer, 8);
+  case CFI_type_int128_t:
+    return std::make_pair(TypeCategory::Integer, 16);
+  case CFI_type_float:
+    return std::make_pair(TypeCategory::Real, 4);
+  case CFI_type_double:
+    return std::make_pair(TypeCategory::Real, 8);
+  case CFI_type_long_double:
+#if __x86_64__
+    return std::make_pair(TypeCategory::Real, 10);
+#else
+    return std::make_pair(TypeCategory::Real, 16);
+#endif
+  case CFI_type_float_Complex:
+    return std::make_pair(TypeCategory::Complex, 4);
+  case CFI_type_double_Complex:
+    return std::make_pair(TypeCategory::Complex, 8);
+  case CFI_type_long_double_Complex:
+#if __x86_64__
+    return std::make_pair(TypeCategory::Complex, 10);
+#else
+    return std::make_pair(TypeCategory::Complex, 16);
+#endif
+  case CFI_type_char:
+    return std::make_pair(TypeCategory::Character, 1);
+  case CFI_type_char16_t:
+    return std::make_pair(TypeCategory::Character, 2);
+  case CFI_type_char32_t:
+    return std::make_pair(TypeCategory::Character, 4);
+  case CFI_type_Bool:
+    return std::make_pair(TypeCategory::Logical, 1);
+  case CFI_type_int_fast8_t:
+    return std::make_pair(TypeCategory::Logical, 1);
+  case CFI_type_int_fast16_t:
+    return std::make_pair(TypeCategory::Logical, 2);
+  case CFI_type_int_fast32_t:
+    return std::make_pair(TypeCategory::Logical, 4);
+  case CFI_type_int_fast64_t:
+    return std::make_pair(TypeCategory::Logical, 8);
+  case CFI_type_struct:
+    return std::make_pair(TypeCategory::Derived, 0);
+  default:
+    return std::nullopt;
+  }
+}
 } // namespace Fortran::runtime

diff  --git a/flang/runtime/type-code.h b/flang/runtime/type-code.h
index bda861bf73ac..9992497445cc 100644
--- a/flang/runtime/type-code.h
+++ b/flang/runtime/type-code.h
@@ -11,6 +11,8 @@
 
 #include "flang/Common/Fortran.h"
 #include "flang/ISO_Fortran_binding.h"
+#include <optional>
+#include <utility>
 
 namespace Fortran::runtime {
 
@@ -41,10 +43,15 @@ class TypeCode {
     return raw_ == CFI_type_char || raw_ == CFI_type_char16_t ||
         raw_ == CFI_type_char32_t;
   }
-  constexpr bool IsLogical() const { return raw_ == CFI_type_Bool; }
+  constexpr bool IsLogical() const {
+    return raw_ == CFI_type_Bool ||
+        (raw_ >= CFI_type_int_fast8_t && raw_ <= CFI_type_int_fast64_t);
+  }
   constexpr bool IsDerived() const { return raw_ == CFI_type_struct; }
   constexpr bool IsIntrinsic() const { return IsValid() && !IsDerived(); }
 
+  std::optional<std::pair<TypeCategory, int>> GetCategoryAndKind() const;
+
 private:
   ISO::CFI_type_t raw_{CFI_type_other};
 };


        


More information about the flang-commits mailing list