[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