2020-08-07 08:30:01 +08:00
|
|
|
//===-- 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.
|
2021-06-26 01:40:08 +08:00
|
|
|
// (All I/O items come through here so that the code is exercised for test;
|
|
|
|
// some scalar I/O data transfer APIs could be changed to bypass their use
|
|
|
|
// of descriptors in the future for better efficiency.)
|
2020-08-07 08:30:01 +08:00
|
|
|
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
#include "cpp-type.h"
|
2020-08-07 08:30:01 +08:00
|
|
|
#include "descriptor.h"
|
|
|
|
#include "edit-input.h"
|
|
|
|
#include "edit-output.h"
|
|
|
|
#include "io-stmt.h"
|
|
|
|
#include "terminator.h"
|
2021-06-18 04:13:19 +08:00
|
|
|
#include "type-info.h"
|
2021-06-26 01:40:08 +08:00
|
|
|
#include "unit.h"
|
2020-08-07 08:30:01 +08:00
|
|
|
#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) {
|
2021-06-18 04:13:19 +08:00
|
|
|
io.GetIoErrorHandler().Crash(
|
|
|
|
"ExtractElement: null base address or subscripts out of range");
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
return *p;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Per-category descriptor-based I/O templates
|
|
|
|
|
2021-05-06 02:37:49 +08:00
|
|
|
// TODO (perhaps as a nontrivial but small starter project): implement
|
|
|
|
// automatic repetition counts, like "10*3.14159", for list-directed and
|
|
|
|
// NAMELIST array output.
|
|
|
|
|
2020-08-07 08:30:01 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-10-03 03:39:05 +08:00
|
|
|
template <int KIND, Direction DIR>
|
2020-08-07 08:30:01 +08:00
|
|
|
inline bool FormattedRealIO(
|
|
|
|
IoStatementState &io, const Descriptor &descriptor) {
|
|
|
|
std::size_t numElements{descriptor.Elements()};
|
|
|
|
SubscriptValue subscripts[maxRank];
|
|
|
|
descriptor.GetLowerBounds(subscripts);
|
2020-10-03 03:39:05 +08:00
|
|
|
using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
|
2020-08-07 08:30:01 +08:00
|
|
|
for (std::size_t j{0}; j < numElements; ++j) {
|
|
|
|
if (auto edit{io.GetNextDataEdit()}) {
|
2020-10-03 03:39:05 +08:00
|
|
|
RawType &x{ExtractElement<RawType>(io, descriptor, subscripts)};
|
2020-08-07 08:30:01 +08:00
|
|
|
if constexpr (DIR == Direction::Output) {
|
2020-10-03 03:39:05 +08:00
|
|
|
if (!RealOutputEditing<KIND>{io, x}.Edit(*edit)) {
|
2020-08-07 08:30:01 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (edit->descriptor != DataEdit::ListDirectedNullValue) {
|
2020-10-03 03:39:05 +08:00
|
|
|
if (!EditRealInput<KIND>(io, *edit, reinterpret_cast<void *>(&x))) {
|
2020-08-07 08:30:01 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
|
|
|
|
io.GetIoErrorHandler().Crash(
|
|
|
|
"FormattedRealIO: subscripts out of bounds");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-10-03 03:39:05 +08:00
|
|
|
template <int KIND, Direction DIR>
|
2020-08-07 08:30:01 +08:00
|
|
|
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};
|
2020-10-03 03:39:05 +08:00
|
|
|
using RawType = typename RealOutputEditing<KIND>::BinaryFloatingPoint;
|
2020-08-07 08:30:01 +08:00
|
|
|
for (std::size_t j{0}; j < numElements; ++j) {
|
2020-10-03 03:39:05 +08:00
|
|
|
RawType *x{&ExtractElement<RawType>(io, descriptor, subscripts)};
|
2020-08-07 08:30:01 +08:00
|
|
|
if (isListOutput) {
|
|
|
|
DataEdit rEdit, iEdit;
|
|
|
|
rEdit.descriptor = DataEdit::ListDirectedRealPart;
|
|
|
|
iEdit.descriptor = DataEdit::ListDirectedImaginaryPart;
|
2020-10-03 03:39:05 +08:00
|
|
|
if (!RealOutputEditing<KIND>{io, x[0]}.Edit(rEdit) ||
|
|
|
|
!RealOutputEditing<KIND>{io, x[1]}.Edit(iEdit)) {
|
2020-08-07 08:30:01 +08:00
|
|
|
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) {
|
2020-10-03 03:39:05 +08:00
|
|
|
if (!RealOutputEditing<KIND>{io, *x}.Edit(*edit)) {
|
2020-08-07 08:30:01 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (edit->descriptor == DataEdit::ListDirectedNullValue) {
|
|
|
|
break;
|
2020-10-03 03:39:05 +08:00
|
|
|
} else if (!EditRealInput<KIND>(
|
2020-08-07 08:30:01 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2020-10-01 03:43:21 +08:00
|
|
|
if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
|
|
|
|
io.GetIoErrorHandler().Crash(
|
|
|
|
"FormattedCharacterIO: subscripts out of bounds");
|
|
|
|
}
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2020-10-01 03:43:21 +08:00
|
|
|
if (!descriptor.IncrementSubscripts(subscripts) && j + 1 < numElements) {
|
|
|
|
io.GetIoErrorHandler().Crash(
|
|
|
|
"FormattedLogicalIO: subscripts out of bounds");
|
|
|
|
}
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-18 04:13:19 +08:00
|
|
|
template <Direction DIR>
|
|
|
|
static bool DescriptorIO(IoStatementState &, const Descriptor &);
|
|
|
|
|
|
|
|
template <Direction DIR>
|
|
|
|
static bool DefaultFormattedComponentIO(IoStatementState &io,
|
|
|
|
const typeInfo::Component &component, const Descriptor &origDescriptor,
|
|
|
|
const SubscriptValue origSubscripts[], Terminator &terminator) {
|
|
|
|
if (component.genre() == typeInfo::Component::Genre::Data) {
|
|
|
|
// Create a descriptor for the component
|
|
|
|
StaticDescriptor<maxRank, true, 16 /*?*/> statDesc;
|
|
|
|
Descriptor &desc{statDesc.descriptor()};
|
2021-07-20 02:53:20 +08:00
|
|
|
component.CreatePointerDescriptor(
|
2021-06-18 04:13:19 +08:00
|
|
|
desc, origDescriptor, origSubscripts, terminator);
|
|
|
|
return DescriptorIO<DIR>(io, desc);
|
|
|
|
} else {
|
|
|
|
// Component is itself a descriptor
|
|
|
|
char *pointer{
|
|
|
|
origDescriptor.Element<char>(origSubscripts) + component.offset()};
|
|
|
|
RUNTIME_CHECK(
|
|
|
|
terminator, component.genre() == typeInfo::Component::Genre::Automatic);
|
|
|
|
const Descriptor &compDesc{*reinterpret_cast<const Descriptor *>(pointer)};
|
|
|
|
return DescriptorIO<DIR>(io, compDesc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-26 01:40:08 +08:00
|
|
|
std::optional<bool> DefinedFormattedIo(
|
|
|
|
IoStatementState &, const Descriptor &, const typeInfo::SpecialBinding &);
|
|
|
|
|
2021-06-18 04:13:19 +08:00
|
|
|
template <Direction DIR>
|
|
|
|
static bool FormattedDerivedTypeIO(
|
|
|
|
IoStatementState &io, const Descriptor &descriptor) {
|
2021-06-26 01:40:08 +08:00
|
|
|
IoErrorHandler &handler{io.GetIoErrorHandler()};
|
|
|
|
// Derived type information must be present for formatted I/O.
|
2021-06-18 04:13:19 +08:00
|
|
|
const DescriptorAddendum *addendum{descriptor.Addendum()};
|
2021-06-26 01:40:08 +08:00
|
|
|
RUNTIME_CHECK(handler, addendum != nullptr);
|
2021-06-18 04:13:19 +08:00
|
|
|
const typeInfo::DerivedType *type{addendum->derivedType()};
|
2021-06-26 01:40:08 +08:00
|
|
|
RUNTIME_CHECK(handler, type != nullptr);
|
|
|
|
if (const typeInfo::SpecialBinding *
|
|
|
|
special{type->FindSpecialBinding(DIR == Direction::Input
|
|
|
|
? typeInfo::SpecialBinding::Which::ReadFormatted
|
|
|
|
: typeInfo::SpecialBinding::Which::WriteFormatted)}) {
|
|
|
|
if (std::optional<bool> wasDefined{
|
|
|
|
DefinedFormattedIo(io, descriptor, *special)}) {
|
|
|
|
return *wasDefined; // user-defined I/O was applied
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Default componentwise derived type formatting
|
|
|
|
const Descriptor &compArray{type->component()};
|
|
|
|
RUNTIME_CHECK(handler, compArray.rank() == 1);
|
|
|
|
std::size_t numComponents{compArray.Elements()};
|
|
|
|
std::size_t numElements{descriptor.Elements()};
|
|
|
|
SubscriptValue subscripts[maxRank];
|
|
|
|
descriptor.GetLowerBounds(subscripts);
|
|
|
|
for (std::size_t j{0}; j < numElements;
|
|
|
|
++j, descriptor.IncrementSubscripts(subscripts)) {
|
|
|
|
SubscriptValue at[maxRank];
|
|
|
|
compArray.GetLowerBounds(at);
|
|
|
|
for (std::size_t k{0}; k < numComponents;
|
|
|
|
++k, compArray.IncrementSubscripts(at)) {
|
|
|
|
const typeInfo::Component &component{
|
|
|
|
*compArray.Element<typeInfo::Component>(at)};
|
|
|
|
if (!DefaultFormattedComponentIO<DIR>(
|
|
|
|
io, component, descriptor, subscripts, handler)) {
|
|
|
|
return false;
|
2021-06-18 04:13:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-26 01:40:08 +08:00
|
|
|
bool DefinedUnformattedIo(
|
|
|
|
IoStatementState &, const Descriptor &, const typeInfo::SpecialBinding &);
|
|
|
|
|
|
|
|
// Unformatted I/O
|
2020-08-07 08:30:01 +08:00
|
|
|
template <Direction DIR>
|
2021-06-26 01:40:08 +08:00
|
|
|
static bool UnformattedDescriptorIO(
|
|
|
|
IoStatementState &io, const Descriptor &descriptor) {
|
|
|
|
IoErrorHandler &handler{io.GetIoErrorHandler()};
|
|
|
|
const DescriptorAddendum *addendum{descriptor.Addendum()};
|
|
|
|
const typeInfo::DerivedType *type{
|
|
|
|
addendum ? addendum->derivedType() : nullptr};
|
|
|
|
if (const typeInfo::SpecialBinding *
|
|
|
|
special{type
|
|
|
|
? type->FindSpecialBinding(DIR == Direction::Input
|
|
|
|
? typeInfo::SpecialBinding::Which::ReadUnformatted
|
|
|
|
: typeInfo::SpecialBinding::Which::WriteUnformatted)
|
|
|
|
: nullptr}) {
|
|
|
|
// User-defined derived type unformatted I/O
|
|
|
|
return DefinedUnformattedIo(io, descriptor, *special);
|
|
|
|
} else {
|
|
|
|
// Regular derived type unformatted I/O, not user-defined
|
|
|
|
auto *externalUnf{io.get_if<ExternalUnformattedIoStatementState<DIR>>()};
|
|
|
|
auto *childUnf{io.get_if<ChildUnformattedIoStatementState<DIR>>()};
|
|
|
|
RUNTIME_CHECK(handler, externalUnf != nullptr || childUnf != nullptr);
|
2020-08-07 08:30:01 +08:00
|
|
|
std::size_t elementBytes{descriptor.ElementBytes()};
|
2021-06-26 01:40:08 +08:00
|
|
|
std::size_t numElements{descriptor.Elements()};
|
2020-08-07 08:30:01 +08:00
|
|
|
SubscriptValue subscripts[maxRank];
|
|
|
|
descriptor.GetLowerBounds(subscripts);
|
2021-06-26 01:40:08 +08:00
|
|
|
using CharType =
|
|
|
|
std::conditional_t<DIR == Direction::Output, const char, char>;
|
|
|
|
auto Transfer{[=](CharType &x, std::size_t totalBytes,
|
|
|
|
std::size_t elementBytes) -> bool {
|
2020-08-07 08:30:01 +08:00
|
|
|
if constexpr (DIR == Direction::Output) {
|
2021-06-26 01:40:08 +08:00
|
|
|
return externalUnf ? externalUnf->Emit(&x, totalBytes, elementBytes)
|
|
|
|
: childUnf->Emit(&x, totalBytes, elementBytes);
|
2020-08-07 08:30:01 +08:00
|
|
|
} else {
|
2021-06-26 01:40:08 +08:00
|
|
|
return externalUnf ? externalUnf->Receive(&x, totalBytes, elementBytes)
|
|
|
|
: childUnf->Receive(&x, totalBytes, elementBytes);
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
2021-06-26 01:40:08 +08:00
|
|
|
}};
|
|
|
|
if (descriptor.IsContiguous()) { // contiguous unformatted I/O
|
|
|
|
char &x{ExtractElement<char>(io, descriptor, subscripts)};
|
|
|
|
return Transfer(x, numElements * elementBytes, elementBytes);
|
2020-08-07 08:30:01 +08:00
|
|
|
} else { // non-contiguous unformatted I/O
|
|
|
|
for (std::size_t j{0}; j < numElements; ++j) {
|
|
|
|
char &x{ExtractElement<char>(io, descriptor, subscripts)};
|
2021-06-26 01:40:08 +08:00
|
|
|
if (!Transfer(x, elementBytes, elementBytes)) {
|
|
|
|
return false;
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
if (!descriptor.IncrementSubscripts(subscripts) &&
|
|
|
|
j + 1 < numElements) {
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash("DescriptorIO: subscripts out of bounds");
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2021-06-26 01:40:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
if (!io.BeginReadingRecord()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!io.get_if<FormattedIoStatementState>()) {
|
|
|
|
return UnformattedDescriptorIO<DIR>(io, descriptor);
|
|
|
|
}
|
|
|
|
IoErrorHandler &handler{io.GetIoErrorHandler()};
|
|
|
|
if (auto catAndKind{descriptor.type().GetCategoryAndKind()}) {
|
|
|
|
TypeCategory cat{catAndKind->first};
|
2020-08-07 08:30:01 +08:00
|
|
|
int kind{catAndKind->second};
|
2021-06-26 01:40:08 +08:00
|
|
|
switch (cat) {
|
2020-08-07 08:30:01 +08:00
|
|
|
case TypeCategory::Integer:
|
|
|
|
switch (kind) {
|
|
|
|
case 1:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 1>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 2:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 2>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 4:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 4>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 8:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 8>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 16:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedIntegerIO<CppTypeFor<TypeCategory::Integer, 16>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
default:
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash(
|
2020-08-07 08:30:01 +08:00
|
|
|
"DescriptorIO: Unimplemented INTEGER kind (%d) in descriptor",
|
|
|
|
kind);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case TypeCategory::Real:
|
|
|
|
switch (kind) {
|
2020-10-03 03:39:05 +08:00
|
|
|
case 2:
|
|
|
|
return FormattedRealIO<2, DIR>(io, descriptor);
|
|
|
|
case 3:
|
|
|
|
return FormattedRealIO<3, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 4:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedRealIO<4, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 8:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedRealIO<8, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 10:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedRealIO<10, DIR>(io, descriptor);
|
|
|
|
// TODO: case double/double
|
2020-08-07 08:30:01 +08:00
|
|
|
case 16:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedRealIO<16, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
default:
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash(
|
2020-08-07 08:30:01 +08:00
|
|
|
"DescriptorIO: Unimplemented REAL kind (%d) in descriptor", kind);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case TypeCategory::Complex:
|
|
|
|
switch (kind) {
|
2020-10-03 03:39:05 +08:00
|
|
|
case 2:
|
|
|
|
return FormattedComplexIO<2, DIR>(io, descriptor);
|
|
|
|
case 3:
|
|
|
|
return FormattedComplexIO<3, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 4:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedComplexIO<4, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 8:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedComplexIO<8, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 10:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedComplexIO<10, DIR>(io, descriptor);
|
|
|
|
// TODO: case double/double
|
2020-08-07 08:30:01 +08:00
|
|
|
case 16:
|
2020-10-03 03:39:05 +08:00
|
|
|
return FormattedComplexIO<16, DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
default:
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash(
|
2020-08-07 08:30:01 +08:00
|
|
|
"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:
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash(
|
2020-08-07 08:30:01 +08:00
|
|
|
"DescriptorIO: Unimplemented CHARACTER kind (%d) in descriptor",
|
|
|
|
kind);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case TypeCategory::Logical:
|
|
|
|
switch (kind) {
|
|
|
|
case 1:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 1>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 2:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 2>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 4:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 4>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
case 8:
|
[flang] Implement reductions in the runtime
Add runtime APIs, implementations, and tests for ALL, ANY, COUNT,
MAXLOC, MAXVAL, MINLOC, MINVAL, PRODUCT, and SUM reduction
transformantional intrinsic functions for all relevant argument
and result types and kinds, both without DIM= arguments
(total reductions) and with (partial reductions).
Complex-valued reductions have their APIs in C so that
C's _Complex types can be used for their results.
Some infrastructure work was also necessary or noticed:
* Usage of "long double" in the compiler was cleaned up a
bit, and host dependences on x86 / MSVC have been isolated
in a new Common/long-double header.
* Character comparison has been exposed via an extern template
so that reductions could use it.
* Mappings from Fortran type category/kind to host C++ types
and vice versa have been isolated into runtime/cpp-type.h and
then used throughout the runtime as appropriate.
* The portable 128-bit integer package in Common/uint128.h
was generalized to support signed comparisons.
* Bugs in descriptor indexing code were fixed.
Differential Revision: https://reviews.llvm.org/D99666
2021-04-01 00:14:08 +08:00
|
|
|
return FormattedLogicalIO<CppTypeFor<TypeCategory::Integer, 8>, DIR>(
|
|
|
|
io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
default:
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash(
|
2020-08-07 08:30:01 +08:00
|
|
|
"DescriptorIO: Unimplemented LOGICAL kind (%d) in descriptor",
|
|
|
|
kind);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
case TypeCategory::Derived:
|
2021-06-18 04:13:19 +08:00
|
|
|
return FormattedDerivedTypeIO<DIR>(io, descriptor);
|
2020-08-07 08:30:01 +08:00
|
|
|
}
|
|
|
|
}
|
2021-06-26 01:40:08 +08:00
|
|
|
handler.Crash("DescriptorIO: Bad type code (%d) in descriptor",
|
2020-08-07 08:30:01 +08:00
|
|
|
static_cast<int>(descriptor.type().raw()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} // namespace Fortran::runtime::io::descr
|
|
|
|
#endif // FORTRAN_RUNTIME_DESCRIPTOR_IO_H_
|