1 //===-- runtime/pointer.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 "flang/Runtime/pointer.h"
10 #include "derived.h"
11 #include "stat.h"
12 #include "terminator.h"
13 #include "tools.h"
14 #include "type-info.h"
15 
16 namespace Fortran::runtime {
17 extern "C" {
18 
RTNAME(PointerNullifyIntrinsic)19 void RTNAME(PointerNullifyIntrinsic)(Descriptor &pointer, TypeCategory category,
20     int kind, int rank, int corank) {
21   INTERNAL_CHECK(corank == 0);
22   pointer.Establish(TypeCode{category, kind},
23       Descriptor::BytesFor(category, kind), nullptr, rank, nullptr,
24       CFI_attribute_pointer);
25 }
26 
RTNAME(PointerNullifyCharacter)27 void RTNAME(PointerNullifyCharacter)(Descriptor &pointer, SubscriptValue length,
28     int kind, int rank, int corank) {
29   INTERNAL_CHECK(corank == 0);
30   pointer.Establish(
31       kind, length, nullptr, rank, nullptr, CFI_attribute_pointer);
32 }
33 
RTNAME(PointerNullifyDerived)34 void RTNAME(PointerNullifyDerived)(Descriptor &pointer,
35     const typeInfo::DerivedType &derivedType, int rank, int corank) {
36   INTERNAL_CHECK(corank == 0);
37   pointer.Establish(derivedType, nullptr, rank, nullptr, CFI_attribute_pointer);
38 }
39 
RTNAME(PointerSetBounds)40 void RTNAME(PointerSetBounds)(Descriptor &pointer, int zeroBasedDim,
41     SubscriptValue lower, SubscriptValue upper) {
42   INTERNAL_CHECK(zeroBasedDim >= 0 && zeroBasedDim < pointer.rank());
43   pointer.GetDimension(zeroBasedDim).SetBounds(lower, upper);
44   // The byte strides are computed when the pointer is allocated.
45 }
46 
47 // TODO: PointerSetCoBounds
48 
RTNAME(PointerSetDerivedLength)49 void RTNAME(PointerSetDerivedLength)(
50     Descriptor &pointer, int which, SubscriptValue x) {
51   DescriptorAddendum *addendum{pointer.Addendum()};
52   INTERNAL_CHECK(addendum != nullptr);
53   addendum->SetLenParameterValue(which, x);
54 }
55 
RTNAME(PointerApplyMold)56 void RTNAME(PointerApplyMold)(Descriptor &pointer, const Descriptor &mold) {
57   pointer = mold;
58   pointer.set_base_addr(nullptr);
59   pointer.raw().attribute = CFI_attribute_pointer;
60 }
61 
RTNAME(PointerAssociateScalar)62 void RTNAME(PointerAssociateScalar)(Descriptor &pointer, void *target) {
63   pointer.set_base_addr(target);
64 }
65 
RTNAME(PointerAssociate)66 void RTNAME(PointerAssociate)(Descriptor &pointer, const Descriptor &target) {
67   pointer = target;
68   pointer.raw().attribute = CFI_attribute_pointer;
69 }
70 
RTNAME(PointerAssociateLowerBounds)71 void RTNAME(PointerAssociateLowerBounds)(Descriptor &pointer,
72     const Descriptor &target, const Descriptor &lowerBounds) {
73   pointer = target;
74   pointer.raw().attribute = CFI_attribute_pointer;
75   int rank{pointer.rank()};
76   Terminator terminator{__FILE__, __LINE__};
77   std::size_t boundElementBytes{lowerBounds.ElementBytes()};
78   for (int j{0}; j < rank; ++j) {
79     Dimension &dim{pointer.GetDimension(j)};
80     dim.SetLowerBound(dim.Extent() == 0
81             ? 1
82             : GetInt64(lowerBounds.ZeroBasedIndexedElement<const char>(j),
83                   boundElementBytes, terminator));
84   }
85 }
86 
RTNAME(PointerAssociateRemapping)87 void RTNAME(PointerAssociateRemapping)(Descriptor &pointer,
88     const Descriptor &target, const Descriptor &bounds, const char *sourceFile,
89     int sourceLine) {
90   pointer = target;
91   pointer.raw().attribute = CFI_attribute_pointer;
92   int rank{pointer.rank()};
93   Terminator terminator{sourceFile, sourceLine};
94   SubscriptValue byteStride{/*captured from first dimension*/};
95   std::size_t boundElementBytes{bounds.ElementBytes()};
96   for (int j{0}; j < rank; ++j) {
97     auto &dim{pointer.GetDimension(j)};
98     dim.SetBounds(GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j),
99                       boundElementBytes, terminator),
100         GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j + 1),
101             boundElementBytes, terminator));
102     if (j == 0) {
103       byteStride = dim.ByteStride();
104     } else {
105       dim.SetByteStride(byteStride);
106       byteStride *= dim.Extent();
107     }
108   }
109   if (pointer.Elements() > target.Elements()) {
110     terminator.Crash("PointerAssociateRemapping: too many elements in remapped "
111                      "pointer (%zd > %zd)",
112         pointer.Elements(), target.Elements());
113   }
114 }
115 
RTNAME(PointerAllocate)116 int RTNAME(PointerAllocate)(Descriptor &pointer, bool hasStat,
117     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
118   Terminator terminator{sourceFile, sourceLine};
119   if (!pointer.IsPointer()) {
120     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
121   }
122   int stat{ReturnError(terminator, pointer.Allocate(), errMsg, hasStat)};
123   if (stat == StatOk) {
124     if (const DescriptorAddendum * addendum{pointer.Addendum()}) {
125       if (const auto *derived{addendum->derivedType()}) {
126         if (!derived->noInitializationNeeded()) {
127           stat = Initialize(pointer, *derived, terminator, hasStat, errMsg);
128         }
129       }
130     }
131   }
132   return stat;
133 }
134 
RTNAME(PointerDeallocate)135 int RTNAME(PointerDeallocate)(Descriptor &pointer, bool hasStat,
136     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
137   Terminator terminator{sourceFile, sourceLine};
138   if (!pointer.IsPointer()) {
139     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
140   }
141   if (!pointer.IsAllocated()) {
142     return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
143   }
144   return ReturnError(terminator, pointer.Destroy(true, true), errMsg, hasStat);
145 }
146 
RTNAME(PointerIsAssociated)147 bool RTNAME(PointerIsAssociated)(const Descriptor &pointer) {
148   return pointer.raw().base_addr != nullptr;
149 }
150 
RTNAME(PointerIsAssociatedWith)151 bool RTNAME(PointerIsAssociatedWith)(
152     const Descriptor &pointer, const Descriptor *target) {
153   if (!target) {
154     return pointer.raw().base_addr != nullptr;
155   }
156   if (!target->raw().base_addr || target->ElementBytes() == 0) {
157     return false;
158   }
159   int rank{pointer.rank()};
160   if (pointer.raw().base_addr != target->raw().base_addr ||
161       pointer.ElementBytes() != target->ElementBytes() ||
162       rank != target->rank()) {
163     return false;
164   }
165   for (int j{0}; j < rank; ++j) {
166     const Dimension &pDim{pointer.GetDimension(j)};
167     const Dimension &tDim{target->GetDimension(j)};
168     auto pExtent{pDim.Extent()};
169     if (pExtent == 0 || pExtent != tDim.Extent() ||
170         (pExtent != 1 && pDim.ByteStride() != tDim.ByteStride())) {
171       return false;
172     }
173   }
174   return true;
175 }
176 
177 // TODO: PointerCheckLengthParameter, PointerAllocateSource
178 
179 } // extern "C"
180 } // namespace Fortran::runtime
181