xref: /llvm-project/flang/runtime/pointer.cpp (revision 084d943663488084c7160b716cad0dc12d4ca115)
1ad424cf1Speter klausler //===-- runtime/pointer.cpp -----------------------------------------------===//
2ad424cf1Speter klausler //
3ad424cf1Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ad424cf1Speter klausler // See https://llvm.org/LICENSE.txt for license information.
5ad424cf1Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ad424cf1Speter klausler //
7ad424cf1Speter klausler //===----------------------------------------------------------------------===//
8ad424cf1Speter klausler 
9830c0b90SPeter Klausler #include "flang/Runtime/pointer.h"
10755535b5SPeter Klausler #include "assign-impl.h"
11a48e4168Speter klausler #include "derived.h"
12af964c7eSPeter Klausler #include "environment.h"
13ad424cf1Speter klausler #include "stat.h"
14ad424cf1Speter klausler #include "terminator.h"
15ad424cf1Speter klausler #include "tools.h"
16a48e4168Speter klausler #include "type-info.h"
17ad424cf1Speter klausler 
18ad424cf1Speter klausler namespace Fortran::runtime {
19ad424cf1Speter klausler extern "C" {
2076facde3SSlava Zakharin RT_EXT_API_GROUP_BEGIN
21ad424cf1Speter klausler 
RTDEF(PointerNullifyIntrinsic)2276facde3SSlava Zakharin void RTDEF(PointerNullifyIntrinsic)(Descriptor &pointer, TypeCategory category,
23ad424cf1Speter klausler     int kind, int rank, int corank) {
24ad424cf1Speter klausler   INTERNAL_CHECK(corank == 0);
25ad424cf1Speter klausler   pointer.Establish(TypeCode{category, kind},
26ad424cf1Speter klausler       Descriptor::BytesFor(category, kind), nullptr, rank, nullptr,
27ad424cf1Speter klausler       CFI_attribute_pointer);
28ad424cf1Speter klausler }
29ad424cf1Speter klausler 
RTDEF(PointerNullifyCharacter)3076facde3SSlava Zakharin void RTDEF(PointerNullifyCharacter)(Descriptor &pointer, SubscriptValue length,
31ad424cf1Speter klausler     int kind, int rank, int corank) {
32ad424cf1Speter klausler   INTERNAL_CHECK(corank == 0);
33ad424cf1Speter klausler   pointer.Establish(
34ad424cf1Speter klausler       kind, length, nullptr, rank, nullptr, CFI_attribute_pointer);
35ad424cf1Speter klausler }
36ad424cf1Speter klausler 
RTDEF(PointerNullifyDerived)3776facde3SSlava Zakharin void RTDEF(PointerNullifyDerived)(Descriptor &pointer,
38ad424cf1Speter klausler     const typeInfo::DerivedType &derivedType, int rank, int corank) {
39ad424cf1Speter klausler   INTERNAL_CHECK(corank == 0);
40ad424cf1Speter klausler   pointer.Establish(derivedType, nullptr, rank, nullptr, CFI_attribute_pointer);
41ad424cf1Speter klausler }
42ad424cf1Speter klausler 
RTDEF(PointerSetBounds)4376facde3SSlava Zakharin void RTDEF(PointerSetBounds)(Descriptor &pointer, int zeroBasedDim,
44ad424cf1Speter klausler     SubscriptValue lower, SubscriptValue upper) {
45ad424cf1Speter klausler   INTERNAL_CHECK(zeroBasedDim >= 0 && zeroBasedDim < pointer.rank());
46ad424cf1Speter klausler   pointer.GetDimension(zeroBasedDim).SetBounds(lower, upper);
47ad424cf1Speter klausler   // The byte strides are computed when the pointer is allocated.
48ad424cf1Speter klausler }
49ad424cf1Speter klausler 
50ad424cf1Speter klausler // TODO: PointerSetCoBounds
51ad424cf1Speter klausler 
RTDEF(PointerSetDerivedLength)5276facde3SSlava Zakharin void RTDEF(PointerSetDerivedLength)(
53ad424cf1Speter klausler     Descriptor &pointer, int which, SubscriptValue x) {
54ad424cf1Speter klausler   DescriptorAddendum *addendum{pointer.Addendum()};
55ad424cf1Speter klausler   INTERNAL_CHECK(addendum != nullptr);
56ad424cf1Speter klausler   addendum->SetLenParameterValue(which, x);
57ad424cf1Speter klausler }
58ad424cf1Speter klausler 
RTDEF(PointerApplyMold)5976facde3SSlava Zakharin void RTDEF(PointerApplyMold)(
60696ad139SValentin Clement     Descriptor &pointer, const Descriptor &mold, int rank) {
61dffd93b3SPeter Klausler   pointer.ApplyMold(mold, rank);
62ad424cf1Speter klausler }
63ad424cf1Speter klausler 
RTDEF(PointerAssociateScalar)6476facde3SSlava Zakharin void RTDEF(PointerAssociateScalar)(Descriptor &pointer, void *target) {
65ad424cf1Speter klausler   pointer.set_base_addr(target);
66ad424cf1Speter klausler }
67ad424cf1Speter klausler 
RTDEF(PointerAssociate)6876facde3SSlava Zakharin void RTDEF(PointerAssociate)(Descriptor &pointer, const Descriptor &target) {
69ad424cf1Speter klausler   pointer = target;
70ad424cf1Speter klausler   pointer.raw().attribute = CFI_attribute_pointer;
71ad424cf1Speter klausler }
72ad424cf1Speter klausler 
RTDEF(PointerAssociateLowerBounds)7376facde3SSlava Zakharin void RTDEF(PointerAssociateLowerBounds)(Descriptor &pointer,
74ad424cf1Speter klausler     const Descriptor &target, const Descriptor &lowerBounds) {
75ad424cf1Speter klausler   pointer = target;
76ad424cf1Speter klausler   pointer.raw().attribute = CFI_attribute_pointer;
77ad424cf1Speter klausler   int rank{pointer.rank()};
78ad424cf1Speter klausler   Terminator terminator{__FILE__, __LINE__};
79ad424cf1Speter klausler   std::size_t boundElementBytes{lowerBounds.ElementBytes()};
80ad424cf1Speter klausler   for (int j{0}; j < rank; ++j) {
813b61587cSPeter Klausler     Dimension &dim{pointer.GetDimension(j)};
823b61587cSPeter Klausler     dim.SetLowerBound(dim.Extent() == 0
833b61587cSPeter Klausler             ? 1
843b61587cSPeter Klausler             : GetInt64(lowerBounds.ZeroBasedIndexedElement<const char>(j),
85ad424cf1Speter klausler                   boundElementBytes, terminator));
86ad424cf1Speter klausler   }
87ad424cf1Speter klausler }
88ad424cf1Speter klausler 
RTDEF(PointerAssociateRemapping)8976facde3SSlava Zakharin void RTDEF(PointerAssociateRemapping)(Descriptor &pointer,
90ad424cf1Speter klausler     const Descriptor &target, const Descriptor &bounds, const char *sourceFile,
91ad424cf1Speter klausler     int sourceLine) {
92ad424cf1Speter klausler   pointer = target;
93ad424cf1Speter klausler   pointer.raw().attribute = CFI_attribute_pointer;
94ad424cf1Speter klausler   Terminator terminator{sourceFile, sourceLine};
95ad424cf1Speter klausler   SubscriptValue byteStride{/*captured from first dimension*/};
96ad424cf1Speter klausler   std::size_t boundElementBytes{bounds.ElementBytes()};
9791ee72d1SValentin Clement   std::size_t boundsRank{
9891ee72d1SValentin Clement       static_cast<std::size_t>(bounds.GetDimension(1).Extent())};
9991ee72d1SValentin Clement   pointer.raw().rank = boundsRank;
100ff0ca64eSValentin Clement   for (unsigned j{0}; j < boundsRank; ++j) {
101ad424cf1Speter klausler     auto &dim{pointer.GetDimension(j)};
102ad424cf1Speter klausler     dim.SetBounds(GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j),
103ad424cf1Speter klausler                       boundElementBytes, terminator),
104ad424cf1Speter klausler         GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j + 1),
105ad424cf1Speter klausler             boundElementBytes, terminator));
106ad424cf1Speter klausler     if (j == 0) {
1076a63e21cSValentin Clement       byteStride = dim.ByteStride() * dim.Extent();
108ad424cf1Speter klausler     } else {
109ad424cf1Speter klausler       dim.SetByteStride(byteStride);
110ad424cf1Speter klausler       byteStride *= dim.Extent();
111ad424cf1Speter klausler     }
112ad424cf1Speter klausler   }
113ad424cf1Speter klausler   if (pointer.Elements() > target.Elements()) {
114ad424cf1Speter klausler     terminator.Crash("PointerAssociateRemapping: too many elements in remapped "
115ad424cf1Speter klausler                      "pointer (%zd > %zd)",
116ad424cf1Speter klausler         pointer.Elements(), target.Elements());
117ad424cf1Speter klausler   }
118ac84bc3cSValentin Clement   if (auto *pointerAddendum{pointer.Addendum()}) {
119ac84bc3cSValentin Clement     if (const auto *targetAddendum{target.Addendum()}) {
120ac84bc3cSValentin Clement       if (const auto *derived{targetAddendum->derivedType()}) {
121ac84bc3cSValentin Clement         pointerAddendum->set_derivedType(derived);
122ac84bc3cSValentin Clement       }
123ac84bc3cSValentin Clement     }
124ac84bc3cSValentin Clement   }
125ad424cf1Speter klausler }
126ad424cf1Speter klausler 
AllocateValidatedPointerPayload(std::size_t byteSize)127514c1ec5SPeter Klausler RT_API_ATTRS void *AllocateValidatedPointerPayload(std::size_t byteSize) {
128514c1ec5SPeter Klausler   // Add space for a footer to validate during deallocation.
129514c1ec5SPeter Klausler   constexpr std::size_t align{sizeof(std::uintptr_t)};
130*084d9436SPeter Klausler   byteSize = ((byteSize + align - 1) / align) * align;
131514c1ec5SPeter Klausler   std::size_t total{byteSize + sizeof(std::uintptr_t)};
132514c1ec5SPeter Klausler   void *p{std::malloc(total)};
133514c1ec5SPeter Klausler   if (p) {
134514c1ec5SPeter Klausler     // Fill the footer word with the XOR of the ones' complement of
135514c1ec5SPeter Klausler     // the base address, which is a value that would be highly unlikely
136514c1ec5SPeter Klausler     // to appear accidentally at the right spot.
137514c1ec5SPeter Klausler     std::uintptr_t *footer{
138514c1ec5SPeter Klausler         reinterpret_cast<std::uintptr_t *>(static_cast<char *>(p) + byteSize)};
139514c1ec5SPeter Klausler     *footer = ~reinterpret_cast<std::uintptr_t>(p);
140514c1ec5SPeter Klausler   }
141514c1ec5SPeter Klausler   return p;
142514c1ec5SPeter Klausler }
143514c1ec5SPeter Klausler 
RTDEF(PointerAllocate)14476facde3SSlava Zakharin int RTDEF(PointerAllocate)(Descriptor &pointer, bool hasStat,
145ad424cf1Speter klausler     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
146ad424cf1Speter klausler   Terminator terminator{sourceFile, sourceLine};
147ad424cf1Speter klausler   if (!pointer.IsPointer()) {
148ad424cf1Speter klausler     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
149ad424cf1Speter klausler   }
150a3bbe627SPeter Klausler   std::size_t elementBytes{pointer.ElementBytes()};
151a3bbe627SPeter Klausler   if (static_cast<std::int64_t>(elementBytes) < 0) {
152a3bbe627SPeter Klausler     // F'2023 7.4.4.2 p5: "If the character length parameter value evaluates
153a3bbe627SPeter Klausler     // to a negative value, the length of character entities declared is zero."
154a3bbe627SPeter Klausler     elementBytes = pointer.raw().elem_len = 0;
155a3bbe627SPeter Klausler   }
156a3bbe627SPeter Klausler   std::size_t byteSize{pointer.Elements() * elementBytes};
157514c1ec5SPeter Klausler   void *p{AllocateValidatedPointerPayload(byteSize)};
158a3bbe627SPeter Klausler   if (!p) {
159a3bbe627SPeter Klausler     return ReturnError(terminator, CFI_ERROR_MEM_ALLOCATION, errMsg, hasStat);
160a3bbe627SPeter Klausler   }
161a3bbe627SPeter Klausler   pointer.set_base_addr(p);
162a3bbe627SPeter Klausler   pointer.SetByteStrides();
163a3bbe627SPeter Klausler   int stat{StatOk};
164a48e4168Speter klausler   if (const DescriptorAddendum * addendum{pointer.Addendum()}) {
165a48e4168Speter klausler     if (const auto *derived{addendum->derivedType()}) {
166a48e4168Speter klausler       if (!derived->noInitializationNeeded()) {
167a48e4168Speter klausler         stat = Initialize(pointer, *derived, terminator, hasStat, errMsg);
168a48e4168Speter klausler       }
169a48e4168Speter klausler     }
170a48e4168Speter klausler   }
171a3bbe627SPeter Klausler   return ReturnError(terminator, stat, errMsg, hasStat);
172ad424cf1Speter klausler }
173ad424cf1Speter klausler 
RTDEF(PointerAllocateSource)17476facde3SSlava Zakharin int RTDEF(PointerAllocateSource)(Descriptor &pointer, const Descriptor &source,
1758c77c011SPeixin Qiao     bool hasStat, const Descriptor *errMsg, const char *sourceFile,
1768c77c011SPeixin Qiao     int sourceLine) {
1778c77c011SPeixin Qiao   int stat{RTNAME(PointerAllocate)(
1788c77c011SPeixin Qiao       pointer, hasStat, errMsg, sourceFile, sourceLine)};
1798c77c011SPeixin Qiao   if (stat == StatOk) {
1808c77c011SPeixin Qiao     Terminator terminator{sourceFile, sourceLine};
181f783c9bbSPeixin Qiao     DoFromSourceAssign(pointer, source, terminator);
1828c77c011SPeixin Qiao   }
1838c77c011SPeixin Qiao   return stat;
1848c77c011SPeixin Qiao }
1858c77c011SPeixin Qiao 
GetByteSize(const ISO::CFI_cdesc_t & descriptor)186514c1ec5SPeter Klausler static RT_API_ATTRS std::size_t GetByteSize(
187514c1ec5SPeter Klausler     const ISO::CFI_cdesc_t &descriptor) {
188514c1ec5SPeter Klausler   std::size_t rank{descriptor.rank};
189514c1ec5SPeter Klausler   const ISO::CFI_dim_t *dim{descriptor.dim};
190514c1ec5SPeter Klausler   std::size_t byteSize{descriptor.elem_len};
191514c1ec5SPeter Klausler   for (std::size_t j{0}; j < rank; ++j) {
192514c1ec5SPeter Klausler     byteSize *= dim[j].extent;
193514c1ec5SPeter Klausler   }
194514c1ec5SPeter Klausler   return byteSize;
195514c1ec5SPeter Klausler }
196514c1ec5SPeter Klausler 
ValidatePointerPayload(const ISO::CFI_cdesc_t & desc)197514c1ec5SPeter Klausler bool RT_API_ATTRS ValidatePointerPayload(const ISO::CFI_cdesc_t &desc) {
198514c1ec5SPeter Klausler   std::size_t byteSize{GetByteSize(desc)};
199514c1ec5SPeter Klausler   constexpr std::size_t align{sizeof(std::uintptr_t)};
200*084d9436SPeter Klausler   byteSize = ((byteSize + align - 1) / align) * align;
201514c1ec5SPeter Klausler   const void *p{desc.base_addr};
202514c1ec5SPeter Klausler   const std::uintptr_t *footer{reinterpret_cast<const std::uintptr_t *>(
203514c1ec5SPeter Klausler       static_cast<const char *>(p) + byteSize)};
204514c1ec5SPeter Klausler   return *footer == ~reinterpret_cast<std::uintptr_t>(p);
205514c1ec5SPeter Klausler }
206514c1ec5SPeter Klausler 
RTDEF(PointerDeallocate)20776facde3SSlava Zakharin int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat,
208ad424cf1Speter klausler     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
209ad424cf1Speter klausler   Terminator terminator{sourceFile, sourceLine};
210ad424cf1Speter klausler   if (!pointer.IsPointer()) {
211ad424cf1Speter klausler     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
212ad424cf1Speter klausler   }
213ad424cf1Speter klausler   if (!pointer.IsAllocated()) {
214ad424cf1Speter klausler     return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
215ad424cf1Speter klausler   }
216514c1ec5SPeter Klausler   if (executionEnvironment.checkPointerDeallocation &&
217514c1ec5SPeter Klausler       !ValidatePointerPayload(pointer.raw())) {
218514c1ec5SPeter Klausler     return ReturnError(terminator, StatBadPointerDeallocation, errMsg, hasStat);
219a3bbe627SPeter Klausler   }
220b21c24c3SPeter Klausler   return ReturnError(terminator,
221b21c24c3SPeter Klausler       pointer.Destroy(/*finalize=*/true, /*destroyPointers=*/true, &terminator),
222b21c24c3SPeter Klausler       errMsg, hasStat);
223ad424cf1Speter klausler }
224ad424cf1Speter klausler 
RTDEF(PointerDeallocatePolymorphic)22576facde3SSlava Zakharin int RTDEF(PointerDeallocatePolymorphic)(Descriptor &pointer,
22601e8e50cSValentin Clement     const typeInfo::DerivedType *derivedType, bool hasStat,
22701e8e50cSValentin Clement     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
22801e8e50cSValentin Clement   int stat{RTNAME(PointerDeallocate)(
22901e8e50cSValentin Clement       pointer, hasStat, errMsg, sourceFile, sourceLine)};
23001e8e50cSValentin Clement   if (stat == StatOk) {
231dffd93b3SPeter Klausler     if (DescriptorAddendum * addendum{pointer.Addendum()}) {
23201e8e50cSValentin Clement       addendum->set_derivedType(derivedType);
233dffd93b3SPeter Klausler       pointer.raw().type = derivedType ? CFI_type_struct : CFI_type_other;
2349ae4e1aeSValentin Clement     } else {
2359ae4e1aeSValentin Clement       // Unlimited polymorphic descriptors initialized with
2369ae4e1aeSValentin Clement       // PointerNullifyIntrinsic do not have an addendum. Make sure the
2379ae4e1aeSValentin Clement       // derivedType is null in that case.
2389ae4e1aeSValentin Clement       INTERNAL_CHECK(!derivedType);
239dffd93b3SPeter Klausler       pointer.raw().type = CFI_type_other;
2409ae4e1aeSValentin Clement     }
24101e8e50cSValentin Clement   }
24201e8e50cSValentin Clement   return stat;
24301e8e50cSValentin Clement }
24401e8e50cSValentin Clement 
RTDEF(PointerIsAssociated)24576facde3SSlava Zakharin bool RTDEF(PointerIsAssociated)(const Descriptor &pointer) {
246ad424cf1Speter klausler   return pointer.raw().base_addr != nullptr;
247ad424cf1Speter klausler }
248ad424cf1Speter klausler 
RTDEF(PointerIsAssociatedWith)24976facde3SSlava Zakharin bool RTDEF(PointerIsAssociatedWith)(
250392cba86SJean Perier     const Descriptor &pointer, const Descriptor *target) {
251392cba86SJean Perier   if (!target) {
252392cba86SJean Perier     return pointer.raw().base_addr != nullptr;
253392cba86SJean Perier   }
254a29d7463SValentin Clement   if (!target->raw().base_addr ||
255a29d7463SValentin Clement       (target->raw().type != CFI_type_struct && target->ElementBytes() == 0)) {
256392cba86SJean Perier     return false;
257392cba86SJean Perier   }
258ad424cf1Speter klausler   int rank{pointer.rank()};
259392cba86SJean Perier   if (pointer.raw().base_addr != target->raw().base_addr ||
260392cba86SJean Perier       pointer.ElementBytes() != target->ElementBytes() ||
261392cba86SJean Perier       rank != target->rank()) {
262ad424cf1Speter klausler     return false;
263ad424cf1Speter klausler   }
264ad424cf1Speter klausler   for (int j{0}; j < rank; ++j) {
265ad424cf1Speter klausler     const Dimension &pDim{pointer.GetDimension(j)};
266392cba86SJean Perier     const Dimension &tDim{target->GetDimension(j)};
267e0e2a117SPeter Klausler     auto pExtent{pDim.Extent()};
268e0e2a117SPeter Klausler     if (pExtent == 0 || pExtent != tDim.Extent() ||
269e0e2a117SPeter Klausler         (pExtent != 1 && pDim.ByteStride() != tDim.ByteStride())) {
270ad424cf1Speter klausler       return false;
271ad424cf1Speter klausler     }
272ad424cf1Speter klausler   }
273ad424cf1Speter klausler   return true;
274ad424cf1Speter klausler }
275ad424cf1Speter klausler 
2768c77c011SPeixin Qiao // TODO: PointerCheckLengthParameter
277ad424cf1Speter klausler 
27876facde3SSlava Zakharin RT_EXT_API_GROUP_END
279ad424cf1Speter klausler } // extern "C"
280ad424cf1Speter klausler } // namespace Fortran::runtime
281