1 //===-- runtime/type-info.h -------------------------------------*- C++ -*-===// 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 #ifndef FORTRAN_RUNTIME_TYPE_INFO_H_ 10 #define FORTRAN_RUNTIME_TYPE_INFO_H_ 11 12 // A C++ perspective of the derived type description schemata in 13 // flang/module/__fortran_type_info.f90. 14 15 #include "terminator.h" 16 #include "flang/Common/Fortran.h" 17 #include "flang/Common/bit-population-count.h" 18 #include "flang/Runtime/descriptor.h" 19 #include <cinttypes> 20 #include <memory> 21 #include <optional> 22 23 namespace Fortran::runtime::typeInfo { 24 25 class DerivedType; 26 27 using ProcedurePointer = void (*)(); // TYPE(C_FUNPTR) 28 29 struct Binding { 30 ProcedurePointer proc; 31 StaticDescriptor<0> name; // CHARACTER(:), POINTER 32 }; 33 34 class Value { 35 public: 36 enum class Genre : std::uint8_t { 37 Deferred = 1, 38 Explicit = 2, 39 LenParameter = 3 40 }; 41 42 std::optional<TypeParameterValue> GetValue(const Descriptor *) const; 43 44 private: 45 Genre genre_{Genre::Explicit}; 46 // The value encodes an index into the table of LEN type parameters in 47 // a descriptor's addendum for genre == Genre::LenParameter. 48 TypeParameterValue value_{0}; 49 }; 50 51 class Component { 52 public: 53 enum class Genre : std::uint8_t { 54 Data = 1, 55 Pointer = 2, 56 Allocatable = 3, 57 Automatic = 4 58 }; 59 name()60 const Descriptor &name() const { return name_.descriptor(); } genre()61 Genre genre() const { return genre_; } category()62 TypeCategory category() const { return static_cast<TypeCategory>(category_); } kind()63 int kind() const { return kind_; } rank()64 int rank() const { return rank_; } offset()65 std::uint64_t offset() const { return offset_; } characterLen()66 const Value &characterLen() const { return characterLen_; } derivedType()67 const DerivedType *derivedType() const { 68 return derivedType_.descriptor().OffsetElement<const DerivedType>(); 69 } lenValue()70 const Value *lenValue() const { 71 return lenValue_.descriptor().OffsetElement<const Value>(); 72 } bounds()73 const Value *bounds() const { 74 return bounds_.descriptor().OffsetElement<const Value>(); 75 } initialization()76 const char *initialization() const { return initialization_; } 77 78 std::size_t GetElementByteSize(const Descriptor &) const; 79 std::size_t GetElements(const Descriptor &) const; 80 81 // For ocmponents that are descriptors, returns size of descriptor; 82 // for Genre::Data, returns elemental byte size times element count. 83 std::size_t SizeInBytes(const Descriptor &) const; 84 85 // Establishes a descriptor from this component description. 86 void EstablishDescriptor( 87 Descriptor &, const Descriptor &container, Terminator &) const; 88 89 // Creates a pointer descriptor from this component description. 90 void CreatePointerDescriptor(Descriptor &, const Descriptor &container, 91 const SubscriptValue[], Terminator &) const; 92 93 FILE *Dump(FILE * = stdout) const; 94 95 private: 96 StaticDescriptor<0> name_; // CHARACTER(:), POINTER 97 Genre genre_{Genre::Data}; 98 std::uint8_t category_; // common::TypeCategory 99 std::uint8_t kind_{0}; 100 std::uint8_t rank_{0}; 101 std::uint64_t offset_{0}; 102 Value characterLen_; // for TypeCategory::Character 103 StaticDescriptor<0, true> derivedType_; // TYPE(DERIVEDTYPE), POINTER 104 StaticDescriptor<1, true> 105 lenValue_; // TYPE(VALUE), POINTER, DIMENSION(:), CONTIGUOUS 106 StaticDescriptor<2, true> 107 bounds_; // TYPE(VALUE), POINTER, DIMENSION(2,:), CONTIGUOUS 108 const char *initialization_{nullptr}; // for Genre::Data and Pointer 109 // TODO: cobounds 110 // TODO: `PRIVATE` attribute 111 }; 112 113 struct ProcPtrComponent { 114 StaticDescriptor<0> name; // CHARACTER(:), POINTER 115 std::uint64_t offset{0}; 116 ProcedurePointer procInitialization; 117 }; 118 119 class SpecialBinding { 120 public: 121 enum class Which : std::uint8_t { 122 None = 0, 123 ScalarAssignment = 1, 124 ElementalAssignment = 2, 125 ReadFormatted = 3, 126 ReadUnformatted = 4, 127 WriteFormatted = 5, 128 WriteUnformatted = 6, 129 ElementalFinal = 7, 130 AssumedRankFinal = 8, 131 ScalarFinal = 9, 132 // higher-ranked final procedures follow 133 }; 134 RankFinal(int rank)135 static constexpr Which RankFinal(int rank) { 136 return static_cast<Which>(static_cast<int>(Which::ScalarFinal) + rank); 137 } 138 which()139 Which which() const { return which_; } IsArgDescriptor(int zeroBasedArg)140 bool IsArgDescriptor(int zeroBasedArg) const { 141 return (isArgDescriptorSet_ >> zeroBasedArg) & 1; 142 } GetProc()143 template <typename PROC> PROC GetProc() const { 144 return reinterpret_cast<PROC>(proc_); 145 } 146 147 FILE *Dump(FILE *) const; 148 149 private: 150 Which which_{Which::None}; 151 152 // The following little bit-set identifies which dummy arguments are 153 // passed via descriptors for their derived type arguments. 154 // Which::Assignment and Which::ElementalAssignment: 155 // Set to 1, 2, or (usually 3). 156 // The passed-object argument (usually the "to") is always passed via a 157 // a descriptor in the cases where the runtime will call a defined 158 // assignment because these calls are to type-bound generics, 159 // not generic interfaces, and type-bound generic defined assigment 160 // may appear only in an extensible type and requires a passed-object 161 // argument (see C774), and passed-object arguments to TBPs must be 162 // both polymorphic and scalar (C760). The non-passed-object argument 163 // (usually the "from") is usually, but not always, also a descriptor. 164 // Which::Final and Which::ElementalFinal: 165 // Set to 1 when dummy argument is assumed-shape; otherwise, the 166 // argument can be passed by address. (Fortran guarantees that 167 // any finalized object must be whole and contiguous by restricting 168 // the use of DEALLOCATE on pointers. The dummy argument of an 169 // elemental final subroutine must be scalar and monomorphic, but 170 // use a descriptors when the type has LEN parameters.) 171 // Which::AssumedRankFinal: flag must necessarily be set 172 // User derived type I/O: 173 // Set to 1 when "dtv" initial dummy argument is polymorphic, which is 174 // the case when and only when the derived type is extensible. 175 // When false, the user derived type I/O subroutine must have been 176 // called via a generic interface, not a generic TBP. 177 std::uint8_t isArgDescriptorSet_{0}; 178 179 ProcedurePointer proc_{nullptr}; 180 }; 181 182 class DerivedType { 183 public: 184 ~DerivedType(); // never defined 185 binding()186 const Descriptor &binding() const { return binding_.descriptor(); } name()187 const Descriptor &name() const { return name_.descriptor(); } sizeInBytes()188 std::uint64_t sizeInBytes() const { return sizeInBytes_; } uninstatiated()189 const Descriptor &uninstatiated() const { 190 return uninstantiated_.descriptor(); 191 } kindParameter()192 const Descriptor &kindParameter() const { 193 return kindParameter_.descriptor(); 194 } lenParameterKind()195 const Descriptor &lenParameterKind() const { 196 return lenParameterKind_.descriptor(); 197 } component()198 const Descriptor &component() const { return component_.descriptor(); } procPtr()199 const Descriptor &procPtr() const { return procPtr_.descriptor(); } special()200 const Descriptor &special() const { return special_.descriptor(); } hasParent()201 bool hasParent() const { return hasParent_; } noInitializationNeeded()202 bool noInitializationNeeded() const { return noInitializationNeeded_; } noDestructionNeeded()203 bool noDestructionNeeded() const { return noDestructionNeeded_; } noFinalizationNeeded()204 bool noFinalizationNeeded() const { return noFinalizationNeeded_; } 205 LenParameters()206 std::size_t LenParameters() const { return lenParameterKind().Elements(); } 207 208 const DerivedType *GetParentType() const; 209 210 // Finds a data component by name in this derived type or tis ancestors. 211 const Component *FindDataComponent( 212 const char *name, std::size_t nameLen) const; 213 214 // O(1) look-up of special procedure bindings FindSpecialBinding(SpecialBinding::Which which)215 const SpecialBinding *FindSpecialBinding(SpecialBinding::Which which) const { 216 auto bitIndex{static_cast<std::uint32_t>(which)}; 217 auto bit{std::uint32_t{1} << bitIndex}; 218 if (specialBitSet_ & bit) { 219 // The index of this special procedure in the sorted array is the 220 // number of special bindings that are present with smaller "which" 221 // code values. 222 int offset{common::BitPopulationCount(specialBitSet_ & (bit - 1))}; 223 const auto *binding{ 224 special_.descriptor().ZeroBasedIndexedElement<SpecialBinding>( 225 offset)}; 226 INTERNAL_CHECK(binding && binding->which() == which); 227 return binding; 228 } else { 229 return nullptr; 230 } 231 } 232 233 FILE *Dump(FILE * = stdout) const; 234 235 private: 236 // This member comes first because it's used like a vtable by generated code. 237 // It includes all of the ancestor types' bindings, if any, first, 238 // with any overrides from descendants already applied to them. Local 239 // bindings then follow in alphabetic order of binding name. 240 StaticDescriptor<1, true> 241 binding_; // TYPE(BINDING), DIMENSION(:), POINTER, CONTIGUOUS 242 243 StaticDescriptor<0> name_; // CHARACTER(:), POINTER 244 245 std::uint64_t sizeInBytes_{0}; 246 247 // Instantiations of a parameterized derived type with KIND type 248 // parameters will point this data member to the description of 249 // the original uninstantiated type, which may be shared from a 250 // module via use association. The original uninstantiated derived 251 // type description will point to itself. Derived types that have 252 // no KIND type parameters will have a null pointer here. 253 StaticDescriptor<0, true> uninstantiated_; // TYPE(DERIVEDTYPE), POINTER 254 255 // These pointer targets include all of the items from the parent, if any. 256 StaticDescriptor<1> kindParameter_; // pointer to rank-1 array of INTEGER(8) 257 StaticDescriptor<1> 258 lenParameterKind_; // pointer to rank-1 array of INTEGER(1) 259 260 // This array of local data components includes the parent component. 261 // Components are in component order, not collation order of their names. 262 // It does not include procedure pointer components. 263 StaticDescriptor<1, true> 264 component_; // TYPE(COMPONENT), POINTER, DIMENSION(:), CONTIGUOUS 265 266 // Procedure pointer components 267 StaticDescriptor<1, true> 268 procPtr_; // TYPE(PROCPTR), POINTER, DIMENSION(:), CONTIGUOUS 269 270 // Packed in ascending order of "which" code values. 271 // Does not include special bindings from ancestral types. 272 StaticDescriptor<1, true> 273 special_; // TYPE(SPECIALBINDING), POINTER, DIMENSION(:), CONTIGUOUS 274 275 // Little-endian bit-set of special procedure binding "which" code values 276 // for O(1) look-up in FindSpecialBinding() above. 277 std::uint32_t specialBitSet_{0}; 278 279 // Flags 280 bool hasParent_{false}; 281 bool noInitializationNeeded_{false}; 282 bool noDestructionNeeded_{false}; 283 bool noFinalizationNeeded_{false}; 284 }; 285 286 } // namespace Fortran::runtime::typeInfo 287 #endif // FORTRAN_RUNTIME_TYPE_INFO_H_ 288