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 
16 namespace Fortran::runtime {
17 
CopyElement(const Descriptor & to,const SubscriptValue toAt[],const Descriptor & from,const SubscriptValue fromAt[],Terminator & terminator)18 void CopyElement(const Descriptor &to, const SubscriptValue toAt[],
19     const Descriptor &from, const SubscriptValue fromAt[],
20     Terminator &terminator) {
21   char *toPtr{to.Element<char>(toAt)};
22   const char *fromPtr{from.Element<const char>(fromAt)};
23   RUNTIME_CHECK(terminator, to.ElementBytes() == from.ElementBytes());
24   std::memcpy(toPtr, fromPtr, to.ElementBytes());
25   if (const auto *addendum{to.Addendum()}) {
26     if (const auto *derived{addendum->derivedType()}) {
27       RUNTIME_CHECK(terminator,
28           from.Addendum() && derived == from.Addendum()->derivedType());
29       const Descriptor &componentDesc{derived->component()};
30       const typeInfo::Component *component{
31           componentDesc.OffsetElement<typeInfo::Component>()};
32       std::size_t nComponents{componentDesc.Elements()};
33       for (std::size_t j{0}; j < nComponents; ++j, ++component) {
34         if (component->genre() == typeInfo::Component::Genre::Allocatable ||
35             component->genre() == typeInfo::Component::Genre::Automatic) {
36           Descriptor &toDesc{
37               *reinterpret_cast<Descriptor *>(toPtr + component->offset())};
38           if (toDesc.raw().base_addr != nullptr) {
39             toDesc.set_base_addr(nullptr);
40             RUNTIME_CHECK(terminator, toDesc.Allocate() == CFI_SUCCESS);
41             const Descriptor &fromDesc{*reinterpret_cast<const Descriptor *>(
42                 fromPtr + component->offset())};
43             CopyArray(toDesc, fromDesc, terminator);
44           }
45         }
46       }
47     }
48   }
49 }
50 
CopyArray(const Descriptor & to,const Descriptor & from,Terminator & terminator)51 void CopyArray(
52     const Descriptor &to, const Descriptor &from, Terminator &terminator) {
53   std::size_t elements{to.Elements()};
54   RUNTIME_CHECK(terminator, elements == from.Elements());
55   SubscriptValue toAt[maxRank], fromAt[maxRank];
56   to.GetLowerBounds(toAt);
57   from.GetLowerBounds(fromAt);
58   while (elements-- > 0) {
59     CopyElement(to, toAt, from, fromAt, terminator);
60     to.IncrementSubscripts(toAt);
61     from.IncrementSubscripts(fromAt);
62   }
63 }
64 } // namespace Fortran::runtime
65