1 //===-- runtime/descriptor.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 "descriptor.h"
10 #include "derived.h"
11 #include "memory.h"
12 #include "terminator.h"
13 #include "type-info.h"
14 #include <cassert>
15 #include <cstdlib>
16 #include <cstring>
17 
18 namespace Fortran::runtime {
19 
Descriptor(const Descriptor & that)20 Descriptor::Descriptor(const Descriptor &that) {
21   std::memcpy(this, &that, that.SizeInBytes());
22 }
23 
~Descriptor()24 Descriptor::~Descriptor() {
25   if (raw_.attribute != CFI_attribute_pointer) {
26     Deallocate();
27   }
28 }
29 
Establish(TypeCode t,std::size_t elementBytes,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute,bool addendum)30 void Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p,
31     int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
32     bool addendum) {
33   Terminator terminator{__FILE__, __LINE__};
34   RUNTIME_CHECK(terminator,
35       ISO::CFI_establish(&raw_, p, attribute, t.raw(), elementBytes, rank,
36           extent) == CFI_SUCCESS);
37   raw_.f18Addendum = addendum;
38   DescriptorAddendum *a{Addendum()};
39   RUNTIME_CHECK(terminator, addendum == (a != nullptr));
40   if (a) {
41     new (a) DescriptorAddendum{};
42   }
43 }
44 
Establish(TypeCategory c,int kind,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute,bool addendum)45 void Descriptor::Establish(TypeCategory c, int kind, void *p, int rank,
46     const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
47     bool addendum) {
48   Establish(TypeCode(c, kind), BytesFor(c, kind), p, rank, extent, attribute,
49       addendum);
50 }
51 
Establish(int characterKind,std::size_t characters,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute,bool addendum)52 void Descriptor::Establish(int characterKind, std::size_t characters, void *p,
53     int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute,
54     bool addendum) {
55   Establish(TypeCode{TypeCategory::Character, characterKind},
56       characterKind * characters, p, rank, extent, attribute, addendum);
57 }
58 
Establish(const typeInfo::DerivedType & dt,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute)59 void Descriptor::Establish(const typeInfo::DerivedType &dt, void *p, int rank,
60     const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
61   Establish(CFI_type_struct, dt.sizeInBytes, p, rank, extent, attribute, true);
62   DescriptorAddendum *a{Addendum()};
63   Terminator terminator{__FILE__, __LINE__};
64   RUNTIME_CHECK(terminator, a != nullptr);
65   new (a) DescriptorAddendum{&dt};
66 }
67 
Create(TypeCode t,std::size_t elementBytes,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute,int derivedTypeLenParameters)68 OwningPtr<Descriptor> Descriptor::Create(TypeCode t, std::size_t elementBytes,
69     void *p, int rank, const SubscriptValue *extent,
70     ISO::CFI_attribute_t attribute, int derivedTypeLenParameters) {
71   std::size_t bytes{SizeInBytes(rank, true, derivedTypeLenParameters)};
72   Terminator terminator{__FILE__, __LINE__};
73   Descriptor *result{
74       reinterpret_cast<Descriptor *>(AllocateMemoryOrCrash(terminator, bytes))};
75   result->Establish(t, elementBytes, p, rank, extent, attribute, true);
76   return OwningPtr<Descriptor>{result};
77 }
78 
Create(TypeCategory c,int kind,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute)79 OwningPtr<Descriptor> Descriptor::Create(TypeCategory c, int kind, void *p,
80     int rank, const SubscriptValue *extent, ISO::CFI_attribute_t attribute) {
81   return Create(
82       TypeCode(c, kind), BytesFor(c, kind), p, rank, extent, attribute);
83 }
84 
Create(int characterKind,SubscriptValue characters,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute)85 OwningPtr<Descriptor> Descriptor::Create(int characterKind,
86     SubscriptValue characters, void *p, int rank, const SubscriptValue *extent,
87     ISO::CFI_attribute_t attribute) {
88   return Create(TypeCode{TypeCategory::Character, characterKind},
89       characterKind * characters, p, rank, extent, attribute);
90 }
91 
Create(const typeInfo::DerivedType & dt,void * p,int rank,const SubscriptValue * extent,ISO::CFI_attribute_t attribute)92 OwningPtr<Descriptor> Descriptor::Create(const typeInfo::DerivedType &dt,
93     void *p, int rank, const SubscriptValue *extent,
94     ISO::CFI_attribute_t attribute) {
95   return Create(TypeCode{CFI_type_struct}, dt.sizeInBytes, p, rank, extent,
96       attribute, dt.LenParameters());
97 }
98 
SizeInBytes() const99 std::size_t Descriptor::SizeInBytes() const {
100   const DescriptorAddendum *addendum{Addendum()};
101   return sizeof *this - sizeof(Dimension) + raw_.rank * sizeof(Dimension) +
102       (addendum ? addendum->SizeInBytes() : 0);
103 }
104 
Elements() const105 std::size_t Descriptor::Elements() const {
106   int n{rank()};
107   std::size_t elements{1};
108   for (int j{0}; j < n; ++j) {
109     elements *= GetDimension(j).Extent();
110   }
111   return elements;
112 }
113 
Allocate()114 int Descriptor::Allocate() {
115   std::size_t byteSize{Elements() * ElementBytes()};
116   void *p{std::malloc(byteSize)};
117   if (!p && byteSize) {
118     return CFI_ERROR_MEM_ALLOCATION;
119   }
120   // TODO: image synchronization
121   // TODO: derived type initialization
122   raw_.base_addr = p;
123   if (int dims{rank()}) {
124     std::size_t stride{ElementBytes()};
125     for (int j{0}; j < dims; ++j) {
126       auto &dimension{GetDimension(j)};
127       dimension.SetByteStride(stride);
128       stride *= dimension.Extent();
129     }
130   }
131   return 0;
132 }
133 
Allocate(const SubscriptValue lb[],const SubscriptValue ub[])134 int Descriptor::Allocate(const SubscriptValue lb[], const SubscriptValue ub[]) {
135   int result{ISO::CFI_allocate(&raw_, lb, ub, ElementBytes())};
136   if (result == CFI_SUCCESS) {
137     // TODO: derived type initialization
138   }
139   return result;
140 }
141 
Deallocate(bool finalize)142 int Descriptor::Deallocate(bool finalize) {
143   Destroy(finalize);
144   return ISO::CFI_deallocate(&raw_);
145 }
146 
Destroy(bool finalize) const147 void Descriptor::Destroy(bool finalize) const {
148   if (const DescriptorAddendum * addendum{Addendum()}) {
149     if (const typeInfo::DerivedType * dt{addendum->derivedType()}) {
150       if (addendum->flags() & DescriptorAddendum::DoNotFinalize) {
151         finalize = false;
152       }
153       runtime::Destroy(*this, finalize, *dt);
154     }
155   }
156 }
157 
IncrementSubscripts(SubscriptValue * subscript,const int * permutation) const158 bool Descriptor::IncrementSubscripts(
159     SubscriptValue *subscript, const int *permutation) const {
160   for (int j{0}; j < raw_.rank; ++j) {
161     int k{permutation ? permutation[j] : j};
162     const Dimension &dim{GetDimension(k)};
163     if (subscript[k]++ < dim.UpperBound()) {
164       return true;
165     }
166     subscript[k] = dim.LowerBound();
167   }
168   return false;
169 }
170 
DecrementSubscripts(SubscriptValue * subscript,const int * permutation) const171 bool Descriptor::DecrementSubscripts(
172     SubscriptValue *subscript, const int *permutation) const {
173   for (int j{raw_.rank - 1}; j >= 0; --j) {
174     int k{permutation ? permutation[j] : j};
175     const Dimension &dim{GetDimension(k)};
176     if (--subscript[k] >= dim.LowerBound()) {
177       return true;
178     }
179     subscript[k] = dim.UpperBound();
180   }
181   return false;
182 }
183 
ZeroBasedElementNumber(const SubscriptValue * subscript,const int * permutation) const184 std::size_t Descriptor::ZeroBasedElementNumber(
185     const SubscriptValue *subscript, const int *permutation) const {
186   std::size_t result{0};
187   std::size_t coefficient{1};
188   for (int j{0}; j < raw_.rank; ++j) {
189     int k{permutation ? permutation[j] : j};
190     const Dimension &dim{GetDimension(k)};
191     result += coefficient * (subscript[k] - dim.LowerBound());
192     coefficient *= dim.Extent();
193   }
194   return result;
195 }
196 
SubscriptsForZeroBasedElementNumber(SubscriptValue * subscript,std::size_t elementNumber,const int * permutation) const197 bool Descriptor::SubscriptsForZeroBasedElementNumber(SubscriptValue *subscript,
198     std::size_t elementNumber, const int *permutation) const {
199   std::size_t coefficient{1};
200   std::size_t dimCoefficient[maxRank];
201   for (int j{0}; j < raw_.rank; ++j) {
202     int k{permutation ? permutation[j] : j};
203     const Dimension &dim{GetDimension(k)};
204     dimCoefficient[j] = coefficient;
205     coefficient *= dim.Extent();
206   }
207   if (elementNumber >= coefficient) {
208     return false; // out of range
209   }
210   for (int j{raw_.rank - 1}; j >= 0; --j) {
211     int k{permutation ? permutation[j] : j};
212     const Dimension &dim{GetDimension(k)};
213     std::size_t quotient{j ? elementNumber / dimCoefficient[j] : 0};
214     subscript[k] =
215         dim.LowerBound() + elementNumber - dimCoefficient[j] * quotient;
216     elementNumber = quotient;
217   }
218   return true;
219 }
220 
Check() const221 void Descriptor::Check() const {
222   // TODO
223 }
224 
Dump(FILE * f) const225 void Descriptor::Dump(FILE *f) const {
226   std::fprintf(f, "Descriptor @ %p:\n", reinterpret_cast<const void *>(this));
227   std::fprintf(f, "  base_addr %p\n", raw_.base_addr);
228   std::fprintf(f, "  elem_len  %zd\n", static_cast<std::size_t>(raw_.elem_len));
229   std::fprintf(f, "  version   %d\n", static_cast<int>(raw_.version));
230   std::fprintf(f, "  rank      %d\n", static_cast<int>(raw_.rank));
231   std::fprintf(f, "  type      %d\n", static_cast<int>(raw_.type));
232   std::fprintf(f, "  attribute %d\n", static_cast<int>(raw_.attribute));
233   std::fprintf(f, "  addendum  %d\n", static_cast<int>(raw_.f18Addendum));
234   for (int j{0}; j < raw_.rank; ++j) {
235     std::fprintf(f, "  dim[%d] lower_bound %jd\n", j,
236         static_cast<std::intmax_t>(raw_.dim[j].lower_bound));
237     std::fprintf(f, "         extent      %jd\n",
238         static_cast<std::intmax_t>(raw_.dim[j].extent));
239     std::fprintf(f, "         sm          %jd\n",
240         static_cast<std::intmax_t>(raw_.dim[j].sm));
241   }
242   if (const DescriptorAddendum * addendum{Addendum()}) {
243     addendum->Dump(f);
244   }
245 }
246 
SizeInBytes() const247 std::size_t DescriptorAddendum::SizeInBytes() const {
248   return SizeInBytes(LenParameters());
249 }
250 
LenParameters() const251 std::size_t DescriptorAddendum::LenParameters() const {
252   const auto *type{derivedType()};
253   return type ? type->LenParameters() : 0;
254 }
255 
Dump(FILE * f) const256 void DescriptorAddendum::Dump(FILE *f) const {
257   std::fprintf(
258       f, "  derivedType @ %p\n", reinterpret_cast<const void *>(derivedType_));
259   std::fprintf(f, "  flags 0x%jx\n", static_cast<std::intmax_t>(flags_));
260   // TODO: LEN parameter values
261 }
262 } // namespace Fortran::runtime
263