-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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
- Loading branch information
Showing
4 changed files
with
495 additions
and
165 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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_ |
Oops, something went wrong.