1 //===-- runtime/type-info.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 //===----------------------------------------------------------------------===//
10 #include "terminator.h"
14 namespace Fortran::runtime::typeInfo
{
16 RT_OFFLOAD_API_GROUP_BEGIN
18 RT_API_ATTRS
Fortran::common::optional
<TypeParameterValue
> Value::GetValue(
19 const Descriptor
*descriptor
) const {
23 case Genre::LenParameter
:
25 if (const auto *addendum
{descriptor
->Addendum()}) {
26 return addendum
->LenParameterValue(value_
);
29 return Fortran::common::nullopt
;
31 return Fortran::common::nullopt
;
35 RT_API_ATTRS
std::size_t Component::GetElementByteSize(
36 const Descriptor
&instance
) const {
38 case TypeCategory::Integer
:
39 case TypeCategory::Unsigned
:
40 case TypeCategory::Real
:
41 case TypeCategory::Logical
:
43 case TypeCategory::Complex
:
45 case TypeCategory::Character
:
46 if (auto value
{characterLen_
.GetValue(&instance
)}) {
47 return kind_
* *value
;
50 case TypeCategory::Derived
:
51 if (const auto *type
{derivedType()}) {
52 return type
->sizeInBytes();
59 RT_API_ATTRS
std::size_t Component::GetElements(
60 const Descriptor
&instance
) const {
61 std::size_t elements
{1};
62 if (int rank
{rank_
}) {
63 if (const Value
* boundValues
{bounds()}) {
64 for (int j
{0}; j
< rank
; ++j
) {
65 TypeParameterValue lb
{
66 boundValues
[2 * j
].GetValue(&instance
).value_or(0)};
67 TypeParameterValue ub
{
68 boundValues
[2 * j
+ 1].GetValue(&instance
).value_or(0)};
70 elements
*= ub
- lb
+ 1;
82 RT_API_ATTRS
std::size_t Component::SizeInBytes(
83 const Descriptor
&instance
) const {
84 if (genre() == Genre::Data
) {
85 return GetElementByteSize(instance
) * GetElements(instance
);
86 } else if (category() == TypeCategory::Derived
) {
87 const DerivedType
*type
{derivedType()};
88 return Descriptor::SizeInBytes(
89 rank_
, true, type
? type
->LenParameters() : 0);
91 return Descriptor::SizeInBytes(rank_
);
95 RT_API_ATTRS
void Component::EstablishDescriptor(Descriptor
&descriptor
,
96 const Descriptor
&container
, Terminator
&terminator
) const {
97 ISO::CFI_attribute_t attribute
{static_cast<ISO::CFI_attribute_t
>(
98 genre_
== Genre::Allocatable
? CFI_attribute_allocatable
99 : genre_
== Genre::Pointer
? CFI_attribute_pointer
100 : CFI_attribute_other
)};
101 TypeCategory cat
{category()};
102 if (cat
== TypeCategory::Character
) {
103 std::size_t lengthInChars
{0};
104 if (auto length
{characterLen_
.GetValue(&container
)}) {
105 lengthInChars
= static_cast<std::size_t>(*length
);
108 terminator
, characterLen_
.genre() == Value::Genre::Deferred
);
110 descriptor
.Establish(
111 kind_
, lengthInChars
, nullptr, rank_
, nullptr, attribute
);
112 } else if (cat
== TypeCategory::Derived
) {
113 if (const DerivedType
* type
{derivedType()}) {
114 descriptor
.Establish(*type
, nullptr, rank_
, nullptr, attribute
);
115 } else { // unlimited polymorphic
116 descriptor
.Establish(TypeCode
{TypeCategory::Derived
, 0}, 0, nullptr,
117 rank_
, nullptr, attribute
, true);
120 descriptor
.Establish(cat
, kind_
, nullptr, rank_
, nullptr, attribute
);
122 if (rank_
&& genre_
!= Genre::Allocatable
&& genre_
!= Genre::Pointer
) {
123 const typeInfo::Value
*boundValues
{bounds()};
124 RUNTIME_CHECK(terminator
, boundValues
!= nullptr);
125 auto byteStride
{static_cast<SubscriptValue
>(descriptor
.ElementBytes())};
126 for (int j
{0}; j
< rank_
; ++j
) {
127 auto lb
{boundValues
++->GetValue(&container
)};
128 auto ub
{boundValues
++->GetValue(&container
)};
129 RUNTIME_CHECK(terminator
, lb
.has_value() && ub
.has_value());
130 Dimension
&dim
{descriptor
.GetDimension(j
)};
131 dim
.SetBounds(*lb
, *ub
);
132 dim
.SetByteStride(byteStride
);
133 byteStride
*= dim
.Extent();
138 RT_API_ATTRS
void Component::CreatePointerDescriptor(Descriptor
&descriptor
,
139 const Descriptor
&container
, Terminator
&terminator
,
140 const SubscriptValue
*subscripts
) const {
141 RUNTIME_CHECK(terminator
, genre_
== Genre::Data
);
142 EstablishDescriptor(descriptor
, container
, terminator
);
144 descriptor
.set_base_addr(container
.Element
<char>(subscripts
) + offset_
);
146 descriptor
.set_base_addr(container
.OffsetElement
<char>() + offset_
);
148 descriptor
.raw().attribute
= CFI_attribute_pointer
;
151 RT_API_ATTRS
const DerivedType
*DerivedType::GetParentType() const {
153 const Descriptor
&compDesc
{component()};
154 const Component
&component
{*compDesc
.OffsetElement
<const Component
>()};
155 return component
.derivedType();
161 RT_API_ATTRS
const Component
*DerivedType::FindDataComponent(
162 const char *compName
, std::size_t compNameLen
) const {
163 const Descriptor
&compDesc
{component()};
164 std::size_t n
{compDesc
.Elements()};
165 SubscriptValue at
[maxRank
];
166 compDesc
.GetLowerBounds(at
);
167 for (std::size_t j
{0}; j
< n
; ++j
, compDesc
.IncrementSubscripts(at
)) {
168 const Component
*component
{compDesc
.Element
<Component
>(at
)};
169 INTERNAL_CHECK(component
!= nullptr);
170 const Descriptor
&nameDesc
{component
->name()};
171 if (nameDesc
.ElementBytes() == compNameLen
&&
172 Fortran::runtime::memcmp(
173 compName
, nameDesc
.OffsetElement(), compNameLen
) == 0) {
177 const DerivedType
*parent
{GetParentType()};
178 return parent
? parent
->FindDataComponent(compName
, compNameLen
) : nullptr;
181 RT_OFFLOAD_API_GROUP_END
183 static void DumpScalarCharacter(
184 FILE *f
, const Descriptor
&desc
, const char *what
) {
185 if (desc
.raw().version
== CFI_VERSION
&&
186 desc
.type() == TypeCode
{TypeCategory::Character
, 1} &&
187 desc
.ElementBytes() > 0 && desc
.rank() == 0 &&
188 desc
.OffsetElement() != nullptr) {
189 std::fwrite(desc
.OffsetElement(), desc
.ElementBytes(), 1, f
);
191 std::fprintf(f
, "bad %s descriptor: ", what
);
196 FILE *DerivedType::Dump(FILE *f
) const {
197 std::fprintf(f
, "DerivedType @ %p:\n", reinterpret_cast<const void *>(this));
198 const std::uint64_t *uints
{reinterpret_cast<const std::uint64_t *>(this)};
199 for (int j
{0}; j
< 64; ++j
) {
200 int offset
{j
* static_cast<int>(sizeof *uints
)};
201 std::fprintf(f
, " [+%3d](%p) 0x%016jx", offset
,
202 reinterpret_cast<const void *>(&uints
[j
]),
203 static_cast<std::uintmax_t>(uints
[j
]));
204 if (offset
== offsetof(DerivedType
, binding_
)) {
205 std::fputs(" <-- binding_\n", f
);
206 } else if (offset
== offsetof(DerivedType
, name_
)) {
207 std::fputs(" <-- name_\n", f
);
208 } else if (offset
== offsetof(DerivedType
, sizeInBytes_
)) {
209 std::fputs(" <-- sizeInBytes_\n", f
);
210 } else if (offset
== offsetof(DerivedType
, uninstantiated_
)) {
211 std::fputs(" <-- uninstantiated_\n", f
);
212 } else if (offset
== offsetof(DerivedType
, kindParameter_
)) {
213 std::fputs(" <-- kindParameter_\n", f
);
214 } else if (offset
== offsetof(DerivedType
, lenParameterKind_
)) {
215 std::fputs(" <-- lenParameterKind_\n", f
);
216 } else if (offset
== offsetof(DerivedType
, component_
)) {
217 std::fputs(" <-- component_\n", f
);
218 } else if (offset
== offsetof(DerivedType
, procPtr_
)) {
219 std::fputs(" <-- procPtr_\n", f
);
220 } else if (offset
== offsetof(DerivedType
, special_
)) {
221 std::fputs(" <-- special_\n", f
);
222 } else if (offset
== offsetof(DerivedType
, specialBitSet_
)) {
223 std::fputs(" <-- specialBitSet_\n", f
);
224 } else if (offset
== offsetof(DerivedType
, hasParent_
)) {
225 std::fputs(" <-- (flags)\n", f
);
230 std::fputs(" name: ", f
);
231 DumpScalarCharacter(f
, name(), "DerivedType::name");
232 const Descriptor
&bindingDesc
{binding()};
234 f
, "\n binding descriptor (byteSize 0x%zx): ", binding_
.byteSize
);
236 const Descriptor
&compDesc
{component()};
237 std::fputs("\n components:\n", f
);
238 if (compDesc
.raw().version
== CFI_VERSION
&&
239 compDesc
.type() == TypeCode
{TypeCategory::Derived
, 0} &&
240 compDesc
.ElementBytes() == sizeof(Component
) && compDesc
.rank() == 1) {
241 std::size_t n
{compDesc
.Elements()};
242 for (std::size_t j
{0}; j
< n
; ++j
) {
243 const Component
&comp
{*compDesc
.ZeroBasedIndexedElement
<Component
>(j
)};
244 std::fprintf(f
, " [%3zd] ", j
);
248 std::fputs(" bad descriptor: ", f
);
251 const Descriptor
&specialDesc
{special()};
253 f
, "\n special descriptor (byteSize 0x%zx): ", special_
.byteSize
);
255 if (specialDesc
.IsAllocated()) {
256 std::size_t specials
{specialDesc
.Elements()};
257 for (std::size_t j
{0}; j
< specials
; ++j
) {
258 std::fprintf(f
, " [%3zd] ", j
);
259 specialDesc
.ZeroBasedIndexedElement
<SpecialBinding
>(j
)->Dump(f
);
265 FILE *Component::Dump(FILE *f
) const {
266 std::fprintf(f
, "Component @ %p:\n", reinterpret_cast<const void *>(this));
267 std::fputs(" name: ", f
);
268 DumpScalarCharacter(f
, name(), "Component::name");
269 if (genre_
== Genre::Data
) {
270 std::fputs(" Data ", f
);
271 } else if (genre_
== Genre::Pointer
) {
272 std::fputs(" Pointer ", f
);
273 } else if (genre_
== Genre::Allocatable
) {
274 std::fputs(" Allocatable", f
);
275 } else if (genre_
== Genre::Automatic
) {
276 std::fputs(" Automatic ", f
);
278 std::fprintf(f
, " (bad genre 0x%x)", static_cast<int>(genre_
));
280 std::fprintf(f
, " category %d kind %d rank %d offset 0x%zx\n", category_
,
281 kind_
, rank_
, static_cast<std::size_t>(offset_
));
282 if (initialization_
) {
283 std::fprintf(f
, " initialization @ %p:\n",
284 reinterpret_cast<const void *>(initialization_
));
285 for (int j
{0}; j
< 128; j
+= sizeof(std::uint64_t)) {
286 std::fprintf(f
, " [%3d] 0x%016jx\n", j
,
287 static_cast<std::uintmax_t>(
288 *reinterpret_cast<const std::uint64_t *>(initialization_
+ j
)));
294 FILE *SpecialBinding::Dump(FILE *f
) const {
296 f
, "SpecialBinding @ %p:\n", reinterpret_cast<const void *>(this));
298 case Which::ScalarAssignment
:
299 std::fputs(" ScalarAssignment", f
);
301 case Which::ElementalAssignment
:
302 std::fputs(" ElementalAssignment", f
);
304 case Which::ReadFormatted
:
305 std::fputs(" ReadFormatted", f
);
307 case Which::ReadUnformatted
:
308 std::fputs(" ReadUnformatted", f
);
310 case Which::WriteFormatted
:
311 std::fputs(" WriteFormatted", f
);
313 case Which::WriteUnformatted
:
314 std::fputs(" WriteUnformatted", f
);
316 case Which::ElementalFinal
:
317 std::fputs(" ElementalFinal", f
);
319 case Which::AssumedRankFinal
:
320 std::fputs(" AssumedRankFinal", f
);
323 std::fprintf(f
, " rank-%d final:",
324 static_cast<int>(which_
) - static_cast<int>(Which::ScalarFinal
));
327 std::fprintf(f
, " isArgDescriptorSet: 0x%x\n", isArgDescriptorSet_
);
328 std::fprintf(f
, " isTypeBound: 0x%x\n", isTypeBound_
);
329 std::fprintf(f
, " isArgContiguousSet: 0x%x\n", isArgContiguousSet_
);
330 std::fprintf(f
, " proc: %p\n", reinterpret_cast<void *>(proc_
));
334 } // namespace Fortran::runtime::typeInfo