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