1//===-- runtime/copy.cpp -------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "copy.h"
10#include "terminator.h"
11#include "type-info.h"
12#include "flang/Runtime/allocatable.h"
13#include "flang/Runtime/descriptor.h"
14#include <cstring>
15
16namespace Fortran::runtime {
17RT_OFFLOAD_API_GROUP_BEGIN
18
19RT_API_ATTRS void CopyElement(const Descriptor &to, const SubscriptValue toAt[],
20 const Descriptor &from, const SubscriptValue fromAt[],
21 Terminator &terminator) {
22 char *toPtr{to.Element<char>(toAt)};
23 char *fromPtr{from.Element<char>(fromAt)};
24 RUNTIME_CHECK(terminator, to.ElementBytes() == from.ElementBytes());
25 std::memcpy(dest: toPtr, src: fromPtr, n: to.ElementBytes());
26 // Deep copy allocatable and automatic components if any.
27 if (const auto *addendum{to.Addendum()}) {
28 if (const auto *derived{addendum->derivedType()};
29 derived && !derived->noDestructionNeeded()) {
30 RUNTIME_CHECK(terminator,
31 from.Addendum() && derived == from.Addendum()->derivedType());
32 const Descriptor &componentDesc{derived->component()};
33 const typeInfo::Component *component{
34 componentDesc.OffsetElement<typeInfo::Component>()};
35 std::size_t nComponents{componentDesc.Elements()};
36 for (std::size_t j{0}; j < nComponents; ++j, ++component) {
37 if (component->genre() == typeInfo::Component::Genre::Allocatable ||
38 component->genre() == typeInfo::Component::Genre::Automatic) {
39 Descriptor &toDesc{
40 *reinterpret_cast<Descriptor *>(toPtr + component->offset())};
41 if (toDesc.raw().base_addr != nullptr) {
42 toDesc.set_base_addr(nullptr);
43 RUNTIME_CHECK(terminator, toDesc.Allocate() == CFI_SUCCESS);
44 const Descriptor &fromDesc{*reinterpret_cast<const Descriptor *>(
45 fromPtr + component->offset())};
46 CopyArray(toDesc, fromDesc, terminator);
47 }
48 } else if (component->genre() == typeInfo::Component::Genre::Data &&
49 component->derivedType() &&
50 !component->derivedType()->noDestructionNeeded()) {
51 SubscriptValue extents[maxRank];
52 const typeInfo::Value *bounds{component->bounds()};
53 for (int dim{0}; dim < component->rank(); ++dim) {
54 SubscriptValue lb{bounds[2 * dim].GetValue(&to).value_or(0)};
55 SubscriptValue ub{bounds[2 * dim + 1].GetValue(&to).value_or(0)};
56 extents[dim] = ub >= lb ? ub - lb + 1 : 0;
57 }
58 const typeInfo::DerivedType &compType{*component->derivedType()};
59 StaticDescriptor<maxRank, true, 0> toStaticDescriptor;
60 Descriptor &toCompDesc{toStaticDescriptor.descriptor()};
61 toCompDesc.Establish(compType, toPtr + component->offset(),
62 component->rank(), extents);
63 StaticDescriptor<maxRank, true, 0> fromStaticDescriptor;
64 Descriptor &fromCompDesc{fromStaticDescriptor.descriptor()};
65 fromCompDesc.Establish(compType, fromPtr + component->offset(),
66 component->rank(), extents);
67 CopyArray(toCompDesc, fromCompDesc, terminator);
68 }
69 }
70 }
71 }
72}
73
74RT_API_ATTRS void CopyArray(
75 const Descriptor &to, const Descriptor &from, Terminator &terminator) {
76 std::size_t elements{to.Elements()};
77 RUNTIME_CHECK(terminator, elements == from.Elements());
78 SubscriptValue toAt[maxRank], fromAt[maxRank];
79 to.GetLowerBounds(toAt);
80 from.GetLowerBounds(fromAt);
81 while (elements-- > 0) {
82 CopyElement(to, toAt, from, fromAt, terminator);
83 to.IncrementSubscripts(toAt);
84 from.IncrementSubscripts(fromAt);
85 }
86}
87
88RT_OFFLOAD_API_GROUP_END
89} // namespace Fortran::runtime
90

source code of flang/runtime/copy.cpp