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 #ifndef OPTIMIZER_DIALECT_FIRTYPE_H
10 #define OPTIMIZER_DIALECT_FIRTYPE_H
11
12 #include "mlir/IR/BuiltinAttributes.h"
13 #include "mlir/IR/BuiltinTypes.h"
14 #include "llvm/ADT/SmallVector.h"
15
16 namespace llvm {
17 class raw_ostream;
18 class StringRef;
19 template <typename>
20 class ArrayRef;
21 class hash_code;
22 } // namespace llvm
23
24 namespace mlir {
25 class DialectAsmParser;
26 class DialectAsmPrinter;
27 class ComplexType;
28 class FloatType;
29 } // namespace mlir
30
31 namespace fir {
32
33 class FIROpsDialect;
34
35 using KindTy = int;
36
37 namespace detail {
38 struct BoxTypeStorage;
39 struct BoxCharTypeStorage;
40 struct BoxProcTypeStorage;
41 struct CharacterTypeStorage;
42 struct CplxTypeStorage;
43 struct DimsTypeStorage;
44 struct FieldTypeStorage;
45 struct HeapTypeStorage;
46 struct IntTypeStorage;
47 struct LenTypeStorage;
48 struct LogicalTypeStorage;
49 struct PointerTypeStorage;
50 struct RealTypeStorage;
51 struct RecordTypeStorage;
52 struct ReferenceTypeStorage;
53 struct SequenceTypeStorage;
54 struct TypeDescTypeStorage;
55 } // namespace detail
56
57 // These isa_ routines follow the precedent of llvm::isa_or_null<>
58
59 /// Is `t` any of the FIR dialect types?
60 bool isa_fir_type(mlir::Type t);
61
62 /// Is `t` any of the Standard dialect types?
63 bool isa_std_type(mlir::Type t);
64
65 /// Is `t` any of the FIR dialect or Standard dialect types?
66 bool isa_fir_or_std_type(mlir::Type t);
67
68 /// Is `t` a FIR dialect type that implies a memory (de)reference?
69 bool isa_ref_type(mlir::Type t);
70
71 /// Is `t` a type that is always trivially pass-by-reference?
72 bool isa_passbyref_type(mlir::Type t);
73
74 /// Is `t` a boxed type?
75 bool isa_box_type(mlir::Type t);
76
77 /// Is `t` a type that can conform to be pass-by-reference? Depending on the
78 /// context, these types may simply demote to pass-by-reference or a reference
79 /// to them may have to be passed instead.
conformsWithPassByRef(mlir::Type t)80 inline bool conformsWithPassByRef(mlir::Type t) {
81 return isa_ref_type(t) || isa_box_type(t);
82 }
83
84 /// Is `t` a FIR dialect aggregate type?
85 bool isa_aggregate(mlir::Type t);
86
87 /// Extract the `Type` pointed to from a FIR memory reference type. If `t` is
88 /// not a memory reference type, then returns a null `Type`.
89 mlir::Type dyn_cast_ptrEleTy(mlir::Type t);
90
91 // Intrinsic types
92
93 /// Model of the Fortran CHARACTER intrinsic type, including the KIND type
94 /// parameter. The model does not include a LEN type parameter. A CharacterType
95 /// is thus the type of a single character value.
96 class CharacterType
97 : public mlir::Type::TypeBase<CharacterType, mlir::Type,
98 detail::CharacterTypeStorage> {
99 public:
100 using Base::Base;
101 static CharacterType get(mlir::MLIRContext *ctxt, KindTy kind);
102 KindTy getFKind() const;
103 };
104
105 /// Model of a Fortran COMPLEX intrinsic type, including the KIND type
106 /// parameter. COMPLEX is a floating point type with a real and imaginary
107 /// member.
108 class CplxType : public mlir::Type::TypeBase<CplxType, mlir::Type,
109 detail::CplxTypeStorage> {
110 public:
111 using Base::Base;
112 static CplxType get(mlir::MLIRContext *ctxt, KindTy kind);
113
114 /// Get the corresponding fir.real<k> type.
115 mlir::Type getElementType() const;
116
117 KindTy getFKind() const;
118 };
119
120 /// Model of a Fortran INTEGER intrinsic type, including the KIND type
121 /// parameter.
122 class IntType
123 : public mlir::Type::TypeBase<IntType, mlir::Type, detail::IntTypeStorage> {
124 public:
125 using Base::Base;
126 static IntType get(mlir::MLIRContext *ctxt, KindTy kind);
127 KindTy getFKind() const;
128 };
129
130 /// Model of a Fortran LOGICAL intrinsic type, including the KIND type
131 /// parameter.
132 class LogicalType
133 : public mlir::Type::TypeBase<LogicalType, mlir::Type,
134 detail::LogicalTypeStorage> {
135 public:
136 using Base::Base;
137 static LogicalType get(mlir::MLIRContext *ctxt, KindTy kind);
138 KindTy getFKind() const;
139 };
140
141 /// Model of a Fortran REAL (and DOUBLE PRECISION) intrinsic type, including the
142 /// KIND type parameter.
143 class RealType : public mlir::Type::TypeBase<RealType, mlir::Type,
144 detail::RealTypeStorage> {
145 public:
146 using Base::Base;
147 static RealType get(mlir::MLIRContext *ctxt, KindTy kind);
148 KindTy getFKind() const;
149 };
150
151 // FIR support types
152
153 /// The type of a Fortran descriptor. Descriptors are tuples of information that
154 /// describe an entity being passed from a calling context. This information
155 /// might include (but is not limited to) whether the entity is an array, its
156 /// size, or what type it has.
157 class BoxType
158 : public mlir::Type::TypeBase<BoxType, mlir::Type, detail::BoxTypeStorage> {
159 public:
160 using Base::Base;
161 static BoxType get(mlir::Type eleTy, mlir::AffineMapAttr map = {});
162 mlir::Type getEleTy() const;
163 mlir::AffineMapAttr getLayoutMap() const;
164
165 static mlir::LogicalResult
166 verifyConstructionInvariants(mlir::Location, mlir::Type eleTy,
167 mlir::AffineMapAttr map);
168 };
169
170 /// The type of a pair that describes a CHARACTER variable. Specifically, a
171 /// CHARACTER consists of a reference to a buffer (the string value) and a LEN
172 /// type parameter (the runtime length of the buffer).
173 class BoxCharType : public mlir::Type::TypeBase<BoxCharType, mlir::Type,
174 detail::BoxCharTypeStorage> {
175 public:
176 using Base::Base;
177 static BoxCharType get(mlir::MLIRContext *ctxt, KindTy kind);
178 CharacterType getEleTy() const;
179 };
180
181 /// The type of a pair that describes a PROCEDURE reference. Pointers to
182 /// internal procedures must carry an additional reference to the host's
183 /// variables that are referenced.
184 class BoxProcType : public mlir::Type::TypeBase<BoxProcType, mlir::Type,
185 detail::BoxProcTypeStorage> {
186 public:
187 using Base::Base;
188 static BoxProcType get(mlir::Type eleTy);
189 mlir::Type getEleTy() const;
190
191 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
192 mlir::Type eleTy);
193 };
194
195 /// The type of a runtime vector that describes triples of array dimension
196 /// information. A triple consists of a lower bound, upper bound, and
197 /// stride. Each dimension of an array entity may have an associated triple that
198 /// maps how elements of the array are accessed.
199 class DimsType : public mlir::Type::TypeBase<DimsType, mlir::Type,
200 detail::DimsTypeStorage> {
201 public:
202 using Base::Base;
203 static DimsType get(mlir::MLIRContext *ctx, unsigned rank);
204
205 /// returns -1 if the rank is unknown
206 unsigned getRank() const;
207 };
208
209 /// The type of a field name. Implementations may defer the layout of a Fortran
210 /// derived type until runtime. This implies that the runtime must be able to
211 /// determine the offset of fields within the entity.
212 class FieldType : public mlir::Type::TypeBase<FieldType, mlir::Type,
213 detail::FieldTypeStorage> {
214 public:
215 using Base::Base;
216 static FieldType get(mlir::MLIRContext *ctxt);
217 };
218
219 /// The type of a heap pointer. Fortran entities with the ALLOCATABLE attribute
220 /// may be allocated on the heap at runtime. These pointers are explicitly
221 /// distinguished to disallow the composition of multiple levels of
222 /// indirection. For example, an ALLOCATABLE POINTER is invalid.
223 class HeapType : public mlir::Type::TypeBase<HeapType, mlir::Type,
224 detail::HeapTypeStorage> {
225 public:
226 using Base::Base;
227 static HeapType get(mlir::Type elementType);
228
229 mlir::Type getEleTy() const;
230
231 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
232 mlir::Type eleTy);
233 };
234
235 /// The type of a LEN parameter name. Implementations may defer the layout of a
236 /// Fortran derived type until runtime. This implies that the runtime must be
237 /// able to determine the offset of LEN type parameters related to an entity.
238 class LenType
239 : public mlir::Type::TypeBase<LenType, mlir::Type, detail::LenTypeStorage> {
240 public:
241 using Base::Base;
242 static LenType get(mlir::MLIRContext *ctxt);
243 };
244
245 /// The type of entities with the POINTER attribute. These pointers are
246 /// explicitly distinguished to disallow the composition of multiple levels of
247 /// indirection. For example, an ALLOCATABLE POINTER is invalid.
248 class PointerType : public mlir::Type::TypeBase<PointerType, mlir::Type,
249 detail::PointerTypeStorage> {
250 public:
251 using Base::Base;
252 static PointerType get(mlir::Type elementType);
253
254 mlir::Type getEleTy() const;
255
256 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
257 mlir::Type eleTy);
258 };
259
260 /// The type of a reference to an entity in memory.
261 class ReferenceType
262 : public mlir::Type::TypeBase<ReferenceType, mlir::Type,
263 detail::ReferenceTypeStorage> {
264 public:
265 using Base::Base;
266 static ReferenceType get(mlir::Type elementType);
267
268 mlir::Type getEleTy() const;
269
270 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
271 mlir::Type eleTy);
272 };
273
274 /// A sequence type is a multi-dimensional array of values. The sequence type
275 /// may have an unknown number of dimensions or the extent of dimensions may be
276 /// unknown. A sequence type models a Fortran array entity, giving it a type in
277 /// FIR. A sequence type is assumed to be stored in a column-major order, which
278 /// differs from LLVM IR and other dialects of MLIR.
279 class SequenceType : public mlir::Type::TypeBase<SequenceType, mlir::Type,
280 detail::SequenceTypeStorage> {
281 public:
282 using Base::Base;
283 using Extent = int64_t;
284 using Shape = llvm::SmallVector<Extent, 8>;
285
286 /// Return a sequence type with the specified shape and element type
287 static SequenceType get(const Shape &shape, mlir::Type elementType,
288 mlir::AffineMapAttr map = {});
289
290 /// The element type of this sequence
291 mlir::Type getEleTy() const;
292
293 /// The shape of the sequence. If the sequence has an unknown shape, the shape
294 /// returned will be empty.
295 Shape getShape() const;
296
297 mlir::AffineMapAttr getLayoutMap() const;
298
299 /// The number of dimensions of the sequence
getDimension()300 unsigned getDimension() const { return getShape().size(); }
301
302 /// Number of rows of constant extent
303 unsigned getConstantRows() const;
304
305 /// Is the shape of the sequence constant?
hasConstantShape()306 bool hasConstantShape() const { return getConstantRows() == getDimension(); }
307
308 /// Does the sequence have unknown shape? (`array<* x T>`)
hasUnknownShape()309 bool hasUnknownShape() const { return getShape().empty(); }
310
311 /// Is the interior of the sequence constant? Check if the array is
312 /// one of constant shape (`array<C...xCxT>`), unknown shape
313 /// (`array<*xT>`), or rows with shape and ending with column(s) of
314 /// unknown extent (`array<C...xCx?...x?xT>`).
315 bool hasConstantInterior() const;
316
317 /// The value `-1` represents an unknown extent for a dimension
getUnknownExtent()318 static constexpr Extent getUnknownExtent() { return -1; }
319
320 static mlir::LogicalResult
321 verifyConstructionInvariants(mlir::Location loc, const Shape &shape,
322 mlir::Type eleTy, mlir::AffineMapAttr map);
323 };
324
325 bool operator==(const SequenceType::Shape &, const SequenceType::Shape &);
326 llvm::hash_code hash_value(const SequenceType::Extent &);
327 llvm::hash_code hash_value(const SequenceType::Shape &);
328
329 /// The type of a type descriptor object. The runtime may generate type
330 /// descriptor objects to determine the type of an entity at runtime, etc.
331 class TypeDescType : public mlir::Type::TypeBase<TypeDescType, mlir::Type,
332 detail::TypeDescTypeStorage> {
333 public:
334 using Base::Base;
335 static TypeDescType get(mlir::Type ofType);
336 mlir::Type getOfTy() const;
337
338 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
339 mlir::Type ofType);
340 };
341
342 // Derived types
343
344 /// Model of Fortran's derived type, TYPE. The name of the TYPE includes any
345 /// KIND type parameters. The record includes runtime slots for LEN type
346 /// parameters and for data components.
347 class RecordType : public mlir::Type::TypeBase<RecordType, mlir::Type,
348 detail::RecordTypeStorage> {
349 public:
350 using Base::Base;
351 using TypePair = std::pair<std::string, mlir::Type>;
352 using TypeList = std::vector<TypePair>;
353
354 llvm::StringRef getName();
355 TypeList getTypeList();
356 TypeList getLenParamList();
357
358 mlir::Type getType(llvm::StringRef ident);
getType(unsigned index)359 mlir::Type getType(unsigned index) {
360 assert(index < getNumFields());
361 return getTypeList()[index].second;
362 }
getNumFields()363 unsigned getNumFields() { return getTypeList().size(); }
getNumLenParams()364 unsigned getNumLenParams() { return getLenParamList().size(); }
365
366 static RecordType get(mlir::MLIRContext *ctxt, llvm::StringRef name);
367 void finalize(llvm::ArrayRef<TypePair> lenPList,
368 llvm::ArrayRef<TypePair> typeList);
369
370 detail::RecordTypeStorage const *uniqueKey() const;
371
372 static mlir::LogicalResult verifyConstructionInvariants(mlir::Location,
373 llvm::StringRef name);
374 };
375
376 mlir::Type parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser);
377
378 void printFirType(FIROpsDialect *, mlir::Type ty, mlir::DialectAsmPrinter &p);
379
380 /// Guarantee `type` is a scalar integral type (standard Integer, standard
381 /// Index, or FIR Int). Aborts execution if condition is false.
382 void verifyIntegralType(mlir::Type type);
383
384 /// Is `t` a FIR Real or MLIR Float type?
isa_real(mlir::Type t)385 inline bool isa_real(mlir::Type t) {
386 return t.isa<fir::RealType>() || t.isa<mlir::FloatType>();
387 }
388
389 /// Is `t` an integral type?
isa_integer(mlir::Type t)390 inline bool isa_integer(mlir::Type t) {
391 return t.isa<mlir::IndexType>() || t.isa<mlir::IntegerType>() ||
392 t.isa<fir::IntType>();
393 }
394
395 /// Is `t` a FIR or MLIR Complex type?
isa_complex(mlir::Type t)396 inline bool isa_complex(mlir::Type t) {
397 return t.isa<fir::CplxType>() || t.isa<mlir::ComplexType>();
398 }
399
400 } // namespace fir
401
402 #endif // OPTIMIZER_DIALECT_FIRTYPE_H
403