FLANG

derived-type.h
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:
28 const char *name() const { return name_; }
29 const TypeCode typeCode() const { return typeCode_; }
30
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.
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:
59 const char *name() const { return name_; }
60 TypeCode typeCode() const { return typeCode_; }
61 const Descriptor *staticDescriptor() const { return staticDescriptor_; }
62
63 bool IsParent() const { return (flags_ & PARENT) != 0; }
64 bool IsPrivate() const { return (flags_ & PRIVATE) != 0; }
65 bool IsDescriptor() const { return (flags_ & IS_DESCRIPTOR) != 0; }
66
67 template <typename A> A *Locate(char *dtInstance) const {
68 return reinterpret_cast<A *>(dtInstance + offset_);
69 }
70 template <typename A> const A *Locate(const char *dtInstance) const {
71 return reinterpret_cast<const A *>(dtInstance + offset_);
72 }
73
74 Descriptor *GetDescriptor(char *dtInstance) const {
75 if (IsDescriptor()) {
76 return Locate<Descriptor>(dtInstance);
77 } else {
78 return nullptr;
79 }
80 }
81
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 {
102 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:
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
132 const char *name() const { return name_; }
133 std::size_t kindParameters() const { return kindParameters_; }
134 std::size_t lenParameters() const { return lenParameters_; }
135
136 // KIND type parameters come first.
137 const TypeParameter &typeParameter(int n) const { return typeParameter_[n]; }
138
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
144 std::size_t typeBoundProcedures() const { return typeBoundProcedures_; }
145 const TypeBoundProcedure &typeBoundProcedure(int n) const {
146 return typeBoundProcedure_[n];
147 }
148
149 DerivedType &set_sequence() {
150 flags_ |= SEQUENCE;
151 return *this;
152 }
153 DerivedType &set_bind_c() {
154 flags_ |= BIND_C;
155 return *this;
156 }
157
158 std::size_t SizeInBytes() const { return bytes_; }
159 bool Extends() const { return components_ > 0 && component_[0].IsParent(); }
160 bool AnyPrivate() const;
161 bool IsSequence() const { return (flags_ & SEQUENCE) != 0; }
162 bool IsBindC() const { return (flags_ & BIND_C) != 0; }
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_
Fortran::runtime::TypeBoundProcedure
Definition: derived-type.h:109
Fortran::runtime::ExecutableCode
Definition: derived-type.h:101
Fortran::runtime::Component
Definition: derived-type.h:57
Fortran::runtime::DerivedType
Definition: derived-type.h:119
Fortran::runtime::Descriptor
Definition: descriptor.h:109
Fortran::runtime::TypeCode
Definition: type-code.h:19
Fortran::runtime::TypeParameter
Definition: derived-type.h:26