blob: 7cf94836541415536dc5945e0b9a0fb1164339df [file] [log] [blame]
//===-- runtime/copy.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 "copy.h"
#include "terminator.h"
#include "type-info.h"
#include "flang/Runtime/allocatable.h"
#include "flang/Runtime/descriptor.h"
#include <cstring>
namespace Fortran::runtime {
RT_OFFLOAD_API_GROUP_BEGIN
RT_API_ATTRS void CopyElement(const Descriptor &to, const SubscriptValue toAt[],
const Descriptor &from, const SubscriptValue fromAt[],
Terminator &terminator) {
char *toPtr{to.Element<char>(toAt)};
char *fromPtr{from.Element<char>(fromAt)};
RUNTIME_CHECK(terminator, to.ElementBytes() == from.ElementBytes());
std::memcpy(toPtr, fromPtr, to.ElementBytes());
// Deep copy allocatable and automatic components if any.
if (const auto *addendum{to.Addendum()}) {
if (const auto *derived{addendum->derivedType()};
derived && !derived->noDestructionNeeded()) {
RUNTIME_CHECK(terminator,
from.Addendum() && derived == from.Addendum()->derivedType());
const Descriptor &componentDesc{derived->component()};
const typeInfo::Component *component{
componentDesc.OffsetElement<typeInfo::Component>()};
std::size_t nComponents{componentDesc.Elements()};
for (std::size_t j{0}; j < nComponents; ++j, ++component) {
if (component->genre() == typeInfo::Component::Genre::Allocatable ||
component->genre() == typeInfo::Component::Genre::Automatic) {
Descriptor &toDesc{
*reinterpret_cast<Descriptor *>(toPtr + component->offset())};
if (toDesc.raw().base_addr != nullptr) {
toDesc.set_base_addr(nullptr);
RUNTIME_CHECK(terminator, toDesc.Allocate() == CFI_SUCCESS);
const Descriptor &fromDesc{*reinterpret_cast<const Descriptor *>(
fromPtr + component->offset())};
CopyArray(toDesc, fromDesc, terminator);
}
} else if (component->genre() == typeInfo::Component::Genre::Data &&
component->derivedType() &&
!component->derivedType()->noDestructionNeeded()) {
SubscriptValue extents[maxRank];
const typeInfo::Value *bounds{component->bounds()};
for (int dim{0}; dim < component->rank(); ++dim) {
SubscriptValue lb{bounds[2 * dim].GetValue(&to).value_or(0)};
SubscriptValue ub{bounds[2 * dim + 1].GetValue(&to).value_or(0)};
extents[dim] = ub >= lb ? ub - lb + 1 : 0;
}
const typeInfo::DerivedType &compType{*component->derivedType()};
StaticDescriptor<maxRank, true, 0> toStaticDescriptor;
Descriptor &toCompDesc{toStaticDescriptor.descriptor()};
toCompDesc.Establish(compType, toPtr + component->offset(),
component->rank(), extents);
StaticDescriptor<maxRank, true, 0> fromStaticDescriptor;
Descriptor &fromCompDesc{fromStaticDescriptor.descriptor()};
fromCompDesc.Establish(compType, fromPtr + component->offset(),
component->rank(), extents);
CopyArray(toCompDesc, fromCompDesc, terminator);
}
}
}
}
}
RT_API_ATTRS void CopyArray(
const Descriptor &to, const Descriptor &from, Terminator &terminator) {
std::size_t elements{to.Elements()};
RUNTIME_CHECK(terminator, elements == from.Elements());
SubscriptValue toAt[maxRank], fromAt[maxRank];
to.GetLowerBounds(toAt);
from.GetLowerBounds(fromAt);
while (elements-- > 0) {
CopyElement(to, toAt, from, fromAt, terminator);
to.IncrementSubscripts(toAt);
from.IncrementSubscripts(fromAt);
}
}
RT_OFFLOAD_API_GROUP_END
} // namespace Fortran::runtime