diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h new file mode 100644 --- /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 +inline A &ExtractElement(IoStatementState &io, const Descriptor &descriptor, + const SubscriptValue subscripts[]) { + A *p{descriptor.Element(subscripts)}; + if (!p) { + io.GetIoErrorHandler().Crash("ExtractElement: subscripts out of range"); + } + return *p; +} + +// Per-category descriptor-based I/O templates + +template +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(io, descriptor, subscripts)}; + if constexpr (DIR == Direction::Output) { + if (!EditIntegerOutput(io, *edit, static_cast(x))) { + return false; + } + } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { + if (!EditIntegerInput(io, *edit, reinterpret_cast(&x), + static_cast(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 +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(io, descriptor, subscripts)}; + if constexpr (DIR == Direction::Output) { + if (!RealOutputEditing{io, x}.Edit(*edit)) { + return false; + } + } else if (edit->descriptor != DataEdit::ListDirectedNullValue) { + if (!EditRealInput(io, *edit, reinterpret_cast(&x))) { + return false; + } + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedRealIO: subscripts out of bounds"); + } + } else { + return false; + } + } + return true; +} + +template +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>() != nullptr}; + for (std::size_t j{0}; j < numElements; ++j) { + A *x{&ExtractElement(io, descriptor, subscripts)}; + if (isListOutput) { + DataEdit rEdit, iEdit; + rEdit.descriptor = DataEdit::ListDirectedRealPart; + iEdit.descriptor = DataEdit::ListDirectedImaginaryPart; + if (!RealOutputEditing{io, x[0]}.Edit(rEdit) || + !RealOutputEditing{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{io, *x}.Edit(*edit)) { + return false; + } + } else if (edit->descriptor == DataEdit::ListDirectedNullValue) { + break; + } else if (!EditRealInput( + io, *edit, reinterpret_cast(x))) { + return false; + } + } + } + if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) { + io.GetIoErrorHandler().Crash( + "FormattedComplexIO: subscripts out of bounds"); + } + } + return true; +} + +template +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>()}; + for (std::size_t j{0}; j < numElements; ++j) { + A *x{&ExtractElement(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 +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>()}; + for (std::size_t j{0}; j < numElements; ++j) { + A &x{ExtractElement(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 +static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) { + if (!io.get_if>()) { + 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>()}) { + std::size_t elementBytes{descriptor.ElementBytes()}; + SubscriptValue subscripts[maxRank]; + descriptor.GetLowerBounds(subscripts); + if (descriptor.IsContiguous()) { // contiguous unformatted I/O + char &x{ExtractElement(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(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(io, descriptor); + case 2: + return FormattedIntegerIO(io, descriptor); + case 4: + return FormattedIntegerIO(io, descriptor); + case 8: + return FormattedIntegerIO(io, descriptor); + case 16: + return FormattedIntegerIO(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(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(io, descriptor); + case 2: + return FormattedLogicalIO(io, descriptor); + case 4: + return FormattedLogicalIO(io, descriptor); + case 8: + return FormattedLogicalIO(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(descriptor.type().raw())); + return false; + } + } + io.GetIoErrorHandler().Crash("DescriptorIO: Bad type code (%d) in descriptor", + static_cast(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 --- 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 @@ // 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(*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(*cookie, descriptor); } bool IONAME(OutputUnformattedBlock)(Cookie cookie, const char *x, @@ -898,198 +897,112 @@ } bool IONAME(OutputInteger64)(Cookie cookie, std::int64_t n) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(&n), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(InputInteger)(Cookie cookie, std::int64_t &n, int kind) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(&n), kind); - } - return false; -} - -template -static bool OutputReal(Cookie cookie, REAL x) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - io.GetIoErrorHandler().Crash( - "OutputReal() called for a non-output I/O statement"); - return false; - } - if (auto edit{io.GetNextDataEdit()}) { - return RealOutputEditing{io, x}.Edit(*edit); - } - return false; + StaticDescriptor staticDescriptor; + Descriptor &descriptor{staticDescriptor.descriptor()}; + descriptor.Establish( + TypeCategory::Integer, kind, reinterpret_cast(&n), 0); + return descr::DescriptorIO(*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(&x), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(OutputReal64)(Cookie cookie, double x) { - return OutputReal<53, double>(cookie, x); -} - -template -static bool InputReal(Cookie cookie, REAL &x) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(io, *edit, reinterpret_cast(&x)); - } - return false; + StaticDescriptor staticDescriptor; + Descriptor &descriptor{staticDescriptor.descriptor()}; + descriptor.Establish(TypeCategory::Real, 8, reinterpret_cast(&x), 0); + return descr::DescriptorIO(*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(&x), 0); + return descr::DescriptorIO(*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(&x), 0); + return descr::DescriptorIO(*cookie, descriptor); } -template -static bool OutputComplex(Cookie cookie, REAL r, REAL z) { - IoStatementState &io{*cookie}; - if (io.get_if>()) { - DataEdit real, imaginary; - real.descriptor = DataEdit::ListDirectedRealPart; - imaginary.descriptor = DataEdit::ListDirectedImaginaryPart; - return RealOutputEditing{io, r}.Edit(real) && - RealOutputEditing{io, z}.Edit(imaginary); - } - return OutputReal(cookie, r) && OutputReal(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(&z), 0); + return descr::DescriptorIO(*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(&z), 0); + return descr::DescriptorIO(*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(z), 0); + return descr::DescriptorIO(*cookie, descriptor); } -template -static bool InputComplex(Cookie cookie, REAL x[2]) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(io, *edit, reinterpret_cast(&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(z), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(OutputAscii)(Cookie cookie, const char *x, std::size_t length) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - io.GetIoErrorHandler().Crash( - "OutputAscii() called for a non-output I/O statement"); - return false; - } - if (auto *list{io.get_if>()}) { - 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(const_cast(x)), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(InputAscii)(Cookie cookie, char *x, std::size_t length) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(x), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(OutputLogical)(Cookie cookie, bool truth) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - io.GetIoErrorHandler().Crash( - "OutputLogical() called for a non-output I/O statement"); - return false; - } - if (auto *list{io.get_if>()}) { - 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(&truth), 0); + return descr::DescriptorIO(*cookie, descriptor); } bool IONAME(InputLogical)(Cookie cookie, bool &truth) { - IoStatementState &io{*cookie}; - if (!io.get_if()) { - 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(&truth), 0); + return descr::DescriptorIO(*cookie, descriptor); } void IONAME(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) { diff --git a/flang/runtime/type-code.h b/flang/runtime/type-code.h --- 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 +#include namespace Fortran::runtime { @@ -41,10 +43,15 @@ 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> GetCategoryAndKind() const; + private: ISO::CFI_type_t raw_{CFI_type_other}; }; diff --git a/flang/runtime/type-code.cpp b/flang/runtime/type-code.cpp --- a/flang/runtime/type-code.cpp +++ b/flang/runtime/type-code.cpp @@ -93,4 +93,60 @@ break; } } + +std::optional> +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