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