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