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 "llvm/ADT/SmallVector.h"
19 #include "llvm/IR/Type.h"
20 
21 namespace fir {
22 class FIROpsDialect;
23 class KindMapping;
24 using KindTy = unsigned;
25 } // namespace fir
26 
27 #define GET_TYPEDEF_CLASSES
28 #include "flang/Optimizer/Dialect/FIROpsTypes.h.inc"
29 
30 namespace llvm {
31 class raw_ostream;
32 class StringRef;
33 template <typename>
34 class ArrayRef;
35 class hash_code;
36 } // namespace llvm
37 
38 namespace mlir {
39 class DialectAsmParser;
40 class DialectAsmPrinter;
41 class ComplexType;
42 class FloatType;
43 class ValueRange;
44 } // namespace mlir
45 
46 namespace fir {
47 namespace detail {
48 struct RecordTypeStorage;
49 } // namespace detail
50 
51 // These isa_ routines follow the precedent of llvm::isa_or_null<>
52 
53 /// Is `t` any of the FIR dialect types?
54 bool isa_fir_type(mlir::Type t);
55 
56 /// Is `t` any of the Standard dialect types?
57 bool isa_std_type(mlir::Type t);
58 
59 /// Is `t` any of the FIR dialect or Standard dialect types?
60 bool isa_fir_or_std_type(mlir::Type t);
61 
62 /// Is `t` a FIR dialect type that implies a memory (de)reference?
isa_ref_type(mlir::Type t)63 inline bool isa_ref_type(mlir::Type t) {
64   return t.isa<fir::ReferenceType, fir::PointerType, fir::HeapType,
65                fir::LLVMPointerType>();
66 }
67 
68 /// Is `t` a boxed type?
isa_box_type(mlir::Type t)69 inline bool isa_box_type(mlir::Type t) {
70   return t.isa<fir::BoxType, fir::BoxCharType, fir::BoxProcType>();
71 }
72 
73 /// Is `t` a type that is always trivially pass-by-reference? Specifically, this
74 /// is testing if `t` is a ReferenceType or any box type. Compare this to
75 /// conformsWithPassByRef(), which includes pointers and allocatables.
isa_passbyref_type(mlir::Type t)76 inline bool isa_passbyref_type(mlir::Type t) {
77   return t.isa<fir::ReferenceType, mlir::FunctionType>() || isa_box_type(t);
78 }
79 
80 /// Is `t` a type that can conform to be pass-by-reference? Depending on the
81 /// context, these types may simply demote to pass-by-reference or a reference
82 /// to them may have to be passed instead. Functions are always referent.
conformsWithPassByRef(mlir::Type t)83 inline bool conformsWithPassByRef(mlir::Type t) {
84   return isa_ref_type(t) || isa_box_type(t) || t.isa<mlir::FunctionType>();
85 }
86 
87 /// Is `t` a derived (record) type?
isa_derived(mlir::Type t)88 inline bool isa_derived(mlir::Type t) { return t.isa<fir::RecordType>(); }
89 
90 /// Is `t` a FIR dialect aggregate type?
isa_aggregate(mlir::Type t)91 inline bool isa_aggregate(mlir::Type t) {
92   return t.isa<SequenceType, mlir::TupleType>() || fir::isa_derived(t);
93 }
94 
95 /// Extract the `Type` pointed to from a FIR memory reference type. If `t` is
96 /// not a memory reference type, then returns a null `Type`.
97 mlir::Type dyn_cast_ptrEleTy(mlir::Type t);
98 
99 /// Extract the `Type` pointed to from a FIR memory reference or box type. If
100 /// `t` is not a memory reference or box type, then returns a null `Type`.
101 mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t);
102 
103 /// Is `t` a FIR Real or MLIR Float type?
isa_real(mlir::Type t)104 inline bool isa_real(mlir::Type t) {
105   return t.isa<fir::RealType, mlir::FloatType>();
106 }
107 
108 /// Is `t` an integral type?
isa_integer(mlir::Type t)109 inline bool isa_integer(mlir::Type t) {
110   return t.isa<mlir::IndexType, mlir::IntegerType, fir::IntegerType>();
111 }
112 
113 mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser);
114 
115 void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p);
116 
117 /// Guarantee `type` is a scalar integral type (standard Integer, standard
118 /// Index, or FIR Int). Aborts execution if condition is false.
119 void verifyIntegralType(mlir::Type type);
120 
121 /// Is `t` a FIR or MLIR Complex type?
isa_complex(mlir::Type t)122 inline bool isa_complex(mlir::Type t) {
123   return t.isa<fir::ComplexType, mlir::ComplexType>();
124 }
125 
126 /// Is `t` a CHARACTER type? Does not check the length.
isa_char(mlir::Type t)127 inline bool isa_char(mlir::Type t) { return t.isa<fir::CharacterType>(); }
128 
129 /// Is `t` a trivial intrinsic type? CHARACTER is <em>excluded</em> because it
130 /// is a dependent type.
isa_trivial(mlir::Type t)131 inline bool isa_trivial(mlir::Type t) {
132   return isa_integer(t) || isa_real(t) || isa_complex(t) ||
133          t.isa<fir::LogicalType>();
134 }
135 
136 /// Is `t` a CHARACTER type with a LEN other than 1?
isa_char_string(mlir::Type t)137 inline bool isa_char_string(mlir::Type t) {
138   if (auto ct = t.dyn_cast_or_null<fir::CharacterType>())
139     return ct.getLen() != fir::CharacterType::singleton();
140   return false;
141 }
142 
143 /// Is `t` a box type for which it is not possible to deduce the box size?
144 /// It is not possible to deduce the size of a box that describes an entity
145 /// of unknown rank or type.
146 bool isa_unknown_size_box(mlir::Type t);
147 
148 /// Returns true iff `t` is a fir.char type and has an unknown length.
characterWithDynamicLen(mlir::Type t)149 inline bool characterWithDynamicLen(mlir::Type t) {
150   if (auto charTy = t.dyn_cast<fir::CharacterType>())
151     return charTy.hasDynamicLen();
152   return false;
153 }
154 
155 /// Returns true iff `seqTy` has either an unknown shape or a non-constant shape
156 /// (where rank > 0).
sequenceWithNonConstantShape(fir::SequenceType seqTy)157 inline bool sequenceWithNonConstantShape(fir::SequenceType seqTy) {
158   return seqTy.hasUnknownShape() || !seqTy.hasConstantShape();
159 }
160 
161 /// Returns true iff the type `t` does not have a constant size.
162 bool hasDynamicSize(mlir::Type t);
163 
getRankOfShapeType(mlir::Type t)164 inline unsigned getRankOfShapeType(mlir::Type t) {
165   if (auto shTy = t.dyn_cast<fir::ShapeType>())
166     return shTy.getRank();
167   if (auto shTy = t.dyn_cast<fir::ShapeShiftType>())
168     return shTy.getRank();
169   if (auto shTy = t.dyn_cast<fir::ShiftType>())
170     return shTy.getRank();
171   return 0;
172 }
173 
174 /// Get the memory reference type of the data pointer from the box type,
boxMemRefType(fir::BoxType t)175 inline mlir::Type boxMemRefType(fir::BoxType t) {
176   auto eleTy = t.getEleTy();
177   if (!eleTy.isa<fir::PointerType, fir::HeapType>())
178     eleTy = fir::ReferenceType::get(t);
179   return eleTy;
180 }
181 
182 /// If `t` is a SequenceType return its element type, otherwise return `t`.
unwrapSequenceType(mlir::Type t)183 inline mlir::Type unwrapSequenceType(mlir::Type t) {
184   if (auto seqTy = t.dyn_cast<fir::SequenceType>())
185     return seqTy.getEleTy();
186   return t;
187 }
188 
unwrapRefType(mlir::Type t)189 inline mlir::Type unwrapRefType(mlir::Type t) {
190   if (auto eleTy = dyn_cast_ptrEleTy(t))
191     return eleTy;
192   return t;
193 }
194 
195 /// If `t` conforms with a pass-by-reference type (box, ref, ptr, etc.) then
196 /// return the element type of `t`. Otherwise, return `t`.
unwrapPassByRefType(mlir::Type t)197 inline mlir::Type unwrapPassByRefType(mlir::Type t) {
198   if (auto eleTy = dyn_cast_ptrOrBoxEleTy(t))
199     return eleTy;
200   return t;
201 }
202 
203 /// Unwrap either a sequence or a boxed sequence type, returning the element
204 /// type of the sequence type.
205 /// e.g.,
206 ///   !fir.array<...xT>  ->  T
207 ///   !fir.box<!fir.ptr<!fir.array<...xT>>>  ->  T
208 /// otherwise
209 ///   T -> T
210 mlir::Type unwrapSeqOrBoxedSeqType(mlir::Type ty);
211 
212 /// Unwrap all referential and sequential outer types (if any). Returns the
213 /// element type. This is useful for determining the element type of any object
214 /// memory reference, whether it is a single instance or a series of instances.
215 mlir::Type unwrapAllRefAndSeqType(mlir::Type ty);
216 
217 /// Unwrap all pointer and box types and return the element type if it is a
218 /// sequence type, otherwise return null.
unwrapUntilSeqType(mlir::Type t)219 inline fir::SequenceType unwrapUntilSeqType(mlir::Type t) {
220   while (true) {
221     if (!t)
222       return {};
223     if (auto ty = dyn_cast_ptrOrBoxEleTy(t)) {
224       t = ty;
225       continue;
226     }
227     if (auto seqTy = t.dyn_cast<fir::SequenceType>())
228       return seqTy;
229     return {};
230   }
231 }
232 
233 #ifndef NDEBUG
234 // !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref
235 // is undefined and disallowed.
singleIndirectionLevel(mlir::Type ty)236 inline bool singleIndirectionLevel(mlir::Type ty) {
237   return !fir::isa_ref_type(ty);
238 }
239 #endif
240 
241 /// Return true iff `ty` is the type of a POINTER entity or value.
242 /// `isa_ref_type()` can be used to distinguish.
243 bool isPointerType(mlir::Type ty);
244 
245 /// Return true iff `ty` is the type of an ALLOCATABLE entity or value.
246 bool isAllocatableType(mlir::Type ty);
247 
248 /// Return true iff `ty` is the type of an unlimited polymorphic entity or
249 /// value.
250 bool isUnlimitedPolymorphicType(mlir::Type ty);
251 
252 /// Return true iff `ty` is a RecordType with members that are allocatable.
253 bool isRecordWithAllocatableMember(mlir::Type ty);
254 
255 /// Return true iff `ty` is a RecordType with type parameters.
isRecordWithTypeParameters(mlir::Type ty)256 inline bool isRecordWithTypeParameters(mlir::Type ty) {
257   if (auto recTy = ty.dyn_cast_or_null<fir::RecordType>())
258     return recTy.isDependentType();
259   return false;
260 }
261 
262 /// Is this tuple type holding a character function and its result length?
263 bool isCharacterProcedureTuple(mlir::Type type, bool acceptRawFunc = true);
264 
265 /// Apply the components specified by `path` to `rootTy` to determine the type
266 /// of the resulting component element. `rootTy` should be an aggregate type.
267 /// Returns null on error.
268 mlir::Type applyPathToType(mlir::Type rootTy, mlir::ValueRange path);
269 
270 /// Does this function type has a result that requires binding the result value
271 /// with a storage in a fir.save_result operation in order to use the result?
272 bool hasAbstractResult(mlir::FunctionType ty);
273 
274 /// Convert llvm::Type::TypeID to mlir::Type
275 mlir::Type fromRealTypeID(mlir::MLIRContext *context, llvm::Type::TypeID typeID,
276                           fir::KindTy kind);
277 
278 } // namespace fir
279 
280 #endif // FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H
281