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