1 //===-- include/flang/Evaluate/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_EVALUATE_TYPE_H_
10 #define FORTRAN_EVALUATE_TYPE_H_
11
12 // These definitions map Fortran's intrinsic types, characterized by byte
13 // sizes encoded in KIND type parameter values, to their value representation
14 // types in the evaluation library, which are parameterized in terms of
15 // total bit width and real precision. Instances of the Type class template
16 // are suitable for use as template parameters to instantiate other class
17 // templates, like expressions, over the supported types and kinds.
18
19 #include "common.h"
20 #include "complex.h"
21 #include "formatting.h"
22 #include "integer.h"
23 #include "logical.h"
24 #include "real.h"
25 #include "flang/Common/Fortran.h"
26 #include "flang/Common/idioms.h"
27 #include "flang/Common/real.h"
28 #include "flang/Common/template.h"
29 #include <cinttypes>
30 #include <optional>
31 #include <string>
32 #include <type_traits>
33 #include <variant>
34
35 namespace Fortran::semantics {
36 class DeclTypeSpec;
37 class DerivedTypeSpec;
38 class ParamValue;
39 class Symbol;
40 bool IsDescriptor(const Symbol &);
41 } // namespace Fortran::semantics
42
43 namespace Fortran::evaluate {
44
45 using common::TypeCategory;
46
47 // Specific intrinsic types are represented by specializations of
48 // this class template Type<CATEGORY, KIND>.
49 template <TypeCategory CATEGORY, int KIND = 0> class Type;
50
51 using SubscriptInteger = Type<TypeCategory::Integer, 8>;
52 using CInteger = Type<TypeCategory::Integer, 4>;
53 using LogicalResult = Type<TypeCategory::Logical, 4>;
54 using LargestReal = Type<TypeCategory::Real, 16>;
55
56 // A predicate that is true when a kind value is a kind that could possibly
57 // be supported for an intrinsic type category on some target instruction
58 // set architecture.
59 // TODO: specialize for the actual target architecture
IsValidKindOfIntrinsicType(TypeCategory category,std::int64_t kind)60 static constexpr bool IsValidKindOfIntrinsicType(
61 TypeCategory category, std::int64_t kind) {
62 switch (category) {
63 case TypeCategory::Integer:
64 return kind == 1 || kind == 2 || kind == 4 || kind == 8 || kind == 16;
65 case TypeCategory::Real:
66 case TypeCategory::Complex:
67 return kind == 2 || kind == 3 || kind == 4 || kind == 8 || kind == 10 ||
68 kind == 16;
69 case TypeCategory::Character:
70 return kind == 1 || kind == 2 || kind == 4;
71 case TypeCategory::Logical:
72 return kind == 1 || kind == 2 || kind == 4 || kind == 8;
73 default:
74 return false;
75 }
76 }
77
78 // DynamicType is meant to be suitable for use as the result type for
79 // GetType() functions and member functions; consequently, it must be
80 // capable of being used in a constexpr context. So it does *not*
81 // directly hold anything requiring a destructor, such as an arbitrary
82 // CHARACTER length type parameter expression. Those must be derived
83 // via LEN() member functions, packaged elsewhere (e.g. as in
84 // ArrayConstructor), or copied from a parameter spec in the symbol table
85 // if one is supplied.
86 class DynamicType {
87 public:
DynamicType(TypeCategory cat,int k)88 constexpr DynamicType(TypeCategory cat, int k) : category_{cat}, kind_{k} {
89 CHECK(IsValidKindOfIntrinsicType(category_, kind_));
90 }
DynamicType(int k,const semantics::ParamValue & pv)91 constexpr DynamicType(int k, const semantics::ParamValue &pv)
92 : category_{TypeCategory::Character}, kind_{k}, charLength_{&pv} {
93 CHECK(IsValidKindOfIntrinsicType(category_, kind_));
94 }
95 explicit constexpr DynamicType(
96 const semantics::DerivedTypeSpec &dt, bool poly = false)
97 : category_{TypeCategory::Derived}, derived_{&dt} {
98 if (poly) {
99 kind_ = ClassKind;
100 }
101 }
CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(DynamicType)102 CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(DynamicType)
103
104 // A rare use case used for representing the characteristics of an
105 // intrinsic function like REAL() that accepts a typeless BOZ literal
106 // argument and for typeless pointers -- things that real user Fortran can't
107 // do.
108 static constexpr DynamicType TypelessIntrinsicArgument() {
109 DynamicType result;
110 result.category_ = TypeCategory::Integer;
111 result.kind_ = TypelessKind;
112 return result;
113 }
114
UnlimitedPolymorphic()115 static constexpr DynamicType UnlimitedPolymorphic() {
116 DynamicType result;
117 result.category_ = TypeCategory::Derived;
118 result.kind_ = ClassKind;
119 result.derived_ = nullptr;
120 return result; // CLASS(*)
121 }
122
AssumedType()123 static constexpr DynamicType AssumedType() {
124 DynamicType result;
125 result.category_ = TypeCategory::Derived;
126 result.kind_ = AssumedTypeKind;
127 result.derived_ = nullptr;
128 return result; // TYPE(*)
129 }
130
131 // Comparison is deep -- type parameters are compared independently.
132 bool operator==(const DynamicType &) const;
133 bool operator!=(const DynamicType &that) const { return !(*this == that); }
134
category()135 constexpr TypeCategory category() const { return category_; }
kind()136 constexpr int kind() const {
137 CHECK(kind_ > 0);
138 return kind_;
139 }
charLength()140 constexpr const semantics::ParamValue *charLength() const {
141 return charLength_;
142 }
143 std::optional<Expr<SubscriptInteger>> GetCharLength() const;
144
145 std::size_t GetAlignment(const FoldingContext &) const;
146 std::optional<Expr<SubscriptInteger>> MeasureSizeInBytes(
147 FoldingContext &, bool aligned) const;
148
149 std::string AsFortran() const;
150 std::string AsFortran(std::string &&charLenExpr) const;
151 DynamicType ResultTypeForMultiply(const DynamicType &) const;
152
153 bool IsAssumedLengthCharacter() const;
154 bool IsNonConstantLengthCharacter() const;
155 bool IsTypelessIntrinsicArgument() const;
IsAssumedType()156 constexpr bool IsAssumedType() const { // TYPE(*)
157 return kind_ == AssumedTypeKind;
158 }
IsPolymorphic()159 constexpr bool IsPolymorphic() const { // TYPE(*) or CLASS()
160 return kind_ == ClassKind || IsAssumedType();
161 }
IsUnlimitedPolymorphic()162 constexpr bool IsUnlimitedPolymorphic() const { // TYPE(*) or CLASS(*)
163 return IsPolymorphic() && !derived_;
164 }
GetDerivedTypeSpec()165 constexpr const semantics::DerivedTypeSpec &GetDerivedTypeSpec() const {
166 return DEREF(derived_);
167 }
168
169 bool RequiresDescriptor() const;
170 bool HasDeferredTypeParameter() const;
171
172 // 7.3.2.3 & 15.5.2.4 type compatibility.
173 // x.IsTkCompatibleWith(y) is true if "x => y" or passing actual y to
174 // dummy argument x would be valid. Be advised, this is not a reflexive
175 // relation. Kind type parameters must match.
176 bool IsTkCompatibleWith(const DynamicType &) const;
177
178 // Result will be missing when a symbol is absent or
179 // has an erroneous type, e.g., REAL(KIND=666).
180 static std::optional<DynamicType> From(const semantics::DeclTypeSpec &);
181 static std::optional<DynamicType> From(const semantics::Symbol &);
182
From(const A & x)183 template <typename A> static std::optional<DynamicType> From(const A &x) {
184 return x.GetType();
185 }
From(const A * p)186 template <typename A> static std::optional<DynamicType> From(const A *p) {
187 if (!p) {
188 return std::nullopt;
189 } else {
190 return From(*p);
191 }
192 }
193 template <typename A>
From(const std::optional<A> & x)194 static std::optional<DynamicType> From(const std::optional<A> &x) {
195 if (x) {
196 return From(*x);
197 } else {
198 return std::nullopt;
199 }
200 }
201
202 private:
203 // Special kind codes are used to distinguish the following Fortran types.
204 enum SpecialKind {
205 TypelessKind = -1, // BOZ actual argument to intrinsic function or pointer
206 // argument to ASSOCIATED
207 ClassKind = -2, // CLASS(T) or CLASS(*)
208 AssumedTypeKind = -3, // TYPE(*)
209 };
210
DynamicType()211 constexpr DynamicType() {}
212
213 TypeCategory category_{TypeCategory::Derived}; // overridable default
214 int kind_{0};
215 const semantics::ParamValue *charLength_{nullptr};
216 const semantics::DerivedTypeSpec *derived_{nullptr}; // TYPE(T), CLASS(T)
217 };
218
219 // Return the DerivedTypeSpec of a DynamicType if it has one.
220 const semantics::DerivedTypeSpec *GetDerivedTypeSpec(const DynamicType &);
221 const semantics::DerivedTypeSpec *GetDerivedTypeSpec(
222 const std::optional<DynamicType> &);
223 const semantics::DerivedTypeSpec *GetParentTypeSpec(
224 const semantics::DerivedTypeSpec &);
225
226 std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &);
227
228 template <TypeCategory CATEGORY, int KIND = 0> struct TypeBase {
229 static constexpr TypeCategory category{CATEGORY};
230 static constexpr int kind{KIND};
231 constexpr bool operator==(const TypeBase &) const { return true; }
GetTypeTypeBase232 static constexpr DynamicType GetType() { return {category, kind}; }
AsFortranTypeBase233 static std::string AsFortran() { return GetType().AsFortran(); }
234 };
235
236 template <int KIND>
237 class Type<TypeCategory::Integer, KIND>
238 : public TypeBase<TypeCategory::Integer, KIND> {
239 public:
240 using Scalar = value::Integer<8 * KIND>;
241 };
242
243 template <int KIND>
244 class Type<TypeCategory::Real, KIND>
245 : public TypeBase<TypeCategory::Real, KIND> {
246 public:
247 static constexpr int precision{common::PrecisionOfRealKind(KIND)};
248 static constexpr int bits{common::BitsForBinaryPrecision(precision)};
249 using Scalar = value::Real<value::Integer<bits>, precision>;
250 };
251
252 // The KIND type parameter on COMPLEX is the kind of each of its components.
253 template <int KIND>
254 class Type<TypeCategory::Complex, KIND>
255 : public TypeBase<TypeCategory::Complex, KIND> {
256 public:
257 using Part = Type<TypeCategory::Real, KIND>;
258 using Scalar = value::Complex<typename Part::Scalar>;
259 };
260
261 template <>
262 class Type<TypeCategory::Character, 1>
263 : public TypeBase<TypeCategory::Character, 1> {
264 public:
265 using Scalar = std::string;
266 };
267
268 template <>
269 class Type<TypeCategory::Character, 2>
270 : public TypeBase<TypeCategory::Character, 2> {
271 public:
272 using Scalar = std::u16string;
273 };
274
275 template <>
276 class Type<TypeCategory::Character, 4>
277 : public TypeBase<TypeCategory::Character, 4> {
278 public:
279 using Scalar = std::u32string;
280 };
281
282 template <int KIND>
283 class Type<TypeCategory::Logical, KIND>
284 : public TypeBase<TypeCategory::Logical, KIND> {
285 public:
286 using Scalar = value::Logical<8 * KIND>;
287 };
288
289 // Type functions
290
291 // Given a specific type, find the type of the same kind in another category.
292 template <TypeCategory CATEGORY, typename T>
293 using SameKind = Type<CATEGORY, std::decay_t<T>::kind>;
294
295 // Many expressions, including subscripts, CHARACTER lengths, array bounds,
296 // and effective type parameter values, are of a maximal kind of INTEGER.
297 using IndirectSubscriptIntegerExpr =
298 common::CopyableIndirection<Expr<SubscriptInteger>>;
299
300 // For each intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
301 // of std::tuple<Type<CAT, K>> that comprises every kind value K in that
302 // category that could possibly be supported on any target.
303 template <TypeCategory CATEGORY, int KIND>
304 using CategoryKindTuple =
305 std::conditional_t<IsValidKindOfIntrinsicType(CATEGORY, KIND),
306 std::tuple<Type<CATEGORY, KIND>>, std::tuple<>>;
307
308 template <TypeCategory CATEGORY, int... KINDS>
309 using CategoryTypesHelper =
310 common::CombineTuples<CategoryKindTuple<CATEGORY, KINDS>...>;
311
312 template <TypeCategory CATEGORY>
313 using CategoryTypes = CategoryTypesHelper<CATEGORY, 1, 2, 3, 4, 8, 10, 16, 32>;
314
315 using IntegerTypes = CategoryTypes<TypeCategory::Integer>;
316 using RealTypes = CategoryTypes<TypeCategory::Real>;
317 using ComplexTypes = CategoryTypes<TypeCategory::Complex>;
318 using CharacterTypes = CategoryTypes<TypeCategory::Character>;
319 using LogicalTypes = CategoryTypes<TypeCategory::Logical>;
320
321 using FloatingTypes = common::CombineTuples<RealTypes, ComplexTypes>;
322 using NumericTypes = common::CombineTuples<IntegerTypes, FloatingTypes>;
323 using RelationalTypes = common::CombineTuples<NumericTypes, CharacterTypes>;
324 using AllIntrinsicTypes = common::CombineTuples<RelationalTypes, LogicalTypes>;
325 using LengthlessIntrinsicTypes =
326 common::CombineTuples<NumericTypes, LogicalTypes>;
327
328 // Predicates: does a type represent a specific intrinsic type?
329 template <typename T>
330 constexpr bool IsSpecificIntrinsicType{common::HasMember<T, AllIntrinsicTypes>};
331
332 // Predicate: is a type an intrinsic type that is completely characterized
333 // by its category and kind parameter value, or might it have a derived type
334 // &/or a length type parameter?
335 template <typename T>
336 constexpr bool IsLengthlessIntrinsicType{
337 common::HasMember<T, LengthlessIntrinsicTypes>};
338
339 // Represents a type of any supported kind within a particular category.
340 template <TypeCategory CATEGORY> struct SomeKind {
341 static constexpr TypeCategory category{CATEGORY};
342 constexpr bool operator==(const SomeKind &) const { return true; }
AsFortranSomeKind343 static std::string AsFortran() {
344 return "Some"s + common::EnumToString(category);
345 }
346 };
347
348 using NumericCategoryTypes = std::tuple<SomeKind<TypeCategory::Integer>,
349 SomeKind<TypeCategory::Real>, SomeKind<TypeCategory::Complex>>;
350 using AllIntrinsicCategoryTypes = std::tuple<SomeKind<TypeCategory::Integer>,
351 SomeKind<TypeCategory::Real>, SomeKind<TypeCategory::Complex>,
352 SomeKind<TypeCategory::Character>, SomeKind<TypeCategory::Logical>>;
353
354 // Represents a completely generic type (or, for Expr<SomeType>, a typeless
355 // value like a BOZ literal or NULL() pointer).
356 struct SomeType {
AsFortranSomeType357 static std::string AsFortran() { return "SomeType"s; }
358 };
359
360 class StructureConstructor;
361
362 // Represents any derived type, polymorphic or not, as well as CLASS(*).
363 template <> class SomeKind<TypeCategory::Derived> {
364 public:
365 static constexpr TypeCategory category{TypeCategory::Derived};
366 using Scalar = StructureConstructor;
367
SomeKind()368 constexpr SomeKind() {} // CLASS(*)
SomeKind(const semantics::DerivedTypeSpec & dts)369 constexpr explicit SomeKind(const semantics::DerivedTypeSpec &dts)
370 : derivedTypeSpec_{&dts} {}
SomeKind(const DynamicType & dt)371 constexpr explicit SomeKind(const DynamicType &dt)
372 : SomeKind(dt.GetDerivedTypeSpec()) {}
CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(SomeKind)373 CONSTEXPR_CONSTRUCTORS_AND_ASSIGNMENTS(SomeKind)
374
375 bool IsUnlimitedPolymorphic() const { return !derivedTypeSpec_; }
GetType()376 constexpr DynamicType GetType() const {
377 if (!derivedTypeSpec_) {
378 return DynamicType::UnlimitedPolymorphic();
379 } else {
380 return DynamicType{*derivedTypeSpec_};
381 }
382 }
derivedTypeSpec()383 const semantics::DerivedTypeSpec &derivedTypeSpec() const {
384 CHECK(derivedTypeSpec_);
385 return *derivedTypeSpec_;
386 }
387 bool operator==(const SomeKind &) const;
388 std::string AsFortran() const;
389
390 private:
391 const semantics::DerivedTypeSpec *derivedTypeSpec_{nullptr};
392 };
393
394 using SomeInteger = SomeKind<TypeCategory::Integer>;
395 using SomeReal = SomeKind<TypeCategory::Real>;
396 using SomeComplex = SomeKind<TypeCategory::Complex>;
397 using SomeCharacter = SomeKind<TypeCategory::Character>;
398 using SomeLogical = SomeKind<TypeCategory::Logical>;
399 using SomeDerived = SomeKind<TypeCategory::Derived>;
400 using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex,
401 SomeCharacter, SomeLogical, SomeDerived>;
402
403 using AllTypes =
404 common::CombineTuples<AllIntrinsicTypes, std::tuple<SomeDerived>>;
405
406 template <typename T> using Scalar = typename std::decay_t<T>::Scalar;
407
408 // When Scalar<T> is S, then TypeOf<S> is T.
409 // TypeOf is implemented by scanning all supported types for a match
410 // with Type<T>::Scalar.
411 template <typename CONST> struct TypeOfHelper {
412 template <typename T> struct Predicate {
valueTypeOfHelper::Predicate413 static constexpr bool value() {
414 return std::is_same_v<std::decay_t<CONST>,
415 std::decay_t<typename T::Scalar>>;
416 }
417 };
418 static constexpr int index{
419 common::SearchMembers<Predicate, AllIntrinsicTypes>};
420 using type = std::conditional_t<index >= 0,
421 std::tuple_element_t<index, AllIntrinsicTypes>, void>;
422 };
423
424 template <typename CONST> using TypeOf = typename TypeOfHelper<CONST>::type;
425
426 int SelectedCharKind(const std::string &, int defaultKind);
427 int SelectedIntKind(std::int64_t precision = 0);
428 int SelectedRealKind(
429 std::int64_t precision = 0, std::int64_t range = 0, std::int64_t radix = 2);
430
431 // For generating "[extern] template class", &c. boilerplate
432 #define EXPAND_FOR_EACH_INTEGER_KIND(M, P, S) \
433 M(P, S, 1) M(P, S, 2) M(P, S, 4) M(P, S, 8) M(P, S, 16)
434 #define EXPAND_FOR_EACH_REAL_KIND(M, P, S) \
435 M(P, S, 2) M(P, S, 3) M(P, S, 4) M(P, S, 8) M(P, S, 10) M(P, S, 16)
436 #define EXPAND_FOR_EACH_COMPLEX_KIND(M, P, S) EXPAND_FOR_EACH_REAL_KIND(M, P, S)
437 #define EXPAND_FOR_EACH_CHARACTER_KIND(M, P, S) M(P, S, 1) M(P, S, 2) M(P, S, 4)
438 #define EXPAND_FOR_EACH_LOGICAL_KIND(M, P, S) \
439 M(P, S, 1) M(P, S, 2) M(P, S, 4) M(P, S, 8)
440 #define TEMPLATE_INSTANTIATION(P, S, ARG) P<ARG> S;
441
442 #define FOR_EACH_INTEGER_KIND_HELP(PREFIX, SUFFIX, K) \
443 PREFIX<Type<TypeCategory::Integer, K>> SUFFIX;
444 #define FOR_EACH_REAL_KIND_HELP(PREFIX, SUFFIX, K) \
445 PREFIX<Type<TypeCategory::Real, K>> SUFFIX;
446 #define FOR_EACH_COMPLEX_KIND_HELP(PREFIX, SUFFIX, K) \
447 PREFIX<Type<TypeCategory::Complex, K>> SUFFIX;
448 #define FOR_EACH_CHARACTER_KIND_HELP(PREFIX, SUFFIX, K) \
449 PREFIX<Type<TypeCategory::Character, K>> SUFFIX;
450 #define FOR_EACH_LOGICAL_KIND_HELP(PREFIX, SUFFIX, K) \
451 PREFIX<Type<TypeCategory::Logical, K>> SUFFIX;
452
453 #define FOR_EACH_INTEGER_KIND(PREFIX, SUFFIX) \
454 EXPAND_FOR_EACH_INTEGER_KIND(FOR_EACH_INTEGER_KIND_HELP, PREFIX, SUFFIX)
455 #define FOR_EACH_REAL_KIND(PREFIX, SUFFIX) \
456 EXPAND_FOR_EACH_REAL_KIND(FOR_EACH_REAL_KIND_HELP, PREFIX, SUFFIX)
457 #define FOR_EACH_COMPLEX_KIND(PREFIX, SUFFIX) \
458 EXPAND_FOR_EACH_COMPLEX_KIND(FOR_EACH_COMPLEX_KIND_HELP, PREFIX, SUFFIX)
459 #define FOR_EACH_CHARACTER_KIND(PREFIX, SUFFIX) \
460 EXPAND_FOR_EACH_CHARACTER_KIND(FOR_EACH_CHARACTER_KIND_HELP, PREFIX, SUFFIX)
461 #define FOR_EACH_LOGICAL_KIND(PREFIX, SUFFIX) \
462 EXPAND_FOR_EACH_LOGICAL_KIND(FOR_EACH_LOGICAL_KIND_HELP, PREFIX, SUFFIX)
463
464 #define FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \
465 FOR_EACH_INTEGER_KIND(PREFIX, SUFFIX) \
466 FOR_EACH_REAL_KIND(PREFIX, SUFFIX) \
467 FOR_EACH_COMPLEX_KIND(PREFIX, SUFFIX) \
468 FOR_EACH_LOGICAL_KIND(PREFIX, SUFFIX)
469 #define FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
470 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX, SUFFIX) \
471 FOR_EACH_CHARACTER_KIND(PREFIX, SUFFIX)
472 #define FOR_EACH_SPECIFIC_TYPE(PREFIX, SUFFIX) \
473 FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
474 PREFIX<SomeDerived> SUFFIX;
475
476 #define FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX) \
477 PREFIX<SomeInteger> SUFFIX; \
478 PREFIX<SomeReal> SUFFIX; \
479 PREFIX<SomeComplex> SUFFIX; \
480 PREFIX<SomeCharacter> SUFFIX; \
481 PREFIX<SomeLogical> SUFFIX; \
482 PREFIX<SomeDerived> SUFFIX; \
483 PREFIX<SomeType> SUFFIX;
484 #define FOR_EACH_TYPE_AND_KIND(PREFIX, SUFFIX) \
485 FOR_EACH_INTRINSIC_KIND(PREFIX, SUFFIX) \
486 FOR_EACH_CATEGORY_TYPE(PREFIX, SUFFIX)
487 } // namespace Fortran::evaluate
488 #endif // FORTRAN_EVALUATE_TYPE_H_
489