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