14fede8bcSpeter klausler //===-- runtime/derived.cpp -----------------------------------------------===//
24fede8bcSpeter klausler //
34fede8bcSpeter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44fede8bcSpeter klausler // See https://llvm.org/LICENSE.txt for license information.
54fede8bcSpeter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64fede8bcSpeter klausler //
74fede8bcSpeter klausler //===----------------------------------------------------------------------===//
84fede8bcSpeter klausler
94fede8bcSpeter klausler #include "derived.h"
10a48e4168Speter klausler #include "stat.h"
11a48e4168Speter klausler #include "terminator.h"
124fede8bcSpeter klausler #include "type-info.h"
13830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
144fede8bcSpeter klausler
154fede8bcSpeter klausler namespace Fortran::runtime {
164fede8bcSpeter klausler
Initialize(const Descriptor & instance,const typeInfo::DerivedType & derived,Terminator & terminator,bool hasStat,const Descriptor * errMsg)17a48e4168Speter klausler int Initialize(const Descriptor &instance, const typeInfo::DerivedType &derived,
18a48e4168Speter klausler Terminator &terminator, bool hasStat, const Descriptor *errMsg) {
19a48e4168Speter klausler const Descriptor &componentDesc{derived.component()};
20a48e4168Speter klausler std::size_t elements{instance.Elements()};
21a48e4168Speter klausler std::size_t byteStride{instance.ElementBytes()};
22a48e4168Speter klausler int stat{StatOk};
23a48e4168Speter klausler // Initialize data components in each element; the per-element iteration
24a48e4168Speter klausler // constitutes the inner loops, not outer
25a48e4168Speter klausler std::size_t myComponents{componentDesc.Elements()};
26a48e4168Speter klausler for (std::size_t k{0}; k < myComponents; ++k) {
27a48e4168Speter klausler const auto &comp{
28a48e4168Speter klausler *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
29a48e4168Speter klausler if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
30a48e4168Speter klausler comp.genre() == typeInfo::Component::Genre::Automatic) {
31a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
32a48e4168Speter klausler Descriptor &allocDesc{*instance.OffsetElement<Descriptor>(
33a48e4168Speter klausler j * byteStride + comp.offset())};
34a48e4168Speter klausler comp.EstablishDescriptor(allocDesc, instance, terminator);
35a48e4168Speter klausler allocDesc.raw().attribute = CFI_attribute_allocatable;
36a48e4168Speter klausler if (comp.genre() == typeInfo::Component::Genre::Automatic) {
37a48e4168Speter klausler stat = ReturnError(terminator, allocDesc.Allocate(), errMsg, hasStat);
38a48e4168Speter klausler if (stat == StatOk) {
39a48e4168Speter klausler stat = Initialize(allocDesc, derived, terminator, hasStat, errMsg);
40a48e4168Speter klausler }
41a48e4168Speter klausler if (stat != StatOk) {
42a48e4168Speter klausler break;
43a48e4168Speter klausler }
44a48e4168Speter klausler }
45a48e4168Speter klausler }
46a48e4168Speter klausler } else if (const void *init{comp.initialization()}) {
47a48e4168Speter klausler // Explicit initialization of data pointers and
48a48e4168Speter klausler // non-allocatable non-automatic components
49a48e4168Speter klausler std::size_t bytes{comp.SizeInBytes(instance)};
50a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
51a48e4168Speter klausler char *ptr{instance.OffsetElement<char>(j * byteStride + comp.offset())};
52a48e4168Speter klausler std::memcpy(ptr, init, bytes);
53a48e4168Speter klausler }
54a48e4168Speter klausler } else if (comp.genre() == typeInfo::Component::Genre::Data &&
55a48e4168Speter klausler comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) {
56a48e4168Speter klausler // Default initialization of non-pointer non-allocatable/automatic
57a48e4168Speter klausler // data component. Handles parent component's elements. Recursive.
58a48e4168Speter klausler SubscriptValue extent[maxRank];
59a48e4168Speter klausler const typeInfo::Value *bounds{comp.bounds()};
60a48e4168Speter klausler for (int dim{0}; dim < comp.rank(); ++dim) {
61a48e4168Speter klausler typeInfo::TypeParameterValue lb{
62a48e4168Speter klausler bounds[2 * dim].GetValue(&instance).value_or(0)};
63a48e4168Speter klausler typeInfo::TypeParameterValue ub{
64a48e4168Speter klausler bounds[2 * dim + 1].GetValue(&instance).value_or(0)};
65a48e4168Speter klausler extent[dim] = ub >= lb ? ub - lb + 1 : 0;
66a48e4168Speter klausler }
67a48e4168Speter klausler StaticDescriptor<maxRank, true, 0> staticDescriptor;
68a48e4168Speter klausler Descriptor &compDesc{staticDescriptor.descriptor()};
69a48e4168Speter klausler const typeInfo::DerivedType &compType{*comp.derivedType()};
70a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
71a48e4168Speter klausler compDesc.Establish(compType,
72a48e4168Speter klausler instance.OffsetElement<char>(j * byteStride + comp.offset()),
73a48e4168Speter klausler comp.rank(), extent);
74a48e4168Speter klausler stat = Initialize(compDesc, compType, terminator, hasStat, errMsg);
75a48e4168Speter klausler if (stat != StatOk) {
76a48e4168Speter klausler break;
77a48e4168Speter klausler }
78a48e4168Speter klausler }
79a48e4168Speter klausler }
80a48e4168Speter klausler }
81a48e4168Speter klausler // Initialize procedure pointer components in each element
82a48e4168Speter klausler const Descriptor &procPtrDesc{derived.procPtr()};
83a48e4168Speter klausler std::size_t myProcPtrs{procPtrDesc.Elements()};
84a48e4168Speter klausler for (std::size_t k{0}; k < myProcPtrs; ++k) {
85a48e4168Speter klausler const auto &comp{
86a48e4168Speter klausler *procPtrDesc.ZeroBasedIndexedElement<typeInfo::ProcPtrComponent>(k)};
87a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
88a48e4168Speter klausler auto &pptr{*instance.OffsetElement<typeInfo::ProcedurePointer>(
89a48e4168Speter klausler j * byteStride + comp.offset)};
90a48e4168Speter klausler pptr = comp.procInitialization;
91a48e4168Speter klausler }
92a48e4168Speter klausler }
93a48e4168Speter klausler return stat;
94a48e4168Speter klausler }
95a48e4168Speter klausler
FindFinal(const typeInfo::DerivedType & derived,int rank)964fede8bcSpeter klausler static const typeInfo::SpecialBinding *FindFinal(
974fede8bcSpeter klausler const typeInfo::DerivedType &derived, int rank) {
9865f52904Speter klausler if (const auto *ranked{derived.FindSpecialBinding(
9965f52904Speter klausler typeInfo::SpecialBinding::RankFinal(rank))}) {
10065f52904Speter klausler return ranked;
10165f52904Speter klausler } else if (const auto *assumed{derived.FindSpecialBinding(
10265f52904Speter klausler typeInfo::SpecialBinding::Which::AssumedRankFinal)}) {
10365f52904Speter klausler return assumed;
10465f52904Speter klausler } else {
10565f52904Speter klausler return derived.FindSpecialBinding(
10665f52904Speter klausler typeInfo::SpecialBinding::Which::ElementalFinal);
1074fede8bcSpeter klausler }
1084fede8bcSpeter klausler }
1094fede8bcSpeter klausler
CallFinalSubroutine(const Descriptor & descriptor,const typeInfo::DerivedType & derived)1104fede8bcSpeter klausler static void CallFinalSubroutine(
1114fede8bcSpeter klausler const Descriptor &descriptor, const typeInfo::DerivedType &derived) {
1124fede8bcSpeter klausler if (const auto *special{FindFinal(derived, descriptor.rank())}) {
113a48e4168Speter klausler // The following code relies on the fact that finalizable objects
114a48e4168Speter klausler // must be contiguous.
11543fadefbSpeter klausler if (special->which() == typeInfo::SpecialBinding::Which::ElementalFinal) {
1164fede8bcSpeter klausler std::size_t byteStride{descriptor.ElementBytes()};
1174fede8bcSpeter klausler std::size_t elements{descriptor.Elements()};
118a48e4168Speter klausler if (special->IsArgDescriptor(0)) {
119a48e4168Speter klausler StaticDescriptor<maxRank, true, 8 /*?*/> statDesc;
120a48e4168Speter klausler Descriptor &elemDesc{statDesc.descriptor()};
121a48e4168Speter klausler elemDesc = descriptor;
122a48e4168Speter klausler elemDesc.raw().attribute = CFI_attribute_pointer;
123a48e4168Speter klausler elemDesc.raw().rank = 0;
124a48e4168Speter klausler auto *p{special->GetProc<void (*)(const Descriptor &)>()};
125a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
126a48e4168Speter klausler elemDesc.set_base_addr(
127a48e4168Speter klausler descriptor.OffsetElement<char>(j * byteStride));
128a48e4168Speter klausler p(elemDesc);
129a48e4168Speter klausler }
130a48e4168Speter klausler } else {
131a48e4168Speter klausler auto *p{special->GetProc<void (*)(char *)>()};
1324fede8bcSpeter klausler for (std::size_t j{0}; j < elements; ++j) {
1334fede8bcSpeter klausler p(descriptor.OffsetElement<char>(j * byteStride));
1344fede8bcSpeter klausler }
135a48e4168Speter klausler }
13643fadefbSpeter klausler } else if (special->IsArgDescriptor(0)) {
137a48e4168Speter klausler StaticDescriptor<maxRank, true, 8 /*?*/> statDesc;
138a48e4168Speter klausler Descriptor &tmpDesc{statDesc.descriptor()};
139a48e4168Speter klausler tmpDesc = descriptor;
140a48e4168Speter klausler tmpDesc.raw().attribute = CFI_attribute_pointer;
141a48e4168Speter klausler tmpDesc.Addendum()->set_derivedType(&derived);
14243fadefbSpeter klausler auto *p{special->GetProc<void (*)(const Descriptor &)>()};
143a48e4168Speter klausler p(tmpDesc);
1444fede8bcSpeter klausler } else {
14543fadefbSpeter klausler auto *p{special->GetProc<void (*)(char *)>()};
1464fede8bcSpeter klausler p(descriptor.OffsetElement<char>());
1474fede8bcSpeter klausler }
1484fede8bcSpeter klausler }
1494fede8bcSpeter klausler }
1504fede8bcSpeter klausler
15165f52904Speter klausler // Fortran 2018 subclause 7.5.6.2
Finalize(const Descriptor & descriptor,const typeInfo::DerivedType & derived)15265f52904Speter klausler void Finalize(
15365f52904Speter klausler const Descriptor &descriptor, const typeInfo::DerivedType &derived) {
15465f52904Speter klausler if (derived.noFinalizationNeeded() || !descriptor.IsAllocated()) {
15565f52904Speter klausler return;
1564fede8bcSpeter klausler }
15765f52904Speter klausler CallFinalSubroutine(descriptor, derived);
15865f52904Speter klausler const auto *parentType{derived.GetParentType()};
15965f52904Speter klausler bool recurse{parentType && !parentType->noFinalizationNeeded()};
16065f52904Speter klausler // If there's a finalizable parent component, handle it last, as required
16165f52904Speter klausler // by the Fortran standard (7.5.6.2), and do so recursively with the same
16265f52904Speter klausler // descriptor so that the rank is preserved.
16379caf69cSpeter klausler const Descriptor &componentDesc{derived.component()};
164a48e4168Speter klausler std::size_t myComponents{componentDesc.Elements()};
1654fede8bcSpeter klausler std::size_t elements{descriptor.Elements()};
1664fede8bcSpeter klausler std::size_t byteStride{descriptor.ElementBytes()};
167a48e4168Speter klausler for (auto k{recurse
168a48e4168Speter klausler ? std::size_t{1} /* skip first component, it's the parent */
169a48e4168Speter klausler : 0};
170a48e4168Speter klausler k < myComponents; ++k) {
1714fede8bcSpeter klausler const auto &comp{
1724fede8bcSpeter klausler *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
17379caf69cSpeter klausler if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
17479caf69cSpeter klausler comp.genre() == typeInfo::Component::Genre::Automatic) {
175a48e4168Speter klausler if (const typeInfo::DerivedType * compType{comp.derivedType()}) {
17665f52904Speter klausler if (!compType->noFinalizationNeeded()) {
177a48e4168Speter klausler for (std::size_t j{0}; j < elements; ++j) {
17865f52904Speter klausler const Descriptor &compDesc{*descriptor.OffsetElement<Descriptor>(
17965f52904Speter klausler j * byteStride + comp.offset())};
18065f52904Speter klausler if (compDesc.IsAllocated()) {
18165f52904Speter klausler Finalize(compDesc, *compType);
182a48e4168Speter klausler }
183a48e4168Speter klausler }
184a48e4168Speter klausler }
1854fede8bcSpeter klausler }
18679caf69cSpeter klausler } else if (comp.genre() == typeInfo::Component::Genre::Data &&
18765f52904Speter klausler comp.derivedType() && !comp.derivedType()->noFinalizationNeeded()) {
1884fede8bcSpeter klausler SubscriptValue extent[maxRank];
18979caf69cSpeter klausler const typeInfo::Value *bounds{comp.bounds()};
19079caf69cSpeter klausler for (int dim{0}; dim < comp.rank(); ++dim) {
191*041080fcSPeter Klausler SubscriptValue lb{bounds[2 * dim].GetValue(&descriptor).value_or(0)};
192*041080fcSPeter Klausler SubscriptValue ub{
193*041080fcSPeter Klausler bounds[2 * dim + 1].GetValue(&descriptor).value_or(0)};
194*041080fcSPeter Klausler extent[dim] = ub >= lb ? ub - lb + 1 : 0;
1954fede8bcSpeter klausler }
1964fede8bcSpeter klausler StaticDescriptor<maxRank, true, 0> staticDescriptor;
1974fede8bcSpeter klausler Descriptor &compDesc{staticDescriptor.descriptor()};
19879caf69cSpeter klausler const typeInfo::DerivedType &compType{*comp.derivedType()};
1994fede8bcSpeter klausler for (std::size_t j{0}; j < elements; ++j) {
2004fede8bcSpeter klausler compDesc.Establish(compType,
20179caf69cSpeter klausler descriptor.OffsetElement<char>(j * byteStride + comp.offset()),
20279caf69cSpeter klausler comp.rank(), extent);
20365f52904Speter klausler Finalize(compDesc, compType);
2044fede8bcSpeter klausler }
2054fede8bcSpeter klausler }
2064fede8bcSpeter klausler }
207a48e4168Speter klausler if (recurse) {
20865f52904Speter klausler Finalize(descriptor, *parentType);
2094fede8bcSpeter klausler }
2104fede8bcSpeter klausler }
211a48e4168Speter klausler
21265f52904Speter klausler // The order of finalization follows Fortran 2018 7.5.6.2, with
213ef44cad5Speter klausler // elementwise finalization of non-parent components taking place
214ef44cad5Speter klausler // before parent component finalization, and with all finalization
215ef44cad5Speter klausler // preceding any deallocation.
Destroy(const Descriptor & descriptor,bool finalize,const typeInfo::DerivedType & derived)21665f52904Speter klausler void Destroy(const Descriptor &descriptor, bool finalize,
21765f52904Speter klausler const typeInfo::DerivedType &derived) {
21865f52904Speter klausler if (derived.noDestructionNeeded() || !descriptor.IsAllocated()) {
21965f52904Speter klausler return;
22065f52904Speter klausler }
22165f52904Speter klausler if (finalize && !derived.noFinalizationNeeded()) {
22265f52904Speter klausler Finalize(descriptor, derived);
22365f52904Speter klausler }
22465f52904Speter klausler const Descriptor &componentDesc{derived.component()};
22565f52904Speter klausler std::size_t myComponents{componentDesc.Elements()};
22665f52904Speter klausler std::size_t elements{descriptor.Elements()};
22765f52904Speter klausler std::size_t byteStride{descriptor.ElementBytes()};
22865f52904Speter klausler for (std::size_t k{0}; k < myComponents; ++k) {
22965f52904Speter klausler const auto &comp{
23065f52904Speter klausler *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
23165f52904Speter klausler if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
23265f52904Speter klausler comp.genre() == typeInfo::Component::Genre::Automatic) {
23365f52904Speter klausler for (std::size_t j{0}; j < elements; ++j) {
23465f52904Speter klausler descriptor.OffsetElement<Descriptor>(j * byteStride + comp.offset())
23565f52904Speter klausler ->Deallocate();
23665f52904Speter klausler }
23765f52904Speter klausler }
23865f52904Speter klausler }
23965f52904Speter klausler }
240a48e4168Speter klausler
2414fede8bcSpeter klausler } // namespace Fortran::runtime
242