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