| //===-- 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 |