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