1 //===-- runtime/derived.cpp -----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include "terminator.h"
13 #include "type-info.h"
14 #include "flang/Runtime/descriptor.h"
16 namespace Fortran::runtime
{
18 RT_OFFLOAD_API_GROUP_BEGIN
20 RT_API_ATTRS
int Initialize(const Descriptor
&instance
,
21 const typeInfo::DerivedType
&derived
, Terminator
&terminator
, bool hasStat
,
22 const Descriptor
*errMsg
) {
23 const Descriptor
&componentDesc
{derived
.component()};
24 std::size_t elements
{instance
.Elements()};
26 // Initialize data components in each element; the per-element iterations
27 // constitute the inner loops, not the outer ones
28 std::size_t myComponents
{componentDesc
.Elements()};
29 for (std::size_t k
{0}; k
< myComponents
; ++k
) {
31 *componentDesc
.ZeroBasedIndexedElement
<typeInfo::Component
>(k
)};
32 SubscriptValue at
[maxRank
];
33 instance
.GetLowerBounds(at
);
34 if (comp
.genre() == typeInfo::Component::Genre::Allocatable
||
35 comp
.genre() == typeInfo::Component::Genre::Automatic
) {
36 for (std::size_t j
{0}; j
++ < elements
; instance
.IncrementSubscripts(at
)) {
37 Descriptor
&allocDesc
{
38 *instance
.ElementComponent
<Descriptor
>(at
, comp
.offset())};
39 comp
.EstablishDescriptor(allocDesc
, instance
, terminator
);
40 allocDesc
.raw().attribute
= CFI_attribute_allocatable
;
41 if (comp
.genre() == typeInfo::Component::Genre::Automatic
) {
42 stat
= ReturnError(terminator
, allocDesc
.Allocate(), errMsg
, hasStat
);
44 if (const DescriptorAddendum
* addendum
{allocDesc
.Addendum()}) {
45 if (const auto *derived
{addendum
->derivedType()}) {
46 if (!derived
->noInitializationNeeded()) {
48 allocDesc
, *derived
, terminator
, hasStat
, errMsg
);
58 } else if (const void *init
{comp
.initialization()}) {
59 // Explicit initialization of data pointers and
60 // non-allocatable non-automatic components
61 std::size_t bytes
{comp
.SizeInBytes(instance
)};
62 for (std::size_t j
{0}; j
++ < elements
; instance
.IncrementSubscripts(at
)) {
63 char *ptr
{instance
.ElementComponent
<char>(at
, comp
.offset())};
64 std::memcpy(ptr
, init
, bytes
);
66 } else if (comp
.genre() == typeInfo::Component::Genre::Pointer
) {
67 // Data pointers without explicit initialization are established
68 // so that they are valid right-hand side targets of pointer
69 // assignment statements.
70 for (std::size_t j
{0}; j
++ < elements
; instance
.IncrementSubscripts(at
)) {
72 *instance
.ElementComponent
<Descriptor
>(at
, comp
.offset())};
73 comp
.EstablishDescriptor(ptrDesc
, instance
, terminator
);
74 ptrDesc
.raw().attribute
= CFI_attribute_pointer
;
76 } else if (comp
.genre() == typeInfo::Component::Genre::Data
&&
77 comp
.derivedType() && !comp
.derivedType()->noInitializationNeeded()) {
78 // Default initialization of non-pointer non-allocatable/automatic
79 // data component. Handles parent component's elements. Recursive.
80 SubscriptValue extent
[maxRank
];
81 const typeInfo::Value
*bounds
{comp
.bounds()};
82 for (int dim
{0}; dim
< comp
.rank(); ++dim
) {
83 typeInfo::TypeParameterValue lb
{
84 bounds
[2 * dim
].GetValue(&instance
).value_or(0)};
85 typeInfo::TypeParameterValue ub
{
86 bounds
[2 * dim
+ 1].GetValue(&instance
).value_or(0)};
87 extent
[dim
] = ub
>= lb
? ub
- lb
+ 1 : 0;
89 StaticDescriptor
<maxRank
, true, 0> staticDescriptor
;
90 Descriptor
&compDesc
{staticDescriptor
.descriptor()};
91 const typeInfo::DerivedType
&compType
{*comp
.derivedType()};
92 for (std::size_t j
{0}; j
++ < elements
; instance
.IncrementSubscripts(at
)) {
93 compDesc
.Establish(compType
,
94 instance
.ElementComponent
<char>(at
, comp
.offset()), comp
.rank(),
96 stat
= Initialize(compDesc
, compType
, terminator
, hasStat
, errMsg
);
103 // Initialize procedure pointer components in each element
104 const Descriptor
&procPtrDesc
{derived
.procPtr()};
105 std::size_t myProcPtrs
{procPtrDesc
.Elements()};
106 for (std::size_t k
{0}; k
< myProcPtrs
; ++k
) {
108 *procPtrDesc
.ZeroBasedIndexedElement
<typeInfo::ProcPtrComponent
>(k
)};
109 SubscriptValue at
[maxRank
];
110 instance
.GetLowerBounds(at
);
111 for (std::size_t j
{0}; j
++ < elements
; instance
.IncrementSubscripts(at
)) {
112 auto &pptr
{*instance
.ElementComponent
<typeInfo::ProcedurePointer
>(
114 pptr
= comp
.procInitialization
;
120 static RT_API_ATTRS
const typeInfo::SpecialBinding
*FindFinal(
121 const typeInfo::DerivedType
&derived
, int rank
) {
122 if (const auto *ranked
{derived
.FindSpecialBinding(
123 typeInfo::SpecialBinding::RankFinal(rank
))}) {
125 } else if (const auto *assumed
{derived
.FindSpecialBinding(
126 typeInfo::SpecialBinding::Which::AssumedRankFinal
)}) {
129 return derived
.FindSpecialBinding(
130 typeInfo::SpecialBinding::Which::ElementalFinal
);
134 static RT_API_ATTRS
void CallFinalSubroutine(const Descriptor
&descriptor
,
135 const typeInfo::DerivedType
&derived
, Terminator
*terminator
) {
136 if (const auto *special
{FindFinal(derived
, descriptor
.rank())}) {
137 if (special
->which() == typeInfo::SpecialBinding::Which::ElementalFinal
) {
138 std::size_t elements
{descriptor
.Elements()};
139 SubscriptValue at
[maxRank
];
140 descriptor
.GetLowerBounds(at
);
141 if (special
->IsArgDescriptor(0)) {
142 StaticDescriptor
<maxRank
, true, 8 /*?*/> statDesc
;
143 Descriptor
&elemDesc
{statDesc
.descriptor()};
144 elemDesc
= descriptor
;
145 elemDesc
.raw().attribute
= CFI_attribute_pointer
;
146 elemDesc
.raw().rank
= 0;
147 auto *p
{special
->GetProc
<void (*)(const Descriptor
&)>()};
148 for (std::size_t j
{0}; j
++ < elements
;
149 descriptor
.IncrementSubscripts(at
)) {
150 elemDesc
.set_base_addr(descriptor
.Element
<char>(at
));
154 auto *p
{special
->GetProc
<void (*)(char *)>()};
155 for (std::size_t j
{0}; j
++ < elements
;
156 descriptor
.IncrementSubscripts(at
)) {
157 p(descriptor
.Element
<char>(at
));
161 StaticDescriptor
<maxRank
, true, 10> statDesc
;
162 Descriptor
©
{statDesc
.descriptor()};
163 const Descriptor
*argDescriptor
{&descriptor
};
164 if (descriptor
.rank() > 0 && special
->IsArgContiguous(0) &&
165 !descriptor
.IsContiguous()) {
166 // The FINAL subroutine demands a contiguous array argument, but
167 // this INTENT(OUT) or intrinsic assignment LHS isn't contiguous.
168 // Finalize a shallow copy of the data.
170 copy
.set_base_addr(nullptr);
171 copy
.raw().attribute
= CFI_attribute_allocatable
;
172 Terminator stubTerminator
{"CallFinalProcedure() in Fortran runtime", 0};
173 RUNTIME_CHECK(terminator
? *terminator
: stubTerminator
,
174 copy
.Allocate() == CFI_SUCCESS
);
175 ShallowCopyDiscontiguousToContiguous(copy
, descriptor
);
176 argDescriptor
= ©
;
178 if (special
->IsArgDescriptor(0)) {
179 StaticDescriptor
<maxRank
, true, 8 /*?*/> statDesc
;
180 Descriptor
&tmpDesc
{statDesc
.descriptor()};
181 tmpDesc
= *argDescriptor
;
182 tmpDesc
.raw().attribute
= CFI_attribute_pointer
;
183 tmpDesc
.Addendum()->set_derivedType(&derived
);
184 auto *p
{special
->GetProc
<void (*)(const Descriptor
&)>()};
187 auto *p
{special
->GetProc
<void (*)(char *)>()};
188 p(argDescriptor
->OffsetElement
<char>());
190 if (argDescriptor
== ©
) {
191 ShallowCopyContiguousToDiscontiguous(descriptor
, copy
);
198 // Fortran 2018 subclause 7.5.6.2
199 RT_API_ATTRS
void Finalize(const Descriptor
&descriptor
,
200 const typeInfo::DerivedType
&derived
, Terminator
*terminator
) {
201 if (derived
.noFinalizationNeeded() || !descriptor
.IsAllocated()) {
204 CallFinalSubroutine(descriptor
, derived
, terminator
);
205 const auto *parentType
{derived
.GetParentType()};
206 bool recurse
{parentType
&& !parentType
->noFinalizationNeeded()};
207 // If there's a finalizable parent component, handle it last, as required
208 // by the Fortran standard (7.5.6.2), and do so recursively with the same
209 // descriptor so that the rank is preserved.
210 const Descriptor
&componentDesc
{derived
.component()};
211 std::size_t myComponents
{componentDesc
.Elements()};
212 std::size_t elements
{descriptor
.Elements()};
213 for (auto k
{recurse
? std::size_t{1}
214 /* skip first component, it's the parent */
216 k
< myComponents
; ++k
) {
218 *componentDesc
.ZeroBasedIndexedElement
<typeInfo::Component
>(k
)};
219 SubscriptValue at
[maxRank
];
220 descriptor
.GetLowerBounds(at
);
221 if (comp
.genre() == typeInfo::Component::Genre::Allocatable
&&
222 comp
.category() == TypeCategory::Derived
) {
223 // Component may be polymorphic or unlimited polymorphic. Need to use the
224 // dynamic type to check whether finalization is needed.
225 for (std::size_t j
{0}; j
++ < elements
;
226 descriptor
.IncrementSubscripts(at
)) {
227 const Descriptor
&compDesc
{
228 *descriptor
.ElementComponent
<Descriptor
>(at
, comp
.offset())};
229 if (compDesc
.IsAllocated()) {
230 if (const DescriptorAddendum
* addendum
{compDesc
.Addendum()}) {
231 if (const typeInfo::DerivedType
*
232 compDynamicType
{addendum
->derivedType()}) {
233 if (!compDynamicType
->noFinalizationNeeded()) {
234 Finalize(compDesc
, *compDynamicType
, terminator
);
240 } else if (comp
.genre() == typeInfo::Component::Genre::Allocatable
||
241 comp
.genre() == typeInfo::Component::Genre::Automatic
) {
242 if (const typeInfo::DerivedType
* compType
{comp
.derivedType()}) {
243 if (!compType
->noFinalizationNeeded()) {
244 for (std::size_t j
{0}; j
++ < elements
;
245 descriptor
.IncrementSubscripts(at
)) {
246 const Descriptor
&compDesc
{
247 *descriptor
.ElementComponent
<Descriptor
>(at
, comp
.offset())};
248 if (compDesc
.IsAllocated()) {
249 Finalize(compDesc
, *compType
, terminator
);
254 } else if (comp
.genre() == typeInfo::Component::Genre::Data
&&
255 comp
.derivedType() && !comp
.derivedType()->noFinalizationNeeded()) {
256 SubscriptValue extent
[maxRank
];
257 const typeInfo::Value
*bounds
{comp
.bounds()};
258 for (int dim
{0}; dim
< comp
.rank(); ++dim
) {
259 SubscriptValue lb
{bounds
[2 * dim
].GetValue(&descriptor
).value_or(0)};
261 bounds
[2 * dim
+ 1].GetValue(&descriptor
).value_or(0)};
262 extent
[dim
] = ub
>= lb
? ub
- lb
+ 1 : 0;
264 StaticDescriptor
<maxRank
, true, 0> staticDescriptor
;
265 Descriptor
&compDesc
{staticDescriptor
.descriptor()};
266 const typeInfo::DerivedType
&compType
{*comp
.derivedType()};
267 for (std::size_t j
{0}; j
++ < elements
;
268 descriptor
.IncrementSubscripts(at
)) {
269 compDesc
.Establish(compType
,
270 descriptor
.ElementComponent
<char>(at
, comp
.offset()), comp
.rank(),
272 Finalize(compDesc
, compType
, terminator
);
277 StaticDescriptor
<maxRank
, true, 8 /*?*/> statDesc
;
278 Descriptor
&tmpDesc
{statDesc
.descriptor()};
279 tmpDesc
= descriptor
;
280 tmpDesc
.raw().attribute
= CFI_attribute_pointer
;
281 tmpDesc
.Addendum()->set_derivedType(parentType
);
282 tmpDesc
.raw().elem_len
= parentType
->sizeInBytes();
283 Finalize(tmpDesc
, *parentType
, terminator
);
287 // The order of finalization follows Fortran 2018 7.5.6.2, with
288 // elementwise finalization of non-parent components taking place
289 // before parent component finalization, and with all finalization
290 // preceding any deallocation.
291 RT_API_ATTRS
void Destroy(const Descriptor
&descriptor
, bool finalize
,
292 const typeInfo::DerivedType
&derived
, Terminator
*terminator
) {
293 if (derived
.noDestructionNeeded() || !descriptor
.IsAllocated()) {
296 if (finalize
&& !derived
.noFinalizationNeeded()) {
297 Finalize(descriptor
, derived
, terminator
);
299 const Descriptor
&componentDesc
{derived
.component()};
300 std::size_t myComponents
{componentDesc
.Elements()};
301 std::size_t elements
{descriptor
.Elements()};
302 SubscriptValue at
[maxRank
];
303 descriptor
.GetLowerBounds(at
);
304 for (std::size_t k
{0}; k
< myComponents
; ++k
) {
306 *componentDesc
.ZeroBasedIndexedElement
<typeInfo::Component
>(k
)};
307 if (comp
.genre() == typeInfo::Component::Genre::Allocatable
||
308 comp
.genre() == typeInfo::Component::Genre::Automatic
) {
309 for (std::size_t j
{0}; j
< elements
; ++j
) {
311 descriptor
.ElementComponent
<Descriptor
>(at
, comp
.offset())};
313 descriptor
.IncrementSubscripts(at
);
319 RT_API_ATTRS
bool HasDynamicComponent(const Descriptor
&descriptor
) {
320 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
321 if (const auto *derived
= addendum
->derivedType()) {
322 const Descriptor
&componentDesc
{derived
->component()};
323 std::size_t myComponents
{componentDesc
.Elements()};
324 for (std::size_t k
{0}; k
< myComponents
; ++k
) {
326 *componentDesc
.ZeroBasedIndexedElement
<typeInfo::Component
>(k
)};
327 if (comp
.genre() == typeInfo::Component::Genre::Allocatable
||
328 comp
.genre() == typeInfo::Component::Genre::Automatic
) {
337 RT_OFFLOAD_API_GROUP_END
338 } // namespace Fortran::runtime