1 //===-- runtime/descriptor.cpp --------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "flang/Runtime/descriptor.h"
10 #include "ISO_Fortran_util.h"
14 #include "terminator.h"
16 #include "type-info.h"
21 namespace Fortran::runtime
{
23 RT_OFFLOAD_API_GROUP_BEGIN
25 RT_API_ATTRS
Descriptor::Descriptor(const Descriptor
&that
) { *this = that
; }
27 RT_API_ATTRS Descriptor
&Descriptor::operator=(const Descriptor
&that
) {
28 std::memcpy(this, &that
, that
.SizeInBytes());
32 RT_API_ATTRS
void Descriptor::Establish(TypeCode t
, std::size_t elementBytes
,
33 void *p
, int rank
, const SubscriptValue
*extent
,
34 ISO::CFI_attribute_t attribute
, bool addendum
) {
35 Terminator terminator
{__FILE__
, __LINE__
};
36 int cfiStatus
{ISO::VerifyEstablishParameters(&raw_
, p
, attribute
, t
.raw(),
37 elementBytes
, rank
, extent
, /*external=*/false)};
38 if (cfiStatus
!= CFI_SUCCESS
) {
40 "Descriptor::Establish: CFI_establish returned %d for CFI_type_t(%d)",
43 ISO::EstablishDescriptor(
44 &raw_
, p
, attribute
, t
.raw(), elementBytes
, rank
, extent
);
45 if (elementBytes
== 0) {
47 // Reset byte strides of the dimensions, since EstablishDescriptor()
48 // only does that when the base address is not nullptr.
49 for (int j
{0}; j
< rank
; ++j
) {
50 GetDimension(j
).SetByteStride(0);
53 raw_
.f18Addendum
= addendum
;
54 DescriptorAddendum
*a
{Addendum()};
55 RUNTIME_CHECK(terminator
, addendum
== (a
!= nullptr));
57 new (a
) DescriptorAddendum
{};
62 template <TypeCategory CAT
, int KIND
> struct TypeSizeGetter
{
63 constexpr RT_API_ATTRS
std::size_t operator()() const {
64 CppTypeFor
<CAT
, KIND
> arr
[2];
65 return sizeof arr
/ 2;
70 RT_API_ATTRS
std::size_t Descriptor::BytesFor(TypeCategory category
, int kind
) {
71 Terminator terminator
{__FILE__
, __LINE__
};
72 return ApplyType
<TypeSizeGetter
, std::size_t>(category
, kind
, terminator
);
75 RT_API_ATTRS
void Descriptor::Establish(TypeCategory c
, int kind
, void *p
,
76 int rank
, const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
,
78 Establish(TypeCode(c
, kind
), BytesFor(c
, kind
), p
, rank
, extent
, attribute
,
82 RT_API_ATTRS
void Descriptor::Establish(int characterKind
,
83 std::size_t characters
, void *p
, int rank
, const SubscriptValue
*extent
,
84 ISO::CFI_attribute_t attribute
, bool addendum
) {
85 Establish(TypeCode
{TypeCategory::Character
, characterKind
},
86 characterKind
* characters
, p
, rank
, extent
, attribute
, addendum
);
89 RT_API_ATTRS
void Descriptor::Establish(const typeInfo::DerivedType
&dt
,
90 void *p
, int rank
, const SubscriptValue
*extent
,
91 ISO::CFI_attribute_t attribute
) {
92 Establish(TypeCode
{TypeCategory::Derived
, 0}, dt
.sizeInBytes(), p
, rank
,
93 extent
, attribute
, true);
94 DescriptorAddendum
*a
{Addendum()};
95 Terminator terminator
{__FILE__
, __LINE__
};
96 RUNTIME_CHECK(terminator
, a
!= nullptr);
97 new (a
) DescriptorAddendum
{&dt
};
100 RT_API_ATTRS OwningPtr
<Descriptor
> Descriptor::Create(TypeCode t
,
101 std::size_t elementBytes
, void *p
, int rank
, const SubscriptValue
*extent
,
102 ISO::CFI_attribute_t attribute
, bool addendum
,
103 const typeInfo::DerivedType
*dt
) {
104 Terminator terminator
{__FILE__
, __LINE__
};
105 RUNTIME_CHECK(terminator
, t
.IsDerived() == (dt
!= nullptr));
106 int derivedTypeLenParameters
= dt
? dt
->LenParameters() : 0;
107 std::size_t bytes
{SizeInBytes(rank
, addendum
, derivedTypeLenParameters
)};
109 reinterpret_cast<Descriptor
*>(AllocateMemoryOrCrash(terminator
, bytes
))};
111 result
->Establish(*dt
, p
, rank
, extent
, attribute
);
113 result
->Establish(t
, elementBytes
, p
, rank
, extent
, attribute
, addendum
);
115 return OwningPtr
<Descriptor
>{result
};
118 RT_API_ATTRS OwningPtr
<Descriptor
> Descriptor::Create(TypeCategory c
, int kind
,
119 void *p
, int rank
, const SubscriptValue
*extent
,
120 ISO::CFI_attribute_t attribute
) {
122 TypeCode(c
, kind
), BytesFor(c
, kind
), p
, rank
, extent
, attribute
);
125 RT_API_ATTRS OwningPtr
<Descriptor
> Descriptor::Create(int characterKind
,
126 SubscriptValue characters
, void *p
, int rank
, const SubscriptValue
*extent
,
127 ISO::CFI_attribute_t attribute
) {
128 return Create(TypeCode
{TypeCategory::Character
, characterKind
},
129 characterKind
* characters
, p
, rank
, extent
, attribute
);
132 RT_API_ATTRS OwningPtr
<Descriptor
> Descriptor::Create(
133 const typeInfo::DerivedType
&dt
, void *p
, int rank
,
134 const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
) {
135 return Create(TypeCode
{TypeCategory::Derived
, 0}, dt
.sizeInBytes(), p
, rank
,
136 extent
, attribute
, /*addendum=*/true, &dt
);
139 RT_API_ATTRS
std::size_t Descriptor::SizeInBytes() const {
140 const DescriptorAddendum
*addendum
{Addendum()};
141 return sizeof *this - sizeof(Dimension
) + raw_
.rank
* sizeof(Dimension
) +
142 (addendum
? addendum
->SizeInBytes() : 0);
145 RT_API_ATTRS
std::size_t Descriptor::Elements() const {
147 std::size_t elements
{1};
148 for (int j
{0}; j
< n
; ++j
) {
149 elements
*= GetDimension(j
).Extent();
154 RT_API_ATTRS
int Descriptor::Allocate() {
155 std::size_t byteSize
{Elements() * ElementBytes()};
156 // Zero size allocation is possible in Fortran and the resulting
157 // descriptor must be allocated/associated. Since std::malloc(0)
158 // result is implementation defined, always allocate at least one byte.
159 void *p
{byteSize
? std::malloc(byteSize
) : std::malloc(1)};
161 return CFI_ERROR_MEM_ALLOCATION
;
163 // TODO: image synchronization
165 if (int dims
{rank()}) {
166 std::size_t stride
{ElementBytes()};
167 for (int j
{0}; j
< dims
; ++j
) {
168 auto &dimension
{GetDimension(j
)};
169 dimension
.SetByteStride(stride
);
170 stride
*= dimension
.Extent();
176 RT_API_ATTRS
int Descriptor::Destroy(
177 bool finalize
, bool destroyPointers
, Terminator
*terminator
) {
178 if (!destroyPointers
&& raw_
.attribute
== CFI_attribute_pointer
) {
181 if (auto *addendum
{Addendum()}) {
182 if (const auto *derived
{addendum
->derivedType()}) {
183 if (!derived
->noDestructionNeeded()) {
184 runtime::Destroy(*this, finalize
, *derived
, terminator
);
192 RT_API_ATTRS
int Descriptor::Deallocate() { return ISO::CFI_deallocate(&raw_
); }
194 RT_API_ATTRS
bool Descriptor::DecrementSubscripts(
195 SubscriptValue
*subscript
, const int *permutation
) const {
196 for (int j
{raw_
.rank
- 1}; j
>= 0; --j
) {
197 int k
{permutation
? permutation
[j
] : j
};
198 const Dimension
&dim
{GetDimension(k
)};
199 if (--subscript
[k
] >= dim
.LowerBound()) {
202 subscript
[k
] = dim
.UpperBound();
207 RT_API_ATTRS
std::size_t Descriptor::ZeroBasedElementNumber(
208 const SubscriptValue
*subscript
, const int *permutation
) const {
209 std::size_t result
{0};
210 std::size_t coefficient
{1};
211 for (int j
{0}; j
< raw_
.rank
; ++j
) {
212 int k
{permutation
? permutation
[j
] : j
};
213 const Dimension
&dim
{GetDimension(k
)};
214 result
+= coefficient
* (subscript
[k
] - dim
.LowerBound());
215 coefficient
*= dim
.Extent();
220 RT_API_ATTRS
bool Descriptor::EstablishPointerSection(const Descriptor
&source
,
221 const SubscriptValue
*lower
, const SubscriptValue
*upper
,
222 const SubscriptValue
*stride
) {
224 raw_
.attribute
= CFI_attribute_pointer
;
225 int newRank
{raw_
.rank
};
226 for (int j
{0}; j
< raw_
.rank
; ++j
) {
227 if (!stride
|| stride
[j
] == 0) {
236 if (const auto *sourceAddendum
= source
.Addendum()) {
237 if (auto *addendum
{Addendum()}) {
238 *addendum
= *sourceAddendum
;
243 return CFI_section(&raw_
, &source
.raw_
, lower
, upper
, stride
) == CFI_SUCCESS
;
246 RT_API_ATTRS
void Descriptor::ApplyMold(const Descriptor
&mold
, int rank
) {
247 raw_
.elem_len
= mold
.raw_
.elem_len
;
249 raw_
.type
= mold
.raw_
.type
;
250 for (int j
{0}; j
< rank
&& j
< mold
.raw_
.rank
; ++j
) {
251 GetDimension(j
) = mold
.GetDimension(j
);
253 if (auto *addendum
{Addendum()}) {
254 if (auto *moldAddendum
{mold
.Addendum()}) {
255 *addendum
= *moldAddendum
;
257 INTERNAL_CHECK(!addendum
->derivedType());
262 RT_API_ATTRS
void Descriptor::Check() const {
266 void Descriptor::Dump(FILE *f
) const {
267 std::fprintf(f
, "Descriptor @ %p:\n", reinterpret_cast<const void *>(this));
268 std::fprintf(f
, " base_addr %p\n", raw_
.base_addr
);
269 std::fprintf(f
, " elem_len %zd\n", static_cast<std::size_t>(raw_
.elem_len
));
270 std::fprintf(f
, " version %d\n", static_cast<int>(raw_
.version
));
271 std::fprintf(f
, " rank %d\n", static_cast<int>(raw_
.rank
));
272 std::fprintf(f
, " type %d\n", static_cast<int>(raw_
.type
));
273 std::fprintf(f
, " attribute %d\n", static_cast<int>(raw_
.attribute
));
274 std::fprintf(f
, " addendum %d\n", static_cast<int>(raw_
.f18Addendum
));
275 for (int j
{0}; j
< raw_
.rank
; ++j
) {
276 std::fprintf(f
, " dim[%d] lower_bound %jd\n", j
,
277 static_cast<std::intmax_t>(raw_
.dim
[j
].lower_bound
));
278 std::fprintf(f
, " extent %jd\n",
279 static_cast<std::intmax_t>(raw_
.dim
[j
].extent
));
280 std::fprintf(f
, " sm %jd\n",
281 static_cast<std::intmax_t>(raw_
.dim
[j
].sm
));
283 if (const DescriptorAddendum
* addendum
{Addendum()}) {
288 RT_API_ATTRS DescriptorAddendum
&DescriptorAddendum::operator=(
289 const DescriptorAddendum
&that
) {
290 derivedType_
= that
.derivedType_
;
291 auto lenParms
{that
.LenParameters()};
292 for (std::size_t j
{0}; j
< lenParms
; ++j
) {
293 len_
[j
] = that
.len_
[j
];
298 RT_API_ATTRS
std::size_t DescriptorAddendum::SizeInBytes() const {
299 return SizeInBytes(LenParameters());
302 RT_API_ATTRS
std::size_t DescriptorAddendum::LenParameters() const {
303 const auto *type
{derivedType()};
304 return type
? type
->LenParameters() : 0;
307 void DescriptorAddendum::Dump(FILE *f
) const {
309 f
, " derivedType @ %p\n", reinterpret_cast<const void *>(derivedType()));
310 std::size_t lenParms
{LenParameters()};
311 for (std::size_t j
{0}; j
< lenParms
; ++j
) {
312 std::fprintf(f
, " len[%zd] %jd\n", j
, static_cast<std::intmax_t>(len_
[j
]));
316 RT_OFFLOAD_API_GROUP_END
318 } // namespace Fortran::runtime