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