llvm-project
333 строки · 11.5 Кб
1//===-- runtime/type-info.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 "type-info.h"
10#include "terminator.h"
11#include "tools.h"
12#include <cstdio>
13
14namespace Fortran::runtime::typeInfo {
15
16RT_OFFLOAD_API_GROUP_BEGIN
17
18RT_API_ATTRS Fortran::common::optional<TypeParameterValue> Value::GetValue(
19const Descriptor *descriptor) const {
20switch (genre_) {
21case Genre::Explicit:
22return value_;
23case Genre::LenParameter:
24if (descriptor) {
25if (const auto *addendum{descriptor->Addendum()}) {
26return addendum->LenParameterValue(value_);
27}
28}
29return Fortran::common::nullopt;
30default:
31return Fortran::common::nullopt;
32}
33}
34
35RT_API_ATTRS std::size_t Component::GetElementByteSize(
36const Descriptor &instance) const {
37switch (category()) {
38case TypeCategory::Integer:
39case TypeCategory::Real:
40case TypeCategory::Logical:
41return kind_;
42case TypeCategory::Complex:
43return 2 * kind_;
44case TypeCategory::Character:
45if (auto value{characterLen_.GetValue(&instance)}) {
46return kind_ * *value;
47}
48break;
49case TypeCategory::Derived:
50if (const auto *type{derivedType()}) {
51return type->sizeInBytes();
52}
53break;
54}
55return 0;
56}
57
58RT_API_ATTRS std::size_t Component::GetElements(
59const Descriptor &instance) const {
60std::size_t elements{1};
61if (int rank{rank_}) {
62if (const Value * boundValues{bounds()}) {
63for (int j{0}; j < rank; ++j) {
64TypeParameterValue lb{
65boundValues[2 * j].GetValue(&instance).value_or(0)};
66TypeParameterValue ub{
67boundValues[2 * j + 1].GetValue(&instance).value_or(0)};
68if (ub >= lb) {
69elements *= ub - lb + 1;
70} else {
71return 0;
72}
73}
74} else {
75return 0;
76}
77}
78return elements;
79}
80
81RT_API_ATTRS std::size_t Component::SizeInBytes(
82const Descriptor &instance) const {
83if (genre() == Genre::Data) {
84return GetElementByteSize(instance) * GetElements(instance);
85} else if (category() == TypeCategory::Derived) {
86const DerivedType *type{derivedType()};
87return Descriptor::SizeInBytes(
88rank_, true, type ? type->LenParameters() : 0);
89} else {
90return Descriptor::SizeInBytes(rank_);
91}
92}
93
94RT_API_ATTRS void Component::EstablishDescriptor(Descriptor &descriptor,
95const Descriptor &container, Terminator &terminator) const {
96ISO::CFI_attribute_t attribute{static_cast<ISO::CFI_attribute_t>(
97genre_ == Genre::Allocatable ? CFI_attribute_allocatable
98: genre_ == Genre::Pointer ? CFI_attribute_pointer
99: CFI_attribute_other)};
100TypeCategory cat{category()};
101if (cat == TypeCategory::Character) {
102std::size_t lengthInChars{0};
103if (auto length{characterLen_.GetValue(&container)}) {
104lengthInChars = static_cast<std::size_t>(*length);
105} else {
106RUNTIME_CHECK(
107terminator, characterLen_.genre() == Value::Genre::Deferred);
108}
109descriptor.Establish(
110kind_, lengthInChars, nullptr, rank_, nullptr, attribute);
111} else if (cat == TypeCategory::Derived) {
112if (const DerivedType * type{derivedType()}) {
113descriptor.Establish(*type, nullptr, rank_, nullptr, attribute);
114} else { // unlimited polymorphic
115descriptor.Establish(TypeCode{TypeCategory::Derived, 0}, 0, nullptr,
116rank_, nullptr, attribute, true);
117}
118} else {
119descriptor.Establish(cat, kind_, nullptr, rank_, nullptr, attribute);
120}
121if (rank_ && genre_ != Genre::Allocatable && genre_ != Genre::Pointer) {
122const typeInfo::Value *boundValues{bounds()};
123RUNTIME_CHECK(terminator, boundValues != nullptr);
124auto byteStride{static_cast<SubscriptValue>(descriptor.ElementBytes())};
125for (int j{0}; j < rank_; ++j) {
126auto lb{boundValues++->GetValue(&container)};
127auto ub{boundValues++->GetValue(&container)};
128RUNTIME_CHECK(terminator, lb.has_value() && ub.has_value());
129Dimension &dim{descriptor.GetDimension(j)};
130dim.SetBounds(*lb, *ub);
131dim.SetByteStride(byteStride);
132byteStride *= dim.Extent();
133}
134}
135}
136
137RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor,
138const Descriptor &container, Terminator &terminator,
139const SubscriptValue *subscripts) const {
140RUNTIME_CHECK(terminator, genre_ == Genre::Data);
141EstablishDescriptor(descriptor, container, terminator);
142if (subscripts) {
143descriptor.set_base_addr(container.Element<char>(subscripts) + offset_);
144} else {
145descriptor.set_base_addr(container.OffsetElement<char>() + offset_);
146}
147descriptor.raw().attribute = CFI_attribute_pointer;
148}
149
150RT_API_ATTRS const DerivedType *DerivedType::GetParentType() const {
151if (hasParent_) {
152const Descriptor &compDesc{component()};
153const Component &component{*compDesc.OffsetElement<const Component>()};
154return component.derivedType();
155} else {
156return nullptr;
157}
158}
159
160RT_API_ATTRS const Component *DerivedType::FindDataComponent(
161const char *compName, std::size_t compNameLen) const {
162const Descriptor &compDesc{component()};
163std::size_t n{compDesc.Elements()};
164SubscriptValue at[maxRank];
165compDesc.GetLowerBounds(at);
166for (std::size_t j{0}; j < n; ++j, compDesc.IncrementSubscripts(at)) {
167const Component *component{compDesc.Element<Component>(at)};
168INTERNAL_CHECK(component != nullptr);
169const Descriptor &nameDesc{component->name()};
170if (nameDesc.ElementBytes() == compNameLen &&
171Fortran::runtime::memcmp(
172compName, nameDesc.OffsetElement(), compNameLen) == 0) {
173return component;
174}
175}
176const DerivedType *parent{GetParentType()};
177return parent ? parent->FindDataComponent(compName, compNameLen) : nullptr;
178}
179
180RT_OFFLOAD_API_GROUP_END
181
182static void DumpScalarCharacter(
183FILE *f, const Descriptor &desc, const char *what) {
184if (desc.raw().version == CFI_VERSION &&
185desc.type() == TypeCode{TypeCategory::Character, 1} &&
186desc.ElementBytes() > 0 && desc.rank() == 0 &&
187desc.OffsetElement() != nullptr) {
188std::fwrite(desc.OffsetElement(), desc.ElementBytes(), 1, f);
189} else {
190std::fprintf(f, "bad %s descriptor: ", what);
191desc.Dump(f);
192}
193}
194
195FILE *DerivedType::Dump(FILE *f) const {
196std::fprintf(f, "DerivedType @ %p:\n", reinterpret_cast<const void *>(this));
197const std::uint64_t *uints{reinterpret_cast<const std::uint64_t *>(this)};
198for (int j{0}; j < 64; ++j) {
199int offset{j * static_cast<int>(sizeof *uints)};
200std::fprintf(f, " [+%3d](%p) 0x%016jx", offset,
201reinterpret_cast<const void *>(&uints[j]),
202static_cast<std::uintmax_t>(uints[j]));
203if (offset == offsetof(DerivedType, binding_)) {
204std::fputs(" <-- binding_\n", f);
205} else if (offset == offsetof(DerivedType, name_)) {
206std::fputs(" <-- name_\n", f);
207} else if (offset == offsetof(DerivedType, sizeInBytes_)) {
208std::fputs(" <-- sizeInBytes_\n", f);
209} else if (offset == offsetof(DerivedType, uninstantiated_)) {
210std::fputs(" <-- uninstantiated_\n", f);
211} else if (offset == offsetof(DerivedType, kindParameter_)) {
212std::fputs(" <-- kindParameter_\n", f);
213} else if (offset == offsetof(DerivedType, lenParameterKind_)) {
214std::fputs(" <-- lenParameterKind_\n", f);
215} else if (offset == offsetof(DerivedType, component_)) {
216std::fputs(" <-- component_\n", f);
217} else if (offset == offsetof(DerivedType, procPtr_)) {
218std::fputs(" <-- procPtr_\n", f);
219} else if (offset == offsetof(DerivedType, special_)) {
220std::fputs(" <-- special_\n", f);
221} else if (offset == offsetof(DerivedType, specialBitSet_)) {
222std::fputs(" <-- specialBitSet_\n", f);
223} else if (offset == offsetof(DerivedType, hasParent_)) {
224std::fputs(" <-- (flags)\n", f);
225} else {
226std::fputc('\n', f);
227}
228}
229std::fputs(" name: ", f);
230DumpScalarCharacter(f, name(), "DerivedType::name");
231const Descriptor &bindingDesc{binding()};
232std::fprintf(
233f, "\n binding descriptor (byteSize 0x%zx): ", binding_.byteSize);
234bindingDesc.Dump(f);
235const Descriptor &compDesc{component()};
236std::fputs("\n components:\n", f);
237if (compDesc.raw().version == CFI_VERSION &&
238compDesc.type() == TypeCode{TypeCategory::Derived, 0} &&
239compDesc.ElementBytes() == sizeof(Component) && compDesc.rank() == 1) {
240std::size_t n{compDesc.Elements()};
241for (std::size_t j{0}; j < n; ++j) {
242const Component &comp{*compDesc.ZeroBasedIndexedElement<Component>(j)};
243std::fprintf(f, " [%3zd] ", j);
244comp.Dump(f);
245}
246} else {
247std::fputs(" bad descriptor: ", f);
248compDesc.Dump(f);
249}
250const Descriptor &specialDesc{special()};
251std::fprintf(
252f, "\n special descriptor (byteSize 0x%zx): ", special_.byteSize);
253specialDesc.Dump(f);
254if (specialDesc.IsAllocated()) {
255std::size_t specials{specialDesc.Elements()};
256for (std::size_t j{0}; j < specials; ++j) {
257std::fprintf(f, " [%3zd] ", j);
258specialDesc.ZeroBasedIndexedElement<SpecialBinding>(j)->Dump(f);
259}
260}
261return f;
262}
263
264FILE *Component::Dump(FILE *f) const {
265std::fprintf(f, "Component @ %p:\n", reinterpret_cast<const void *>(this));
266std::fputs(" name: ", f);
267DumpScalarCharacter(f, name(), "Component::name");
268if (genre_ == Genre::Data) {
269std::fputs(" Data ", f);
270} else if (genre_ == Genre::Pointer) {
271std::fputs(" Pointer ", f);
272} else if (genre_ == Genre::Allocatable) {
273std::fputs(" Allocatable", f);
274} else if (genre_ == Genre::Automatic) {
275std::fputs(" Automatic ", f);
276} else {
277std::fprintf(f, " (bad genre 0x%x)", static_cast<int>(genre_));
278}
279std::fprintf(f, " category %d kind %d rank %d offset 0x%zx\n", category_,
280kind_, rank_, static_cast<std::size_t>(offset_));
281if (initialization_) {
282std::fprintf(f, " initialization @ %p:\n",
283reinterpret_cast<const void *>(initialization_));
284for (int j{0}; j < 128; j += sizeof(std::uint64_t)) {
285std::fprintf(f, " [%3d] 0x%016jx\n", j,
286static_cast<std::uintmax_t>(
287*reinterpret_cast<const std::uint64_t *>(initialization_ + j)));
288}
289}
290return f;
291}
292
293FILE *SpecialBinding::Dump(FILE *f) const {
294std::fprintf(
295f, "SpecialBinding @ %p:\n", reinterpret_cast<const void *>(this));
296switch (which_) {
297case Which::ScalarAssignment:
298std::fputs(" ScalarAssignment", f);
299break;
300case Which::ElementalAssignment:
301std::fputs(" ElementalAssignment", f);
302break;
303case Which::ReadFormatted:
304std::fputs(" ReadFormatted", f);
305break;
306case Which::ReadUnformatted:
307std::fputs(" ReadUnformatted", f);
308break;
309case Which::WriteFormatted:
310std::fputs(" WriteFormatted", f);
311break;
312case Which::WriteUnformatted:
313std::fputs(" WriteUnformatted", f);
314break;
315case Which::ElementalFinal:
316std::fputs(" ElementalFinal", f);
317break;
318case Which::AssumedRankFinal:
319std::fputs(" AssumedRankFinal", f);
320break;
321default:
322std::fprintf(f, " rank-%d final:",
323static_cast<int>(which_) - static_cast<int>(Which::ScalarFinal));
324break;
325}
326std::fprintf(f, " isArgDescriptorSet: 0x%x\n", isArgDescriptorSet_);
327std::fprintf(f, " isTypeBound: 0x%x\n", isTypeBound_);
328std::fprintf(f, " isArgContiguousSet: 0x%x\n", isArgContiguousSet_);
329std::fprintf(f, " proc: %p\n", reinterpret_cast<void *>(proc_));
330return f;
331}
332
333} // namespace Fortran::runtime::typeInfo
334