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 Descriptor::Descriptor(const Descriptor
&that
) { *this = that
; }
25 Descriptor
&Descriptor::operator=(const Descriptor
&that
) {
26 std::memcpy(this, &that
, that
.SizeInBytes());
30 void Descriptor::Establish(TypeCode t
, std::size_t elementBytes
, void *p
,
31 int rank
, const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
,
33 Terminator terminator
{__FILE__
, __LINE__
};
34 int cfiStatus
{ISO::VerifyEstablishParameters(&raw_
, p
, attribute
, t
.raw(),
35 elementBytes
, rank
, extent
, /*external=*/false)};
36 if (cfiStatus
!= CFI_SUCCESS
) {
38 "Descriptor::Establish: CFI_establish returned %d for CFI_type_t(%d)",
41 ISO::EstablishDescriptor(
42 &raw_
, p
, attribute
, t
.raw(), elementBytes
, rank
, extent
);
43 if (elementBytes
== 0) {
45 // Reset byte strides of the dimensions, since EstablishDescriptor()
46 // only does that when the base address is not nullptr.
47 for (int j
{0}; j
< rank
; ++j
) {
48 GetDimension(j
).SetByteStride(0);
51 raw_
.f18Addendum
= addendum
;
52 DescriptorAddendum
*a
{Addendum()};
53 RUNTIME_CHECK(terminator
, addendum
== (a
!= nullptr));
55 new (a
) DescriptorAddendum
{};
60 template <TypeCategory CAT
, int KIND
> struct TypeSizeGetter
{
61 constexpr std::size_t operator()() const {
62 CppTypeFor
<CAT
, KIND
> arr
[2];
63 return sizeof arr
/ 2;
68 std::size_t Descriptor::BytesFor(TypeCategory category
, int kind
) {
69 Terminator terminator
{__FILE__
, __LINE__
};
70 return ApplyType
<TypeSizeGetter
, std::size_t>(category
, kind
, terminator
);
73 void Descriptor::Establish(TypeCategory c
, int kind
, void *p
, int rank
,
74 const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
,
76 Establish(TypeCode(c
, kind
), BytesFor(c
, kind
), p
, rank
, extent
, attribute
,
80 void Descriptor::Establish(int characterKind
, std::size_t characters
, void *p
,
81 int rank
, const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
,
83 Establish(TypeCode
{TypeCategory::Character
, characterKind
},
84 characterKind
* characters
, p
, rank
, extent
, attribute
, addendum
);
87 void Descriptor::Establish(const typeInfo::DerivedType
&dt
, void *p
, int rank
,
88 const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
) {
89 Establish(TypeCode
{TypeCategory::Derived
, 0}, dt
.sizeInBytes(), p
, rank
,
90 extent
, attribute
, true);
91 DescriptorAddendum
*a
{Addendum()};
92 Terminator terminator
{__FILE__
, __LINE__
};
93 RUNTIME_CHECK(terminator
, a
!= nullptr);
94 new (a
) DescriptorAddendum
{&dt
};
97 OwningPtr
<Descriptor
> Descriptor::Create(TypeCode t
, std::size_t elementBytes
,
98 void *p
, int rank
, const SubscriptValue
*extent
,
99 ISO::CFI_attribute_t attribute
, int derivedTypeLenParameters
) {
100 std::size_t bytes
{SizeInBytes(rank
, true, derivedTypeLenParameters
)};
101 Terminator terminator
{__FILE__
, __LINE__
};
103 reinterpret_cast<Descriptor
*>(AllocateMemoryOrCrash(terminator
, bytes
))};
104 result
->Establish(t
, elementBytes
, p
, rank
, extent
, attribute
, true);
105 return OwningPtr
<Descriptor
>{result
};
108 OwningPtr
<Descriptor
> Descriptor::Create(TypeCategory c
, int kind
, void *p
,
109 int rank
, const SubscriptValue
*extent
, ISO::CFI_attribute_t attribute
) {
111 TypeCode(c
, kind
), BytesFor(c
, kind
), p
, rank
, extent
, attribute
);
114 OwningPtr
<Descriptor
> Descriptor::Create(int characterKind
,
115 SubscriptValue characters
, void *p
, int rank
, const SubscriptValue
*extent
,
116 ISO::CFI_attribute_t attribute
) {
117 return Create(TypeCode
{TypeCategory::Character
, characterKind
},
118 characterKind
* characters
, p
, rank
, extent
, attribute
);
121 OwningPtr
<Descriptor
> Descriptor::Create(const typeInfo::DerivedType
&dt
,
122 void *p
, int rank
, const SubscriptValue
*extent
,
123 ISO::CFI_attribute_t attribute
) {
124 return Create(TypeCode
{TypeCategory::Derived
, 0}, dt
.sizeInBytes(), p
, rank
,
125 extent
, attribute
, dt
.LenParameters());
128 std::size_t Descriptor::SizeInBytes() const {
129 const DescriptorAddendum
*addendum
{Addendum()};
130 return sizeof *this - sizeof(Dimension
) + raw_
.rank
* sizeof(Dimension
) +
131 (addendum
? addendum
->SizeInBytes() : 0);
134 std::size_t Descriptor::Elements() const {
136 std::size_t elements
{1};
137 for (int j
{0}; j
< n
; ++j
) {
138 elements
*= GetDimension(j
).Extent();
143 int Descriptor::Allocate() {
144 std::size_t byteSize
{Elements() * ElementBytes()};
145 void *p
{std::malloc(byteSize
)};
146 if (!p
&& byteSize
) {
147 return CFI_ERROR_MEM_ALLOCATION
;
149 // TODO: image synchronization
151 if (int dims
{rank()}) {
152 std::size_t stride
{ElementBytes()};
153 for (int j
{0}; j
< dims
; ++j
) {
154 auto &dimension
{GetDimension(j
)};
155 dimension
.SetByteStride(stride
);
156 stride
*= dimension
.Extent();
162 int Descriptor::Destroy(bool finalize
, bool destroyPointers
) {
163 if (!destroyPointers
&& raw_
.attribute
== CFI_attribute_pointer
) {
166 if (auto *addendum
{Addendum()}) {
167 if (const auto *derived
{addendum
->derivedType()}) {
168 if (!derived
->noDestructionNeeded()) {
169 runtime::Destroy(*this, finalize
, *derived
);
177 int Descriptor::Deallocate() { return ISO::CFI_deallocate(&raw_
); }
179 bool Descriptor::DecrementSubscripts(
180 SubscriptValue
*subscript
, const int *permutation
) const {
181 for (int j
{raw_
.rank
- 1}; j
>= 0; --j
) {
182 int k
{permutation
? permutation
[j
] : j
};
183 const Dimension
&dim
{GetDimension(k
)};
184 if (--subscript
[k
] >= dim
.LowerBound()) {
187 subscript
[k
] = dim
.UpperBound();
192 std::size_t Descriptor::ZeroBasedElementNumber(
193 const SubscriptValue
*subscript
, const int *permutation
) const {
194 std::size_t result
{0};
195 std::size_t coefficient
{1};
196 for (int j
{0}; j
< raw_
.rank
; ++j
) {
197 int k
{permutation
? permutation
[j
] : j
};
198 const Dimension
&dim
{GetDimension(k
)};
199 result
+= coefficient
* (subscript
[k
] - dim
.LowerBound());
200 coefficient
*= dim
.Extent();
205 bool Descriptor::EstablishPointerSection(const Descriptor
&source
,
206 const SubscriptValue
*lower
, const SubscriptValue
*upper
,
207 const SubscriptValue
*stride
) {
209 raw_
.attribute
= CFI_attribute_pointer
;
210 int newRank
{raw_
.rank
};
211 for (int j
{0}; j
< raw_
.rank
; ++j
) {
212 if (!stride
|| stride
[j
] == 0) {
221 if (const auto *sourceAddendum
= source
.Addendum()) {
222 if (auto *addendum
{Addendum()}) {
223 *addendum
= *sourceAddendum
;
228 return CFI_section(&raw_
, &source
.raw_
, lower
, upper
, stride
) == CFI_SUCCESS
;
231 void Descriptor::Check() const {
235 void Descriptor::Dump(FILE *f
) const {
236 std::fprintf(f
, "Descriptor @ %p:\n", reinterpret_cast<const void *>(this));
237 std::fprintf(f
, " base_addr %p\n", raw_
.base_addr
);
238 std::fprintf(f
, " elem_len %zd\n", static_cast<std::size_t>(raw_
.elem_len
));
239 std::fprintf(f
, " version %d\n", static_cast<int>(raw_
.version
));
240 std::fprintf(f
, " rank %d\n", static_cast<int>(raw_
.rank
));
241 std::fprintf(f
, " type %d\n", static_cast<int>(raw_
.type
));
242 std::fprintf(f
, " attribute %d\n", static_cast<int>(raw_
.attribute
));
243 std::fprintf(f
, " addendum %d\n", static_cast<int>(raw_
.f18Addendum
));
244 for (int j
{0}; j
< raw_
.rank
; ++j
) {
245 std::fprintf(f
, " dim[%d] lower_bound %jd\n", j
,
246 static_cast<std::intmax_t>(raw_
.dim
[j
].lower_bound
));
247 std::fprintf(f
, " extent %jd\n",
248 static_cast<std::intmax_t>(raw_
.dim
[j
].extent
));
249 std::fprintf(f
, " sm %jd\n",
250 static_cast<std::intmax_t>(raw_
.dim
[j
].sm
));
252 if (const DescriptorAddendum
* addendum
{Addendum()}) {
257 DescriptorAddendum
&DescriptorAddendum::operator=(
258 const DescriptorAddendum
&that
) {
259 derivedType_
= that
.derivedType_
;
260 auto lenParms
{that
.LenParameters()};
261 for (std::size_t j
{0}; j
< lenParms
; ++j
) {
262 len_
[j
] = that
.len_
[j
];
267 std::size_t DescriptorAddendum::SizeInBytes() const {
268 return SizeInBytes(LenParameters());
271 std::size_t DescriptorAddendum::LenParameters() const {
272 const auto *type
{derivedType()};
273 return type
? type
->LenParameters() : 0;
276 void DescriptorAddendum::Dump(FILE *f
) const {
278 f
, " derivedType @ %p\n", reinterpret_cast<const void *>(derivedType()));
279 std::size_t lenParms
{LenParameters()};
280 for (std::size_t j
{0}; j
< lenParms
; ++j
) {
281 std::fprintf(f
, " len[%zd] %jd\n", j
, static_cast<std::intmax_t>(len_
[j
]));
284 } // namespace Fortran::runtime