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, const SubscriptValue subscripts[], 120 Terminator &terminator) const { 121 RUNTIME_CHECK(terminator, genre_ == Genre::Data); 122 EstablishDescriptor(descriptor, container, terminator); 123 descriptor.set_base_addr(container.Element<char>(subscripts) + offset_); 124 descriptor.raw().attribute = CFI_attribute_pointer; 125 } 126 127 const DerivedType *DerivedType::GetParentType() const { 128 if (hasParent_) { 129 const Descriptor &compDesc{component()}; 130 const Component &component{*compDesc.OffsetElement<const Component>()}; 131 return component.derivedType(); 132 } else { 133 return nullptr; 134 } 135 } 136 137 const Component *DerivedType::FindDataComponent( 138 const char *compName, std::size_t compNameLen) const { 139 const Descriptor &compDesc{component()}; 140 std::size_t n{compDesc.Elements()}; 141 SubscriptValue at[maxRank]; 142 compDesc.GetLowerBounds(at); 143 for (std::size_t j{0}; j < n; ++j, compDesc.IncrementSubscripts(at)) { 144 const Component *component{compDesc.Element<Component>(at)}; 145 INTERNAL_CHECK(component != nullptr); 146 const Descriptor &nameDesc{component->name()}; 147 if (nameDesc.ElementBytes() == compNameLen && 148 std::memcmp(compName, nameDesc.OffsetElement(), compNameLen) == 0) { 149 return component; 150 } 151 } 152 const DerivedType *parent{GetParentType()}; 153 return parent ? parent->FindDataComponent(compName, compNameLen) : nullptr; 154 } 155 156 static void DumpScalarCharacter( 157 FILE *f, const Descriptor &desc, const char *what) { 158 if (desc.raw().version == CFI_VERSION && 159 desc.type() == TypeCode{TypeCategory::Character, 1} && 160 desc.ElementBytes() > 0 && desc.rank() == 0 && 161 desc.OffsetElement() != nullptr) { 162 std::fwrite(desc.OffsetElement(), desc.ElementBytes(), 1, f); 163 } else { 164 std::fprintf(f, "bad %s descriptor: ", what); 165 desc.Dump(f); 166 } 167 } 168 169 FILE *DerivedType::Dump(FILE *f) const { 170 std::fprintf( 171 f, "DerivedType @ 0x%p:\n", reinterpret_cast<const void *>(this)); 172 const std::uint64_t *uints{reinterpret_cast<const std::uint64_t *>(this)}; 173 for (int j{0}; j < 64; ++j) { 174 int offset{j * static_cast<int>(sizeof *uints)}; 175 std::fprintf(f, " [+%3d](0x%p) 0x%016jx", offset, 176 reinterpret_cast<const void *>(&uints[j]), 177 static_cast<std::uintmax_t>(uints[j])); 178 if (offset == offsetof(DerivedType, binding_)) { 179 std::fputs(" <-- binding_\n", f); 180 } else if (offset == offsetof(DerivedType, name_)) { 181 std::fputs(" <-- name_\n", f); 182 } else if (offset == offsetof(DerivedType, sizeInBytes_)) { 183 std::fputs(" <-- sizeInBytes_\n", f); 184 } else if (offset == offsetof(DerivedType, uninstantiated_)) { 185 std::fputs(" <-- uninstantiated_\n", f); 186 } else if (offset == offsetof(DerivedType, kindParameter_)) { 187 std::fputs(" <-- kindParameter_\n", f); 188 } else if (offset == offsetof(DerivedType, lenParameterKind_)) { 189 std::fputs(" <-- lenParameterKind_\n", f); 190 } else if (offset == offsetof(DerivedType, component_)) { 191 std::fputs(" <-- component_\n", f); 192 } else if (offset == offsetof(DerivedType, procPtr_)) { 193 std::fputs(" <-- procPtr_\n", f); 194 } else if (offset == offsetof(DerivedType, special_)) { 195 std::fputs(" <-- special_\n", f); 196 } else if (offset == offsetof(DerivedType, specialBitSet_)) { 197 std::fputs(" <-- specialBitSet_\n", f); 198 } else if (offset == offsetof(DerivedType, hasParent_)) { 199 std::fputs(" <-- (flags)\n", f); 200 } else { 201 std::fputc('\n', f); 202 } 203 } 204 std::fputs(" name: ", f); 205 DumpScalarCharacter(f, name(), "DerivedType::name"); 206 const Descriptor &bindingDesc{binding()}; 207 std::fprintf( 208 f, "\n binding descriptor (byteSize 0x%zx): ", binding_.byteSize); 209 bindingDesc.Dump(f); 210 const Descriptor &compDesc{component()}; 211 std::fputs("\n components:\n", f); 212 if (compDesc.raw().version == CFI_VERSION && 213 compDesc.type() == TypeCode{TypeCategory::Derived, 0} && 214 compDesc.ElementBytes() == sizeof(Component) && compDesc.rank() == 1) { 215 std::size_t n{compDesc.Elements()}; 216 for (std::size_t j{0}; j < n; ++j) { 217 const Component &comp{*compDesc.ZeroBasedIndexedElement<Component>(j)}; 218 std::fprintf(f, " [%3zd] ", j); 219 comp.Dump(f); 220 } 221 } else { 222 std::fputs(" bad descriptor: ", f); 223 compDesc.Dump(f); 224 } 225 const Descriptor &specialDesc{special()}; 226 std::fprintf( 227 f, "\n special descriptor (byteSize 0x%zx): ", special_.byteSize); 228 specialDesc.Dump(f); 229 std::size_t specials{specialDesc.Elements()}; 230 for (std::size_t j{0}; j < specials; ++j) { 231 std::fprintf(f, " [%3zd] ", j); 232 specialDesc.ZeroBasedIndexedElement<SpecialBinding>(j)->Dump(f); 233 } 234 return f; 235 } 236 237 FILE *Component::Dump(FILE *f) const { 238 std::fprintf(f, "Component @ 0x%p:\n", reinterpret_cast<const void *>(this)); 239 std::fputs(" name: ", f); 240 DumpScalarCharacter(f, name(), "Component::name"); 241 if (genre_ == Genre::Data) { 242 std::fputs(" Data ", f); 243 } else if (genre_ == Genre::Pointer) { 244 std::fputs(" Pointer ", f); 245 } else if (genre_ == Genre::Allocatable) { 246 std::fputs(" Allocatable", f); 247 } else if (genre_ == Genre::Automatic) { 248 std::fputs(" Automatic ", f); 249 } else { 250 std::fprintf(f, " (bad genre 0x%x)", static_cast<int>(genre_)); 251 } 252 std::fprintf(f, " category %d kind %d rank %d offset 0x%zx\n", category_, 253 kind_, rank_, static_cast<std::size_t>(offset_)); 254 if (initialization_) { 255 std::fprintf(f, " initialization @ 0x%p:\n", 256 reinterpret_cast<const void *>(initialization_)); 257 for (int j{0}; j < 128; j += sizeof(std::uint64_t)) { 258 std::fprintf(f, " [%3d] 0x%016jx\n", j, 259 static_cast<std::uintmax_t>( 260 *reinterpret_cast<const std::uint64_t *>(initialization_ + j))); 261 } 262 } 263 return f; 264 } 265 266 FILE *SpecialBinding::Dump(FILE *f) const { 267 std::fprintf( 268 f, "SpecialBinding @ 0x%p:\n", reinterpret_cast<const void *>(this)); 269 switch (which_) { 270 case Which::ScalarAssignment: 271 std::fputs(" ScalarAssignment", f); 272 break; 273 case Which::ElementalAssignment: 274 std::fputs(" ElementalAssignment", f); 275 break; 276 case Which::ReadFormatted: 277 std::fputs(" ReadFormatted", f); 278 break; 279 case Which::ReadUnformatted: 280 std::fputs(" ReadUnformatted", f); 281 break; 282 case Which::WriteFormatted: 283 std::fputs(" WriteFormatted", f); 284 break; 285 case Which::WriteUnformatted: 286 std::fputs(" WriteUnformatted", f); 287 break; 288 case Which::ElementalFinal: 289 std::fputs(" ElementalFinal", f); 290 break; 291 case Which::AssumedRankFinal: 292 std::fputs(" AssumedRankFinal", f); 293 break; 294 default: 295 std::fprintf(f, " rank-%d final:", 296 static_cast<int>(which_) - static_cast<int>(Which::ScalarFinal)); 297 break; 298 } 299 std::fprintf(f, " isArgDescriptorSet: 0x%x\n", isArgDescriptorSet_); 300 std::fprintf(f, " proc: 0x%p\n", reinterpret_cast<void *>(proc_)); 301 return f; 302 } 303 304 } // namespace Fortran::runtime::typeInfo 305