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