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