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