llvm-project/flang/runtime/derived.cpp
peter klausler 4fede8bc8a [flang] Implement derived type description table encoding
Define Fortran derived types that describe the characteristics
of derived types, and instantiations of parameterized derived
types, that are of relevance to the runtime language support
library.  Define a suite of corresponding C++ structure types
for the runtime library to use to interpret instances of the
descriptions.

Create instances of these description types in Semantics as
static initializers for compiler-created objects in the scopes
that define or instantiate user derived types.

Delete obsolete code from earlier attempts to package runtime
type information.

Differential Revision: https://reviews.llvm.org/D92802
2020-12-08 10:26:58 -08:00

124 lines
4.7 KiB
C++

//===-- runtime/derived.cpp -----------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "derived.h"
#include "descriptor.h"
#include "type-info.h"
namespace Fortran::runtime {
static const typeInfo::SpecialBinding *FindFinal(
const typeInfo::DerivedType &derived, int rank) {
const typeInfo::SpecialBinding *elemental{nullptr};
const Descriptor &specialDesc{derived.special.descriptor()};
std::size_t totalSpecialBindings{specialDesc.Elements()};
for (std::size_t j{0}; j < totalSpecialBindings; ++j) {
const auto &special{
*specialDesc.ZeroBasedIndexedElement<typeInfo::SpecialBinding>(j)};
switch (special.which) {
case typeInfo::SpecialBinding::Which::Final:
if (special.rank == rank) {
return &special;
}
break;
case typeInfo::SpecialBinding::Which::ElementalFinal:
elemental = &special;
break;
case typeInfo::SpecialBinding::Which::AssumedRankFinal:
return &special;
default:;
}
}
return elemental;
}
static void CallFinalSubroutine(
const Descriptor &descriptor, const typeInfo::DerivedType &derived) {
if (const auto *special{FindFinal(derived, descriptor.rank())}) {
if (special->which == typeInfo::SpecialBinding::Which::ElementalFinal) {
std::size_t byteStride{descriptor.ElementBytes()};
auto p{reinterpret_cast<void (*)(char *)>(special->proc)};
// Finalizable objects must be contiguous.
std::size_t elements{descriptor.Elements()};
for (std::size_t j{0}; j < elements; ++j) {
p(descriptor.OffsetElement<char>(j * byteStride));
}
} else if (special->isArgDescriptorSet & 1) {
auto p{reinterpret_cast<void (*)(const Descriptor &)>(special->proc)};
p(descriptor);
} else {
// Finalizable objects must be contiguous.
auto p{reinterpret_cast<void (*)(char *)>(special->proc)};
p(descriptor.OffsetElement<char>());
}
}
}
static inline SubscriptValue GetValue(
const typeInfo::Value &value, const Descriptor &descriptor) {
if (value.genre == typeInfo::Value::Genre::LenParameter) {
return descriptor.Addendum()->LenParameterValue(value.value);
} else {
return value.value;
}
}
// The order of finalization follows Fortran 2018 7.5.6.2, with
// deallocation of non-parent components (and their consequent finalization)
// taking place before parent component finalization.
void Destroy(const Descriptor &descriptor, bool finalize,
const typeInfo::DerivedType &derived) {
if (finalize) {
CallFinalSubroutine(descriptor, derived);
}
const Descriptor &componentDesc{derived.component.descriptor()};
std::int64_t myComponents{componentDesc.GetDimension(0).Extent()};
std::size_t elements{descriptor.Elements()};
std::size_t byteStride{descriptor.ElementBytes()};
for (unsigned k{0}; k < myComponents; ++k) {
const auto &comp{
*componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
if (comp.genre == typeInfo::Component::Genre::Allocatable ||
comp.genre == typeInfo::Component::Genre::Automatic) {
for (std::size_t j{0}; j < elements; ++j) {
descriptor.OffsetElement<Descriptor>(j * byteStride + comp.offset)
->Deallocate(finalize);
}
} else if (comp.genre == typeInfo::Component::Genre::Data &&
comp.derivedType.descriptor().raw().base_addr) {
SubscriptValue extent[maxRank];
const Descriptor &boundsDesc{comp.bounds.descriptor()};
for (int dim{0}; dim < comp.rank; ++dim) {
extent[dim] =
GetValue(
*boundsDesc.ZeroBasedIndexedElement<typeInfo::Value>(2 * dim),
descriptor) -
GetValue(*boundsDesc.ZeroBasedIndexedElement<typeInfo::Value>(
2 * dim + 1),
descriptor) +
1;
}
StaticDescriptor<maxRank, true, 0> staticDescriptor;
Descriptor &compDesc{staticDescriptor.descriptor()};
const auto &compType{*comp.derivedType.descriptor()
.OffsetElement<typeInfo::DerivedType>()};
for (std::size_t j{0}; j < elements; ++j) {
compDesc.Establish(compType,
descriptor.OffsetElement<char>(j * byteStride + comp.offset),
comp.rank, extent);
Destroy(compDesc, finalize, compType);
}
}
}
const Descriptor &parentDesc{derived.parent.descriptor()};
if (const auto *parent{parentDesc.OffsetElement<typeInfo::DerivedType>()}) {
Destroy(descriptor, finalize, *parent);
}
}
} // namespace Fortran::runtime