Warning: This file is not a C or C++ file. It does not have highlighting.

1//===-- Optimizer/Dialect/FIRType.h -- FIR types ----------------*- 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// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H
14#define FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H
15
16#include "mlir/IR/BuiltinAttributes.h"
17#include "mlir/IR/BuiltinTypes.h"
18#include "mlir/Interfaces/DataLayoutInterfaces.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/IR/Type.h"
21
22namespace fir {
23class FIROpsDialect;
24class KindMapping;
25using KindTy = unsigned;
26
27namespace detail {
28struct RecordTypeStorage;
29} // namespace detail
30
31} // namespace fir
32
33//===----------------------------------------------------------------------===//
34// BaseBoxType
35//===----------------------------------------------------------------------===//
36
37namespace fir {
38
39/// This class provides a shared interface for box and class types.
40class BaseBoxType : public mlir::Type {
41public:
42 using mlir::Type::Type;
43
44 /// Box attributes.
45 enum class Attribute { None, Allocatable, Pointer };
46
47 /// Returns the element type of this box type.
48 mlir::Type getEleTy() const;
49
50 /// Get the raw address type of the memory described by the box.
51 mlir::Type getBaseAddressType() const;
52
53 /// Unwrap element type from fir.heap, fir.ptr and fir.array.
54 mlir::Type unwrapInnerType() const;
55
56 /// Is this the box for an assumed rank?
57 bool isAssumedRank() const;
58
59 /// Is this a box for a pointer?
60 bool isPointer() const;
61
62 /// Does this box for a pointer or allocatable?
63 bool isPointerOrAllocatable() const;
64
65 /// Is this a box describing volatile memory?
66 bool isVolatile() const;
67
68 /// Return the same type, except for the shape, that is taken the shape
69 /// of shapeMold.
70 BaseBoxType getBoxTypeWithNewShape(mlir::Type shapeMold) const;
71 BaseBoxType getBoxTypeWithNewShape(int rank) const;
72
73 /// Return the same type, except for the attribute (fir.heap/fir.ptr).
74 BaseBoxType getBoxTypeWithNewAttr(Attribute attr) const;
75
76 /// Methods for support type inquiry through isa, cast, and dyn_cast.
77 static bool classof(mlir::Type type);
78};
79
80} // namespace fir
81
82#define GET_TYPEDEF_CLASSES
83#include "flang/Optimizer/Dialect/FIROpsTypes.h.inc"
84
85namespace llvm {
86class raw_ostream;
87class StringRef;
88template <typename>
89class ArrayRef;
90class hash_code;
91} // namespace llvm
92
93namespace mlir {
94class DialectAsmParser;
95class DialectAsmPrinter;
96class ComplexType;
97class FloatType;
98class ValueRange;
99} // namespace mlir
100
101namespace fir {
102namespace detail {
103struct RecordTypeStorage;
104} // namespace detail
105
106// These isa_ routines follow the precedent of llvm::isa_or_null<>
107
108/// Is `t` any of the FIR dialect types?
109bool isa_fir_type(mlir::Type t);
110
111/// Is `t` any of the Standard dialect types?
112bool isa_std_type(mlir::Type t);
113
114/// Is `t` any of the FIR dialect or Standard dialect types?
115bool isa_fir_or_std_type(mlir::Type t);
116
117/// Is `t` a FIR dialect type that implies a memory (de)reference?
118inline bool isa_ref_type(mlir::Type t) {
119 return mlir::isa<fir::ReferenceType, fir::PointerType, fir::HeapType,
120 fir::LLVMPointerType>(t);
121}
122
123/// Is `t` a boxed type?
124inline bool isa_box_type(mlir::Type t) {
125 return mlir::isa<fir::BaseBoxType, fir::BoxCharType, fir::BoxProcType>(t);
126}
127
128/// Is `t` a type that is always trivially pass-by-reference? Specifically, this
129/// is testing if `t` is a ReferenceType or any box type. Compare this to
130/// conformsWithPassByRef(), which includes pointers and allocatables.
131inline bool isa_passbyref_type(mlir::Type t) {
132 return mlir::isa<fir::ReferenceType, mlir::FunctionType>(t) ||
133 isa_box_type(t);
134}
135
136/// Is `t` a type that can conform to be pass-by-reference? Depending on the
137/// context, these types may simply demote to pass-by-reference or a reference
138/// to them may have to be passed instead. Functions are always referent.
139inline bool conformsWithPassByRef(mlir::Type t) {
140 return isa_ref_type(t) || isa_box_type(t) || mlir::isa<mlir::FunctionType>(t);
141}
142
143/// Is `t` a derived (record) type?
144inline bool isa_derived(mlir::Type t) { return mlir::isa<fir::RecordType>(t); }
145
146/// Is `t` type(c_ptr) or type(c_funptr)?
147inline bool isa_builtin_cptr_type(mlir::Type t) {
148 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t))
149 return recTy.getName().ends_with("T__builtin_c_ptr") ||
150 recTy.getName().ends_with("T__builtin_c_funptr");
151 return false;
152}
153
154// Is `t` type(c_devptr)?
155inline bool isa_builtin_c_devptr_type(mlir::Type t) {
156 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t))
157 return recTy.getName().ends_with("T__builtin_c_devptr");
158 return false;
159}
160
161/// Is `t` type(c_devptr)?
162inline bool isa_builtin_cdevptr_type(mlir::Type t) {
163 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(t))
164 return recTy.getName().ends_with("T__builtin_c_devptr");
165 return false;
166}
167
168/// Is `t` a FIR dialect aggregate type?
169inline bool isa_aggregate(mlir::Type t) {
170 return mlir::isa<SequenceType, mlir::TupleType>(t) || fir::isa_derived(t);
171}
172
173/// Extract the `Type` pointed to from a FIR memory reference type. If `t` is
174/// not a memory reference type, then returns a null `Type`.
175mlir::Type dyn_cast_ptrEleTy(mlir::Type t);
176
177/// Extract the `Type` pointed to from a FIR memory reference or box type. If
178/// `t` is not a memory reference or box type, then returns a null `Type`.
179mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t);
180
181/// Is `t` a real type?
182inline bool isa_real(mlir::Type t) { return mlir::isa<mlir::FloatType>(t); }
183
184/// Is `t` an integral type?
185inline bool isa_integer(mlir::Type t) {
186 return mlir::isa<mlir::IndexType, mlir::IntegerType, fir::IntegerType>(t);
187}
188
189/// Is `t` a vector type?
190inline bool isa_vector(mlir::Type t) {
191 return mlir::isa<mlir::VectorType, fir::VectorType>(t);
192}
193
194mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser);
195
196void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p);
197
198/// Guarantee `type` is a scalar integral type (standard Integer, standard
199/// Index, or FIR Int). Aborts execution if condition is false.
200void verifyIntegralType(mlir::Type type);
201
202/// Is `t` a floating point complex type?
203inline bool isa_complex(mlir::Type t) {
204 return mlir::isa<mlir::ComplexType>(t) &&
205 mlir::isa<mlir::FloatType>(
206 mlir::cast<mlir::ComplexType>(t).getElementType());
207}
208
209/// Is `t` a CHARACTER type? Does not check the length.
210inline bool isa_char(mlir::Type t) { return mlir::isa<fir::CharacterType>(t); }
211
212/// Is `t` a trivial intrinsic type? CHARACTER is <em>excluded</em> because it
213/// is a dependent type.
214inline bool isa_trivial(mlir::Type t) {
215 return isa_integer(t) || isa_real(t) || isa_complex(t) || isa_vector(t) ||
216 mlir::isa<fir::LogicalType>(t);
217}
218
219/// Is `t` a CHARACTER type with a LEN other than 1?
220inline bool isa_char_string(mlir::Type t) {
221 if (auto ct = mlir::dyn_cast_or_null<fir::CharacterType>(t))
222 return ct.getLen() != fir::CharacterType::singleton();
223 return false;
224}
225
226/// Is `t` a box type for which it is not possible to deduce the box size?
227/// It is not possible to deduce the size of a box that describes an entity
228/// of unknown rank.
229/// Unknown type are always considered to have the size of derived type box
230/// (since they may hold one), and are not considered to be unknown size.
231bool isa_unknown_size_box(mlir::Type t);
232
233/// Returns true iff `t` is a type capable of representing volatility and has
234/// the volatile attribute set.
235bool isa_volatile_type(mlir::Type t);
236
237/// Returns true iff `t` is a fir.char type and has an unknown length.
238inline bool characterWithDynamicLen(mlir::Type t) {
239 if (auto charTy = mlir::dyn_cast<fir::CharacterType>(t))
240 return charTy.hasDynamicLen();
241 return false;
242}
243
244/// Returns true iff `seqTy` has either an unknown shape or a non-constant shape
245/// (where rank > 0).
246inline bool sequenceWithNonConstantShape(fir::SequenceType seqTy) {
247 return seqTy.hasUnknownShape() || seqTy.hasDynamicExtents();
248}
249
250/// Returns true iff the type `t` does not have a constant size.
251bool hasDynamicSize(mlir::Type t);
252
253inline unsigned getRankOfShapeType(mlir::Type t) {
254 if (auto shTy = mlir::dyn_cast<fir::ShapeType>(t))
255 return shTy.getRank();
256 if (auto shTy = mlir::dyn_cast<fir::ShapeShiftType>(t))
257 return shTy.getRank();
258 if (auto shTy = mlir::dyn_cast<fir::ShiftType>(t))
259 return shTy.getRank();
260 return 0;
261}
262
263/// Get the memory reference type of the data pointer from the box type,
264inline mlir::Type boxMemRefType(fir::BaseBoxType t) {
265 auto eleTy = t.getEleTy();
266 if (!mlir::isa<fir::PointerType, fir::HeapType>(eleTy))
267 eleTy = fir::ReferenceType::get(t);
268 return eleTy;
269}
270
271/// If `t` is a SequenceType return its element type, otherwise return `t`.
272inline mlir::Type unwrapSequenceType(mlir::Type t) {
273 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(t))
274 return seqTy.getEleTy();
275 return t;
276}
277
278/// Return the nested sequence type if any.
279mlir::Type extractSequenceType(mlir::Type ty);
280
281inline mlir::Type unwrapRefType(mlir::Type t) {
282 if (auto eleTy = dyn_cast_ptrEleTy(t))
283 return eleTy;
284 return t;
285}
286
287/// If `t` conforms with a pass-by-reference type (box, ref, ptr, etc.) then
288/// return the element type of `t`. Otherwise, return `t`.
289inline mlir::Type unwrapPassByRefType(mlir::Type t) {
290 if (auto eleTy = dyn_cast_ptrOrBoxEleTy(t))
291 return eleTy;
292 return t;
293}
294
295/// Extracts the innermost type, T, **potentially** wrapped inside:
296/// <fir.[ref|ptr|heap] <fir.[ref|ptr|heap|box] <fir.array<T>>>
297///
298/// Any element absent from the above pattern does not affect the returned
299/// value: T.
300mlir::Type getFortranElementType(mlir::Type ty);
301
302/// Unwrap either a sequence or a boxed sequence type, returning the element
303/// type of the sequence type.
304/// e.g.,
305/// !fir.array<...xT> -> T
306/// !fir.box<!fir.ptr<!fir.array<...xT>>> -> T
307/// otherwise
308/// T -> T
309mlir::Type unwrapSeqOrBoxedSeqType(mlir::Type ty);
310
311/// Unwrap all referential and sequential outer types (if any). Returns the
312/// element type. This is useful for determining the element type of any object
313/// memory reference, whether it is a single instance or a series of instances.
314mlir::Type unwrapAllRefAndSeqType(mlir::Type ty);
315
316/// Unwrap all pointer and box types and return the element type if it is a
317/// sequence type, otherwise return null.
318inline fir::SequenceType unwrapUntilSeqType(mlir::Type t) {
319 while (true) {
320 if (!t)
321 return {};
322 if (auto ty = dyn_cast_ptrOrBoxEleTy(t)) {
323 t = ty;
324 continue;
325 }
326 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(t))
327 return seqTy;
328 return {};
329 }
330}
331
332/// Unwrap the referential and sequential outer types (if any). Returns the
333/// the element if type is fir::RecordType
334inline fir::RecordType unwrapIfDerived(fir::BaseBoxType boxTy) {
335 return mlir::dyn_cast<fir::RecordType>(
336 fir::unwrapSequenceType(fir::unwrapRefType(boxTy.getEleTy())));
337}
338
339/// Return true iff `boxTy` wraps a fir::RecordType with length parameters
340inline bool isDerivedTypeWithLenParams(fir::BaseBoxType boxTy) {
341 auto recTy = unwrapIfDerived(boxTy);
342 return recTy && recTy.getNumLenParams() > 0;
343}
344
345/// Return true iff `boxTy` wraps a fir::RecordType
346inline bool isDerivedType(fir::BaseBoxType boxTy) {
347 return static_cast<bool>(unwrapIfDerived(boxTy));
348}
349
350#ifndef NDEBUG
351// !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref
352// is undefined and disallowed.
353inline bool singleIndirectionLevel(mlir::Type ty) {
354 return !fir::isa_ref_type(ty);
355}
356#endif
357
358/// Return true iff `ty` is the type of a POINTER entity or value.
359/// `isa_ref_type()` can be used to distinguish.
360bool isPointerType(mlir::Type ty);
361
362/// Return true iff `ty` is the type of an ALLOCATABLE entity or value.
363bool isAllocatableType(mlir::Type ty);
364
365/// Return true iff `ty` is !fir.box<none>.
366bool isBoxNone(mlir::Type ty);
367
368/// Return true iff `ty` is the type of a boxed record type.
369/// e.g. !fir.box<!fir.type<derived>>
370bool isBoxedRecordType(mlir::Type ty);
371
372/// Return true iff `ty` is a type that contains descriptor information.
373bool isTypeWithDescriptor(mlir::Type ty);
374
375/// Return true iff `ty` is a scalar boxed record type.
376/// e.g. !fir.box<!fir.type<derived>>
377/// !fir.box<!fir.heap<!fir.type<derived>>>
378/// !fir.class<!fir.type<derived>>
379bool isScalarBoxedRecordType(mlir::Type ty);
380
381/// Return the nested RecordType if one if found. Return ty otherwise.
382mlir::Type getDerivedType(mlir::Type ty);
383
384/// Return true iff `ty` is the type of an polymorphic entity or
385/// value.
386bool isPolymorphicType(mlir::Type ty);
387
388/// Return true iff `ty` is the type of an unlimited polymorphic entity or
389/// value.
390bool isUnlimitedPolymorphicType(mlir::Type ty);
391
392/// Return true iff `ty` is the type of an assumed type. In FIR,
393/// assumed types are of the form `[fir.ref|ptr|heap]fir.box<[fir.array]none>`,
394/// or `fir.ref|ptr|heap<[fir.array]none>`.
395bool isAssumedType(mlir::Type ty);
396
397/// Return true iff `ty` is the type of an assumed shape array.
398bool isAssumedShape(mlir::Type ty);
399
400/// Return true iff `ty` is the type of an allocatable array.
401bool isAllocatableOrPointerArray(mlir::Type ty);
402
403/// Return true iff `boxTy` wraps a record type or an unlimited polymorphic
404/// entity. Polymorphic entities with intrinsic type spec do not have addendum
405inline bool boxHasAddendum(fir::BaseBoxType boxTy) {
406 return static_cast<bool>(unwrapIfDerived(boxTy)) ||
407 fir::isUnlimitedPolymorphicType(boxTy);
408}
409
410/// Get the rank from a !fir.box type.
411unsigned getBoxRank(mlir::Type boxTy);
412
413/// Return the inner type of the given type.
414mlir::Type unwrapInnerType(mlir::Type ty);
415
416/// Return true iff `ty` is a RecordType with members that are allocatable.
417bool isRecordWithAllocatableMember(mlir::Type ty);
418
419/// Return true iff `ty` is a scalar/array of RecordType
420/// with members that are descriptors.
421bool isRecordWithDescriptorMember(mlir::Type ty);
422
423/// Return true iff `ty` is a RecordType with type parameters.
424inline bool isRecordWithTypeParameters(mlir::Type ty) {
425 if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(ty))
426 return recTy.isDependentType();
427 return false;
428}
429
430/// Is this tuple type holding a character function and its result length?
431bool isCharacterProcedureTuple(mlir::Type type, bool acceptRawFunc = true);
432
433/// Apply the components specified by `path` to `rootTy` to determine the type
434/// of the resulting component element. `rootTy` should be an aggregate type.
435/// Returns null on error.
436mlir::Type applyPathToType(mlir::Type rootTy, mlir::ValueRange path);
437
438/// Does this function type has a result that requires binding the result value
439/// with a storage in a fir.save_result operation in order to use the result?
440bool hasAbstractResult(mlir::FunctionType ty);
441
442/// Convert llvm::Type::TypeID to mlir::Type
443mlir::Type fromRealTypeID(mlir::MLIRContext *context, llvm::Type::TypeID typeID,
444 fir::KindTy kind);
445
446int getTypeCode(mlir::Type ty, const KindMapping &kindMap);
447
448inline bool BaseBoxType::classof(mlir::Type type) {
449 return mlir::isa<fir::BoxType, fir::ClassType>(type);
450}
451
452/// Return true iff `ty` is none or fir.array<none>.
453inline bool isNoneOrSeqNone(mlir::Type type) {
454 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type))
455 return mlir::isa<mlir::NoneType>(seqTy.getEleTy());
456 return mlir::isa<mlir::NoneType>(type);
457}
458
459/// Return a fir.box<T> or fir.class<T> if the type is polymorphic. If the type
460/// is polymorphic and assumed shape return fir.box<T>.
461inline mlir::Type wrapInClassOrBoxType(mlir::Type eleTy,
462 bool isPolymorphic = false,
463 bool isAssumedType = false) {
464 if (isPolymorphic && !isAssumedType)
465 return fir::ClassType::get(eleTy);
466 return fir::BoxType::get(eleTy);
467}
468
469/// Re-create the given type with the given volatility, if this is a type
470/// that can represent volatility.
471mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile);
472
473/// Return the elementType where intrinsic types are replaced with none for
474/// unlimited polymorphic entities.
475///
476/// i32 -> ()
477/// !fir.array<2xf32> -> !fir.array<2xnone>
478/// !fir.heap<!fir.array<2xf32>> -> !fir.heap<!fir.array<2xnone>>
479inline mlir::Type updateTypeForUnlimitedPolymorphic(mlir::Type ty) {
480 if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty))
481 return fir::SequenceType::get(
482 seqTy.getShape(), updateTypeForUnlimitedPolymorphic(seqTy.getEleTy()));
483 if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty))
484 return fir::HeapType::get(
485 updateTypeForUnlimitedPolymorphic(heapTy.getEleTy()));
486 if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty))
487 return fir::PointerType::get(
488 updateTypeForUnlimitedPolymorphic(pointerTy.getEleTy()));
489 if (!mlir::isa<mlir::NoneType, fir::RecordType>(ty))
490 return mlir::NoneType::get(ty.getContext());
491 return ty;
492}
493
494/// Re-create the given type with the given volatility, if this is a type
495/// that can represent volatility.
496mlir::Type updateTypeWithVolatility(mlir::Type type, bool isVolatile);
497
498/// Replace the element type of \p type by \p newElementType, preserving
499/// all other layers of the type (fir.ref/ptr/heap/array/box/class).
500/// If \p turnBoxIntoClass and the input is a fir.box, it will be turned into
501/// a fir.class in the result.
502mlir::Type changeElementType(mlir::Type type, mlir::Type newElementType,
503 bool turnBoxIntoClass);
504
505/// Is `t` an address to fir.box or class type?
506inline bool isBoxAddress(mlir::Type t) {
507 return fir::isa_ref_type(t) &&
508 mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(t));
509}
510
511/// Is `t` a fir.box or class address or value type?
512inline bool isBoxAddressOrValue(mlir::Type t) {
513 return mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(t));
514}
515
516/// Is this a fir.boxproc address type?
517inline bool isBoxProcAddressType(mlir::Type t) {
518 t = fir::dyn_cast_ptrEleTy(t);
519 return t && mlir::isa<fir::BoxProcType>(t);
520}
521
522inline bool isRefOfConstantSizeAggregateType(mlir::Type t) {
523 t = fir::dyn_cast_ptrEleTy(t);
524 return t &&
525 mlir::isa<fir::CharacterType, fir::RecordType, fir::SequenceType>(t) &&
526 !hasDynamicSize(t);
527}
528
529/// Return a string representation of `ty`.
530///
531/// fir.array<10x10xf32> -> prefix_10x10xf32
532/// fir.ref<i32> -> prefix_ref_i32
533std::string getTypeAsString(mlir::Type ty, const KindMapping &kindMap,
534 llvm::StringRef prefix = "");
535
536/// Return the size and alignment of FIR types.
537/// TODO: consider moving this to a DataLayoutTypeInterface implementation
538/// for FIR types. It should first be ensured that it is OK to open the gate of
539/// target dependent type size inquiries in lowering. It would also not be
540/// straightforward given the need for a kind map that would need to be
541/// converted in terms of mlir::DataLayoutEntryKey.
542
543/// This variant terminates the compilation if an unsupported type is passed.
544std::pair<std::uint64_t, unsigned short>
545getTypeSizeAndAlignmentOrCrash(mlir::Location loc, mlir::Type ty,
546 const mlir::DataLayout &dl,
547 const fir::KindMapping &kindMap);
548
549/// This variant returns std::nullopt if an unsupported type is passed.
550std::optional<std::pair<uint64_t, unsigned short>>
551getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
552 const mlir::DataLayout &dl,
553 const fir::KindMapping &kindMap);
554} // namespace fir
555
556#endif // FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H
557

Warning: This file is not a C or C++ file. It does not have highlighting.

source code of flang/include/flang/Optimizer/Dialect/FIRType.h