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 <cstdio>
12 
13 namespace Fortran::runtime::typeInfo {
14 
15 std::optional<TypeParameterValue> Value::GetValue(
16     const Descriptor *descriptor) const {
17   switch (genre_) {
18   case Genre::Explicit:
19     return value_;
20   case Genre::LenParameter:
21     if (descriptor) {
22       if (const auto *addendum{descriptor->Addendum()}) {
23         return addendum->LenParameterValue(value_);
24       }
25     }
26     return std::nullopt;
27   default:
28     return std::nullopt;
29   }
30 }
31 
32 void Component::EstablishDescriptor(Descriptor &descriptor,
33     const Descriptor &container, const SubscriptValue subscripts[],
34     Terminator &terminator) const {
35   RUNTIME_CHECK(terminator, genre_ == Genre::Data);
36   TypeCategory cat{category()};
37   if (cat == TypeCategory::Character) {
38     auto length{characterLen_.GetValue(&container)};
39     RUNTIME_CHECK(terminator, length.has_value());
40     descriptor.Establish(kind_, *length / kind_, nullptr, rank_);
41   } else if (cat == TypeCategory::Derived) {
42     const DerivedType *type{derivedType()};
43     RUNTIME_CHECK(terminator, type != nullptr);
44     descriptor.Establish(*type, nullptr, rank_);
45   } else {
46     descriptor.Establish(cat, kind_, nullptr, rank_);
47   }
48   if (rank_) {
49     const typeInfo::Value *boundValues{bounds()};
50     RUNTIME_CHECK(terminator, boundValues != nullptr);
51     auto byteStride{static_cast<SubscriptValue>(descriptor.ElementBytes())};
52     for (int j{0}; j < rank_; ++j) {
53       auto lb{boundValues++->GetValue(&container)};
54       auto ub{boundValues++->GetValue(&container)};
55       RUNTIME_CHECK(terminator, lb.has_value() && ub.has_value());
56       Dimension &dim{descriptor.GetDimension(j)};
57       dim.SetBounds(*lb, *ub);
58       dim.SetByteStride(byteStride);
59       byteStride *= dim.Extent();
60     }
61   }
62   descriptor.set_base_addr(container.Element<char>(subscripts) + offset_);
63 }
64 
65 const Component *DerivedType::FindDataComponent(
66     const char *compName, std::size_t compNameLen) const {
67   const Descriptor &compDesc{component()};
68   std::size_t n{compDesc.Elements()};
69   SubscriptValue at[maxRank];
70   compDesc.GetLowerBounds(at);
71   for (std::size_t j{0}; j < n; ++j, compDesc.IncrementSubscripts(at)) {
72     const Component *component{compDesc.Element<Component>(at)};
73     INTERNAL_CHECK(component != nullptr);
74     const Descriptor &nameDesc{component->name()};
75     if (nameDesc.ElementBytes() == compNameLen &&
76         std::memcmp(compName, nameDesc.OffsetElement(), compNameLen) == 0) {
77       return component;
78     }
79   }
80   const DerivedType *ancestor{parent().OffsetElement<DerivedType>()};
81   return ancestor ? ancestor->FindDataComponent(compName, compNameLen)
82                   : nullptr;
83 }
84 
85 static void DumpScalarCharacter(
86     FILE *f, const Descriptor &desc, const char *what) {
87   if (desc.raw().version == CFI_VERSION &&
88       desc.type() == TypeCode{TypeCategory::Character, 1} &&
89       desc.ElementBytes() > 0 && desc.rank() == 0 &&
90       desc.OffsetElement() != nullptr) {
91     std::fwrite(desc.OffsetElement(), desc.ElementBytes(), 1, f);
92   } else {
93     std::fprintf(f, "bad %s descriptor: ", what);
94     desc.Dump(f);
95   }
96 }
97 
98 FILE *DerivedType::Dump(FILE *f) const {
99   std::fprintf(
100       f, "DerivedType @ 0x%p:\n", reinterpret_cast<const void *>(this));
101   const std::uint64_t *uints{reinterpret_cast<const std::uint64_t *>(this)};
102   for (int j{0}; j < 64; ++j) {
103     int offset{j * static_cast<int>(sizeof *uints)};
104     std::fprintf(f, "    [+%3d](0x%p) %#016jx", offset,
105         reinterpret_cast<const void *>(&uints[j]),
106         static_cast<std::intmax_t>(uints[j]));
107     if (offset == offsetof(DerivedType, binding_)) {
108       std::fputs(" <-- binding_\n", f);
109     } else if (offset == offsetof(DerivedType, name_)) {
110       std::fputs(" <-- name_\n", f);
111     } else if (offset == offsetof(DerivedType, sizeInBytes_)) {
112       std::fputs(" <-- sizeInBytes_\n", f);
113     } else if (offset == offsetof(DerivedType, parent_)) {
114       std::fputs(" <-- parent_\n", f);
115     } else if (offset == offsetof(DerivedType, uninstantiated_)) {
116       std::fputs(" <-- uninstantiated_\n", f);
117     } else if (offset == offsetof(DerivedType, typeHash_)) {
118       std::fputs(" <-- typeHash_\n", f);
119     } else if (offset == offsetof(DerivedType, kindParameter_)) {
120       std::fputs(" <-- kindParameter_\n", f);
121     } else if (offset == offsetof(DerivedType, lenParameterKind_)) {
122       std::fputs(" <-- lenParameterKind_\n", f);
123     } else if (offset == offsetof(DerivedType, component_)) {
124       std::fputs(" <-- component_\n", f);
125     } else if (offset == offsetof(DerivedType, procPtr_)) {
126       std::fputs(" <-- procPtr_\n", f);
127     } else if (offset == offsetof(DerivedType, special_)) {
128       std::fputs(" <-- special_\n", f);
129     } else {
130       std::fputc('\n', f);
131     }
132   }
133   std::fputs("  name: ", f);
134   DumpScalarCharacter(f, name(), "DerivedType::name");
135   const Descriptor &bindingDesc{binding()};
136   std::fprintf(
137       f, "\n  binding descriptor (byteSize 0x%zx): ", binding_.byteSize);
138   bindingDesc.Dump(f);
139   const Descriptor &compDesc{component()};
140   std::fputs("\n  components:\n", f);
141   if (compDesc.raw().version == CFI_VERSION &&
142       compDesc.type() == TypeCode{TypeCategory::Derived, 0} &&
143       compDesc.ElementBytes() == sizeof(Component) && compDesc.rank() == 1) {
144     std::size_t n{compDesc.Elements()};
145     for (std::size_t j{0}; j < n; ++j) {
146       const Component &comp{*compDesc.ZeroBasedIndexedElement<Component>(j)};
147       std::fprintf(f, "  [%3zd] ", j);
148       comp.Dump(f);
149     }
150   } else {
151     std::fputs("    bad descriptor: ", f);
152     compDesc.Dump(f);
153   }
154   return f;
155 }
156 
157 FILE *Component::Dump(FILE *f) const {
158   std::fprintf(f, "Component @ 0x%p:\n", reinterpret_cast<const void *>(this));
159   std::fputs("    name: ", f);
160   DumpScalarCharacter(f, name(), "Component::name");
161   if (genre_ == Genre::Data) {
162     std::fputs("    Data       ", f);
163   } else if (genre_ == Genre::Pointer) {
164     std::fputs("    Pointer    ", f);
165   } else if (genre_ == Genre::Allocatable) {
166     std::fputs("    Allocatable", f);
167   } else if (genre_ == Genre::Automatic) {
168     std::fputs("    Automatic  ", f);
169   } else {
170     std::fprintf(f, "    (bad genre 0x%x)", static_cast<int>(genre_));
171   }
172   std::fprintf(f, " category %d  kind %d  rank %d  offset 0x%zx\n", category_,
173       kind_, rank_, static_cast<std::size_t>(offset_));
174   return f;
175 }
176 
177 } // namespace Fortran::runtime::typeInfo
178