1 //===-- runtime/derived-type.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_DERIVED_TYPE_H_
10 #define FORTRAN_RUNTIME_DERIVED_TYPE_H_
11 
12 #include "type-code.h"
13 #include "flang/ISO_Fortran_binding.h"
14 #include <cinttypes>
15 #include <cstddef>
16 
17 namespace Fortran::runtime {
18 
19 class Descriptor;
20 
21 // Static type information about derived type specializations,
22 // suitable for residence in read-only storage.
23 
24 using TypeParameterValue = ISO::CFI_index_t;
25 
26 class TypeParameter {
27 public:
name()28   const char *name() const { return name_; }
typeCode()29   const TypeCode typeCode() const { return typeCode_; }
30 
IsLenTypeParameter()31   bool IsLenTypeParameter() const { return which_ < 0; }
32 
33   // Returns the static value of a KIND type parameter, or the default
34   // value of a LEN type parameter.
StaticValue()35   TypeParameterValue StaticValue() const { return value_; }
36 
37   // Returns the static value of a KIND type parameter, or an
38   // instantiated value of LEN type parameter.
39   TypeParameterValue GetValue(const Descriptor &) const;
40 
41 private:
42   const char *name_;
43   TypeCode typeCode_; // INTEGER, but not necessarily default kind
44   int which_{-1}; // index into DescriptorAddendum LEN type parameter values
45   TypeParameterValue value_; // default in the case of LEN type parameter
46 };
47 
48 // Components that have any need for a descriptor will either reference
49 // a static descriptor that applies to all instances, or will *be* a
50 // descriptor.  Be advised: the base addresses in static descriptors
51 // are null.  Most runtime interfaces separate the data address from that
52 // of the descriptor, and ignore the encapsulated base address in the
53 // descriptor.  Some interfaces, e.g. calls to interoperable procedures,
54 // cannot pass a separate data address, and any static descriptor being used
55 // in that kind of situation must be copied and customized.
56 // Static descriptors are flagged in their attributes.
57 class Component {
58 public:
name()59   const char *name() const { return name_; }
typeCode()60   TypeCode typeCode() const { return typeCode_; }
staticDescriptor()61   const Descriptor *staticDescriptor() const { return staticDescriptor_; }
62 
IsParent()63   bool IsParent() const { return (flags_ & PARENT) != 0; }
IsPrivate()64   bool IsPrivate() const { return (flags_ & PRIVATE) != 0; }
IsDescriptor()65   bool IsDescriptor() const { return (flags_ & IS_DESCRIPTOR) != 0; }
66 
Locate(char * dtInstance)67   template <typename A> A *Locate(char *dtInstance) const {
68     return reinterpret_cast<A *>(dtInstance + offset_);
69   }
Locate(const char * dtInstance)70   template <typename A> const A *Locate(const char *dtInstance) const {
71     return reinterpret_cast<const A *>(dtInstance + offset_);
72   }
73 
GetDescriptor(char * dtInstance)74   Descriptor *GetDescriptor(char *dtInstance) const {
75     if (IsDescriptor()) {
76       return Locate<Descriptor>(dtInstance);
77     } else {
78       return nullptr;
79     }
80   }
81 
GetDescriptor(const char * dtInstance)82   const Descriptor *GetDescriptor(const char *dtInstance) const {
83     if (staticDescriptor_) {
84       return staticDescriptor_;
85     } else if (IsDescriptor()) {
86       return Locate<const Descriptor>(dtInstance);
87     } else {
88       return nullptr;
89     }
90   }
91 
92 private:
93   enum Flag { PARENT = 1, PRIVATE = 2, IS_DESCRIPTOR = 4 };
94   const char *name_{nullptr};
95   std::uint32_t flags_{0};
96   TypeCode typeCode_{CFI_type_other};
97   const Descriptor *staticDescriptor_{nullptr};
98   std::size_t offset_{0}; // byte offset in derived type instance
99 };
100 
101 struct ExecutableCode {
ExecutableCodeExecutableCode102   ExecutableCode() {}
103   ExecutableCode(const ExecutableCode &) = default;
104   ExecutableCode &operator=(const ExecutableCode &) = default;
105   std::intptr_t host{0};
106   std::intptr_t device{0};
107 };
108 
109 struct TypeBoundProcedure {
110   const char *name;
111   ExecutableCode code;
112 };
113 
114 // Represents a specialization of a derived type; i.e., any KIND type
115 // parameters have values set at compilation time.
116 // Extended derived types have the EXTENDS flag set and place their base
117 // component first in the component descriptions, which is significant for
118 // the execution of FINAL subroutines.
119 class DerivedType {
120 public:
DerivedType(const char * n,std::size_t kps,std::size_t lps,const TypeParameter * tp,std::size_t cs,const Component * ca,std::size_t tbps,const TypeBoundProcedure * tbp,std::size_t sz)121   DerivedType(const char *n, std::size_t kps, std::size_t lps,
122       const TypeParameter *tp, std::size_t cs, const Component *ca,
123       std::size_t tbps, const TypeBoundProcedure *tbp, std::size_t sz)
124       : name_{n}, kindParameters_{kps}, lenParameters_{lps}, typeParameter_{tp},
125         components_{cs}, component_{ca}, typeBoundProcedures_{tbps},
126         typeBoundProcedure_{tbp}, bytes_{sz} {
127     if (IsNontrivialAnalysis()) {
128       flags_ |= NONTRIVIAL;
129     }
130   }
131 
name()132   const char *name() const { return name_; }
kindParameters()133   std::size_t kindParameters() const { return kindParameters_; }
lenParameters()134   std::size_t lenParameters() const { return lenParameters_; }
135 
136   // KIND type parameters come first.
typeParameter(int n)137   const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; }
138 
components()139   std::size_t components() const { return components_; }
140 
141   // The first few type-bound procedure indices are special.
142   enum SpecialTBP { InitializerTBP, CopierTBP, FinalTBP };
143 
typeBoundProcedures()144   std::size_t typeBoundProcedures() const { return typeBoundProcedures_; }
typeBoundProcedure(int n)145   const TypeBoundProcedure &typeBoundProcedure(int n) const {
146     return typeBoundProcedure_[n];
147   }
148 
set_sequence()149   DerivedType &set_sequence() {
150     flags_ |= SEQUENCE;
151     return *this;
152   }
set_bind_c()153   DerivedType &set_bind_c() {
154     flags_ |= BIND_C;
155     return *this;
156   }
157 
SizeInBytes()158   std::size_t SizeInBytes() const { return bytes_; }
Extends()159   bool Extends() const { return components_ > 0 && component_[0].IsParent(); }
160   bool AnyPrivate() const;
IsSequence()161   bool IsSequence() const { return (flags_ & SEQUENCE) != 0; }
IsBindC()162   bool IsBindC() const { return (flags_ & BIND_C) != 0; }
IsNontrivial()163   bool IsNontrivial() const { return (flags_ & NONTRIVIAL) != 0; }
164 
165   bool IsSameType(const DerivedType &) const;
166 
167   void Initialize(char *instance) const;
168   void Destroy(char *instance, bool finalize = true) const;
169 
170 private:
171   enum Flag { SEQUENCE = 1, BIND_C = 2, NONTRIVIAL = 4 };
172 
173   // True when any descriptor of data of this derived type will require
174   // an addendum pointing to a DerivedType, possibly with values of
175   // LEN type parameters.  Conservative.
176   bool IsNontrivialAnalysis() const;
177 
178   const char *name_{""}; // NUL-terminated constant text
179   std::size_t kindParameters_{0};
180   std::size_t lenParameters_{0};
181   const TypeParameter *typeParameter_{nullptr}; // array
182   std::size_t components_{0}; // *not* including type parameters
183   const Component *component_{nullptr}; // array
184   std::size_t typeBoundProcedures_{0};
185   const TypeBoundProcedure *typeBoundProcedure_{nullptr}; // array
186   std::uint64_t flags_{0};
187   std::size_t bytes_{0};
188 };
189 } // namespace Fortran::runtime
190 #endif // FORTRAN_RUNTIME_DERIVED_TYPE_H_
191