//===-- 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 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(toAt)}; char *fromPtr{from.Element(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()}; 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(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( 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 toStaticDescriptor; Descriptor &toCompDesc{toStaticDescriptor.descriptor()}; toCompDesc.Establish(compType, toPtr + component->offset(), component->rank(), extents); StaticDescriptor 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