1 //===-- FIRType.cpp -------------------------------------------------------===//
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 #include "flang/Optimizer/Dialect/FIRType.h"
10 #include "flang/Optimizer/Dialect/FIRDialect.h"
11 #include "mlir/IR/Diagnostics.h"
12 #include "mlir/IR/DialectImplementation.h"
13 #include "llvm/ADT/SmallPtrSet.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/ADT/TypeSwitch.h"
16 #include "llvm/Support/ErrorHandling.h"
17
18 using namespace fir;
19
20 namespace {
21
22 template <typename TYPE>
parseIntSingleton(mlir::DialectAsmParser & parser)23 TYPE parseIntSingleton(mlir::DialectAsmParser &parser) {
24 int kind = 0;
25 if (parser.parseLess() || parser.parseInteger(kind) ||
26 parser.parseGreater()) {
27 parser.emitError(parser.getCurrentLocation(), "kind value expected");
28 return {};
29 }
30 return TYPE::get(parser.getBuilder().getContext(), kind);
31 }
32
33 template <typename TYPE>
parseKindSingleton(mlir::DialectAsmParser & parser)34 TYPE parseKindSingleton(mlir::DialectAsmParser &parser) {
35 return parseIntSingleton<TYPE>(parser);
36 }
37
38 template <typename TYPE>
parseRankSingleton(mlir::DialectAsmParser & parser)39 TYPE parseRankSingleton(mlir::DialectAsmParser &parser) {
40 return parseIntSingleton<TYPE>(parser);
41 }
42
43 template <typename TYPE>
parseTypeSingleton(mlir::DialectAsmParser & parser,mlir::Location)44 TYPE parseTypeSingleton(mlir::DialectAsmParser &parser, mlir::Location) {
45 mlir::Type ty;
46 if (parser.parseLess() || parser.parseType(ty) || parser.parseGreater()) {
47 parser.emitError(parser.getCurrentLocation(), "type expected");
48 return {};
49 }
50 return TYPE::get(ty);
51 }
52
53 // `box` `<` type (',' affine-map)? `>`
parseBox(mlir::DialectAsmParser & parser,mlir::Location loc)54 BoxType parseBox(mlir::DialectAsmParser &parser, mlir::Location loc) {
55 mlir::Type ofTy;
56 if (parser.parseLess() || parser.parseType(ofTy)) {
57 parser.emitError(parser.getCurrentLocation(), "expected type parameter");
58 return {};
59 }
60
61 mlir::AffineMapAttr map;
62 if (!parser.parseOptionalComma())
63 if (parser.parseAttribute(map)) {
64 parser.emitError(parser.getCurrentLocation(), "expected affine map");
65 return {};
66 }
67 if (parser.parseGreater()) {
68 parser.emitError(parser.getCurrentLocation(), "expected '>'");
69 return {};
70 }
71 return BoxType::get(ofTy, map);
72 }
73
74 // `boxchar` `<` kind `>`
parseBoxChar(mlir::DialectAsmParser & parser)75 BoxCharType parseBoxChar(mlir::DialectAsmParser &parser) {
76 return parseKindSingleton<BoxCharType>(parser);
77 }
78
79 // `boxproc` `<` return-type `>`
parseBoxProc(mlir::DialectAsmParser & parser,mlir::Location loc)80 BoxProcType parseBoxProc(mlir::DialectAsmParser &parser, mlir::Location loc) {
81 return parseTypeSingleton<BoxProcType>(parser, loc);
82 }
83
84 // `char` `<` kind `>`
parseCharacter(mlir::DialectAsmParser & parser)85 CharacterType parseCharacter(mlir::DialectAsmParser &parser) {
86 return parseKindSingleton<CharacterType>(parser);
87 }
88
89 // `complex` `<` kind `>`
parseComplex(mlir::DialectAsmParser & parser)90 CplxType parseComplex(mlir::DialectAsmParser &parser) {
91 return parseKindSingleton<CplxType>(parser);
92 }
93
94 // `dims` `<` rank `>`
parseDims(mlir::DialectAsmParser & parser)95 DimsType parseDims(mlir::DialectAsmParser &parser) {
96 return parseRankSingleton<DimsType>(parser);
97 }
98
99 // `field`
parseField(mlir::DialectAsmParser & parser)100 FieldType parseField(mlir::DialectAsmParser &parser) {
101 return FieldType::get(parser.getBuilder().getContext());
102 }
103
104 // `heap` `<` type `>`
parseHeap(mlir::DialectAsmParser & parser,mlir::Location loc)105 HeapType parseHeap(mlir::DialectAsmParser &parser, mlir::Location loc) {
106 return parseTypeSingleton<HeapType>(parser, loc);
107 }
108
109 // `int` `<` kind `>`
parseInteger(mlir::DialectAsmParser & parser)110 IntType parseInteger(mlir::DialectAsmParser &parser) {
111 return parseKindSingleton<IntType>(parser);
112 }
113
114 // `len`
parseLen(mlir::DialectAsmParser & parser)115 LenType parseLen(mlir::DialectAsmParser &parser) {
116 return LenType::get(parser.getBuilder().getContext());
117 }
118
119 // `logical` `<` kind `>`
parseLogical(mlir::DialectAsmParser & parser)120 LogicalType parseLogical(mlir::DialectAsmParser &parser) {
121 return parseKindSingleton<LogicalType>(parser);
122 }
123
124 // `ptr` `<` type `>`
parsePointer(mlir::DialectAsmParser & parser,mlir::Location loc)125 PointerType parsePointer(mlir::DialectAsmParser &parser, mlir::Location loc) {
126 return parseTypeSingleton<PointerType>(parser, loc);
127 }
128
129 // `real` `<` kind `>`
parseReal(mlir::DialectAsmParser & parser)130 RealType parseReal(mlir::DialectAsmParser &parser) {
131 return parseKindSingleton<RealType>(parser);
132 }
133
134 // `ref` `<` type `>`
parseReference(mlir::DialectAsmParser & parser,mlir::Location loc)135 ReferenceType parseReference(mlir::DialectAsmParser &parser,
136 mlir::Location loc) {
137 return parseTypeSingleton<ReferenceType>(parser, loc);
138 }
139
140 // `tdesc` `<` type `>`
parseTypeDesc(mlir::DialectAsmParser & parser,mlir::Location loc)141 TypeDescType parseTypeDesc(mlir::DialectAsmParser &parser, mlir::Location loc) {
142 return parseTypeSingleton<TypeDescType>(parser, loc);
143 }
144
145 // `void`
parseVoid(mlir::DialectAsmParser & parser)146 mlir::Type parseVoid(mlir::DialectAsmParser &parser) {
147 return parser.getBuilder().getNoneType();
148 }
149
150 // `array` `<` `*` | bounds (`x` bounds)* `:` type (',' affine-map)? `>`
151 // bounds ::= `?` | int-lit
parseSequence(mlir::DialectAsmParser & parser,mlir::Location)152 SequenceType parseSequence(mlir::DialectAsmParser &parser, mlir::Location) {
153 if (parser.parseLess()) {
154 parser.emitError(parser.getNameLoc(), "expecting '<'");
155 return {};
156 }
157 SequenceType::Shape shape;
158 if (parser.parseOptionalStar()) {
159 if (parser.parseDimensionList(shape, true)) {
160 parser.emitError(parser.getNameLoc(), "invalid shape");
161 return {};
162 }
163 } else if (parser.parseColon()) {
164 parser.emitError(parser.getNameLoc(), "expected ':'");
165 return {};
166 }
167 mlir::Type eleTy;
168 if (parser.parseType(eleTy) || parser.parseGreater()) {
169 parser.emitError(parser.getNameLoc(), "expecting element type");
170 return {};
171 }
172 mlir::AffineMapAttr map;
173 if (!parser.parseOptionalComma())
174 if (parser.parseAttribute(map)) {
175 parser.emitError(parser.getNameLoc(), "expecting affine map");
176 return {};
177 }
178 return SequenceType::get(shape, eleTy, map);
179 }
180
181 /// Is `ty` a standard or FIR integer type?
isaIntegerType(mlir::Type ty)182 static bool isaIntegerType(mlir::Type ty) {
183 // TODO: why aren't we using isa_integer? investigatation required.
184 return ty.isa<mlir::IntegerType>() || ty.isa<fir::IntType>();
185 }
186
verifyRecordMemberType(mlir::Type ty)187 bool verifyRecordMemberType(mlir::Type ty) {
188 return !(ty.isa<BoxType>() || ty.isa<BoxCharType>() ||
189 ty.isa<BoxProcType>() || ty.isa<DimsType>() || ty.isa<FieldType>() ||
190 ty.isa<LenType>() || ty.isa<ReferenceType>() ||
191 ty.isa<TypeDescType>());
192 }
193
verifySameLists(llvm::ArrayRef<RecordType::TypePair> a1,llvm::ArrayRef<RecordType::TypePair> a2)194 bool verifySameLists(llvm::ArrayRef<RecordType::TypePair> a1,
195 llvm::ArrayRef<RecordType::TypePair> a2) {
196 // FIXME: do we need to allow for any variance here?
197 return a1 == a2;
198 }
199
verifyDerived(mlir::DialectAsmParser & parser,RecordType derivedTy,llvm::ArrayRef<RecordType::TypePair> lenPList,llvm::ArrayRef<RecordType::TypePair> typeList)200 RecordType verifyDerived(mlir::DialectAsmParser &parser, RecordType derivedTy,
201 llvm::ArrayRef<RecordType::TypePair> lenPList,
202 llvm::ArrayRef<RecordType::TypePair> typeList) {
203 auto loc = parser.getNameLoc();
204 if (!verifySameLists(derivedTy.getLenParamList(), lenPList) ||
205 !verifySameLists(derivedTy.getTypeList(), typeList)) {
206 parser.emitError(loc, "cannot redefine record type members");
207 return {};
208 }
209 for (auto &p : lenPList)
210 if (!isaIntegerType(p.second)) {
211 parser.emitError(loc, "LEN parameter must be integral type");
212 return {};
213 }
214 for (auto &p : typeList)
215 if (!verifyRecordMemberType(p.second)) {
216 parser.emitError(loc, "field parameter has invalid type");
217 return {};
218 }
219 llvm::StringSet<> uniq;
220 for (auto &p : lenPList)
221 if (!uniq.insert(p.first).second) {
222 parser.emitError(loc, "LEN parameter cannot have duplicate name");
223 return {};
224 }
225 for (auto &p : typeList)
226 if (!uniq.insert(p.first).second) {
227 parser.emitError(loc, "field cannot have duplicate name");
228 return {};
229 }
230 return derivedTy;
231 }
232
233 // Fortran derived type
234 // `type` `<` name
235 // (`(` id `:` type (`,` id `:` type)* `)`)?
236 // (`{` id `:` type (`,` id `:` type)* `}`)? '>'
parseDerived(mlir::DialectAsmParser & parser,mlir::Location)237 RecordType parseDerived(mlir::DialectAsmParser &parser, mlir::Location) {
238 llvm::StringRef name;
239 if (parser.parseLess() || parser.parseKeyword(&name)) {
240 parser.emitError(parser.getNameLoc(),
241 "expected a identifier as name of derived type");
242 return {};
243 }
244 RecordType result = RecordType::get(parser.getBuilder().getContext(), name);
245
246 RecordType::TypeList lenParamList;
247 if (!parser.parseOptionalLParen()) {
248 while (true) {
249 llvm::StringRef lenparam;
250 mlir::Type intTy;
251 if (parser.parseKeyword(&lenparam) || parser.parseColon() ||
252 parser.parseType(intTy)) {
253 parser.emitError(parser.getNameLoc(), "expected LEN parameter list");
254 return {};
255 }
256 lenParamList.emplace_back(lenparam, intTy);
257 if (parser.parseOptionalComma())
258 break;
259 }
260 if (parser.parseRParen()) {
261 parser.emitError(parser.getNameLoc(), "expected ')'");
262 return {};
263 }
264 }
265
266 RecordType::TypeList typeList;
267 if (!parser.parseOptionalLBrace()) {
268 while (true) {
269 llvm::StringRef field;
270 mlir::Type fldTy;
271 if (parser.parseKeyword(&field) || parser.parseColon() ||
272 parser.parseType(fldTy)) {
273 parser.emitError(parser.getNameLoc(), "expected field type list");
274 return {};
275 }
276 typeList.emplace_back(field, fldTy);
277 if (parser.parseOptionalComma())
278 break;
279 }
280 if (parser.parseRBrace()) {
281 parser.emitError(parser.getNameLoc(), "expected '}'");
282 return {};
283 }
284 }
285
286 if (parser.parseGreater()) {
287 parser.emitError(parser.getNameLoc(), "expected '>' in type type");
288 return {};
289 }
290
291 if (lenParamList.empty() && typeList.empty())
292 return result;
293
294 result.finalize(lenParamList, typeList);
295 return verifyDerived(parser, result, lenParamList, typeList);
296 }
297
298 #ifndef NDEBUG
299 // !fir.ptr<X> and !fir.heap<X> where X is !fir.ptr, !fir.heap, or !fir.ref
300 // is undefined and disallowed.
singleIndirectionLevel(mlir::Type ty)301 inline bool singleIndirectionLevel(mlir::Type ty) {
302 return !fir::isa_ref_type(ty);
303 }
304 #endif
305
306 } // namespace
307
308 // Implementation of the thin interface from dialect to type parser
309
parseFirType(FIROpsDialect *,mlir::DialectAsmParser & parser)310 mlir::Type fir::parseFirType(FIROpsDialect *, mlir::DialectAsmParser &parser) {
311 llvm::StringRef typeNameLit;
312 if (mlir::failed(parser.parseKeyword(&typeNameLit)))
313 return {};
314
315 auto loc = parser.getEncodedSourceLoc(parser.getNameLoc());
316 if (typeNameLit == "array")
317 return parseSequence(parser, loc);
318 if (typeNameLit == "box")
319 return parseBox(parser, loc);
320 if (typeNameLit == "boxchar")
321 return parseBoxChar(parser);
322 if (typeNameLit == "boxproc")
323 return parseBoxProc(parser, loc);
324 if (typeNameLit == "char")
325 return parseCharacter(parser);
326 if (typeNameLit == "complex")
327 return parseComplex(parser);
328 if (typeNameLit == "dims")
329 return parseDims(parser);
330 if (typeNameLit == "field")
331 return parseField(parser);
332 if (typeNameLit == "heap")
333 return parseHeap(parser, loc);
334 if (typeNameLit == "int")
335 return parseInteger(parser);
336 if (typeNameLit == "len")
337 return parseLen(parser);
338 if (typeNameLit == "logical")
339 return parseLogical(parser);
340 if (typeNameLit == "ptr")
341 return parsePointer(parser, loc);
342 if (typeNameLit == "real")
343 return parseReal(parser);
344 if (typeNameLit == "ref")
345 return parseReference(parser, loc);
346 if (typeNameLit == "tdesc")
347 return parseTypeDesc(parser, loc);
348 if (typeNameLit == "type")
349 return parseDerived(parser, loc);
350 if (typeNameLit == "void")
351 return parseVoid(parser);
352
353 parser.emitError(parser.getNameLoc(), "unknown FIR type " + typeNameLit);
354 return {};
355 }
356
357 namespace fir {
358 namespace detail {
359
360 // Type storage classes
361
362 /// `CHARACTER` storage
363 struct CharacterTypeStorage : public mlir::TypeStorage {
364 using KeyTy = KindTy;
365
hashKeyfir::detail::CharacterTypeStorage366 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
367
operator ==fir::detail::CharacterTypeStorage368 bool operator==(const KeyTy &key) const { return key == getFKind(); }
369
constructfir::detail::CharacterTypeStorage370 static CharacterTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
371 KindTy kind) {
372 auto *storage = allocator.allocate<CharacterTypeStorage>();
373 return new (storage) CharacterTypeStorage{kind};
374 }
375
getFKindfir::detail::CharacterTypeStorage376 KindTy getFKind() const { return kind; }
377
378 protected:
379 KindTy kind;
380
381 private:
382 CharacterTypeStorage() = delete;
CharacterTypeStoragefir::detail::CharacterTypeStorage383 explicit CharacterTypeStorage(KindTy kind) : kind{kind} {}
384 };
385
386 struct DimsTypeStorage : public mlir::TypeStorage {
387 using KeyTy = unsigned;
388
hashKeyfir::detail::DimsTypeStorage389 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
390
operator ==fir::detail::DimsTypeStorage391 bool operator==(const KeyTy &key) const { return key == getRank(); }
392
constructfir::detail::DimsTypeStorage393 static DimsTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
394 unsigned rank) {
395 auto *storage = allocator.allocate<DimsTypeStorage>();
396 return new (storage) DimsTypeStorage{rank};
397 }
398
getRankfir::detail::DimsTypeStorage399 unsigned getRank() const { return rank; }
400
401 protected:
402 unsigned rank;
403
404 private:
405 DimsTypeStorage() = delete;
DimsTypeStoragefir::detail::DimsTypeStorage406 explicit DimsTypeStorage(unsigned rank) : rank{rank} {}
407 };
408
409 /// The type of a derived type part reference
410 struct FieldTypeStorage : public mlir::TypeStorage {
411 using KeyTy = KindTy;
412
hashKeyfir::detail::FieldTypeStorage413 static unsigned hashKey(const KeyTy &) { return llvm::hash_combine(0); }
414
operator ==fir::detail::FieldTypeStorage415 bool operator==(const KeyTy &) const { return true; }
416
constructfir::detail::FieldTypeStorage417 static FieldTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
418 KindTy) {
419 auto *storage = allocator.allocate<FieldTypeStorage>();
420 return new (storage) FieldTypeStorage{0};
421 }
422
423 private:
424 FieldTypeStorage() = delete;
FieldTypeStoragefir::detail::FieldTypeStorage425 explicit FieldTypeStorage(KindTy) {}
426 };
427
428 /// The type of a derived type LEN parameter reference
429 struct LenTypeStorage : public mlir::TypeStorage {
430 using KeyTy = KindTy;
431
hashKeyfir::detail::LenTypeStorage432 static unsigned hashKey(const KeyTy &) { return llvm::hash_combine(0); }
433
operator ==fir::detail::LenTypeStorage434 bool operator==(const KeyTy &) const { return true; }
435
constructfir::detail::LenTypeStorage436 static LenTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
437 KindTy) {
438 auto *storage = allocator.allocate<LenTypeStorage>();
439 return new (storage) LenTypeStorage{0};
440 }
441
442 private:
443 LenTypeStorage() = delete;
LenTypeStoragefir::detail::LenTypeStorage444 explicit LenTypeStorage(KindTy) {}
445 };
446
447 /// `LOGICAL` storage
448 struct LogicalTypeStorage : public mlir::TypeStorage {
449 using KeyTy = KindTy;
450
hashKeyfir::detail::LogicalTypeStorage451 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
452
operator ==fir::detail::LogicalTypeStorage453 bool operator==(const KeyTy &key) const { return key == getFKind(); }
454
constructfir::detail::LogicalTypeStorage455 static LogicalTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
456 KindTy kind) {
457 auto *storage = allocator.allocate<LogicalTypeStorage>();
458 return new (storage) LogicalTypeStorage{kind};
459 }
460
getFKindfir::detail::LogicalTypeStorage461 KindTy getFKind() const { return kind; }
462
463 protected:
464 KindTy kind;
465
466 private:
467 LogicalTypeStorage() = delete;
LogicalTypeStoragefir::detail::LogicalTypeStorage468 explicit LogicalTypeStorage(KindTy kind) : kind{kind} {}
469 };
470
471 /// `INTEGER` storage
472 struct IntTypeStorage : public mlir::TypeStorage {
473 using KeyTy = KindTy;
474
hashKeyfir::detail::IntTypeStorage475 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
476
operator ==fir::detail::IntTypeStorage477 bool operator==(const KeyTy &key) const { return key == getFKind(); }
478
constructfir::detail::IntTypeStorage479 static IntTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
480 KindTy kind) {
481 auto *storage = allocator.allocate<IntTypeStorage>();
482 return new (storage) IntTypeStorage{kind};
483 }
484
getFKindfir::detail::IntTypeStorage485 KindTy getFKind() const { return kind; }
486
487 protected:
488 KindTy kind;
489
490 private:
491 IntTypeStorage() = delete;
IntTypeStoragefir::detail::IntTypeStorage492 explicit IntTypeStorage(KindTy kind) : kind{kind} {}
493 };
494
495 /// `COMPLEX` storage
496 struct CplxTypeStorage : public mlir::TypeStorage {
497 using KeyTy = KindTy;
498
hashKeyfir::detail::CplxTypeStorage499 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
500
operator ==fir::detail::CplxTypeStorage501 bool operator==(const KeyTy &key) const { return key == getFKind(); }
502
constructfir::detail::CplxTypeStorage503 static CplxTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
504 KindTy kind) {
505 auto *storage = allocator.allocate<CplxTypeStorage>();
506 return new (storage) CplxTypeStorage{kind};
507 }
508
getFKindfir::detail::CplxTypeStorage509 KindTy getFKind() const { return kind; }
510
511 protected:
512 KindTy kind;
513
514 private:
515 CplxTypeStorage() = delete;
CplxTypeStoragefir::detail::CplxTypeStorage516 explicit CplxTypeStorage(KindTy kind) : kind{kind} {}
517 };
518
519 /// `REAL` storage (for reals of unsupported sizes)
520 struct RealTypeStorage : public mlir::TypeStorage {
521 using KeyTy = KindTy;
522
hashKeyfir::detail::RealTypeStorage523 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
524
operator ==fir::detail::RealTypeStorage525 bool operator==(const KeyTy &key) const { return key == getFKind(); }
526
constructfir::detail::RealTypeStorage527 static RealTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
528 KindTy kind) {
529 auto *storage = allocator.allocate<RealTypeStorage>();
530 return new (storage) RealTypeStorage{kind};
531 }
532
getFKindfir::detail::RealTypeStorage533 KindTy getFKind() const { return kind; }
534
535 protected:
536 KindTy kind;
537
538 private:
539 RealTypeStorage() = delete;
RealTypeStoragefir::detail::RealTypeStorage540 explicit RealTypeStorage(KindTy kind) : kind{kind} {}
541 };
542
543 /// Boxed object (a Fortran descriptor)
544 struct BoxTypeStorage : public mlir::TypeStorage {
545 using KeyTy = std::tuple<mlir::Type, mlir::AffineMapAttr>;
546
hashKeyfir::detail::BoxTypeStorage547 static unsigned hashKey(const KeyTy &key) {
548 auto hashVal{llvm::hash_combine(std::get<mlir::Type>(key))};
549 return llvm::hash_combine(
550 hashVal, llvm::hash_combine(std::get<mlir::AffineMapAttr>(key)));
551 }
552
operator ==fir::detail::BoxTypeStorage553 bool operator==(const KeyTy &key) const {
554 return std::get<mlir::Type>(key) == getElementType() &&
555 std::get<mlir::AffineMapAttr>(key) == getLayoutMap();
556 }
557
constructfir::detail::BoxTypeStorage558 static BoxTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
559 const KeyTy &key) {
560 auto *storage = allocator.allocate<BoxTypeStorage>();
561 return new (storage) BoxTypeStorage{std::get<mlir::Type>(key),
562 std::get<mlir::AffineMapAttr>(key)};
563 }
564
getElementTypefir::detail::BoxTypeStorage565 mlir::Type getElementType() const { return eleTy; }
getLayoutMapfir::detail::BoxTypeStorage566 mlir::AffineMapAttr getLayoutMap() const { return map; }
567
568 protected:
569 mlir::Type eleTy;
570 mlir::AffineMapAttr map;
571
572 private:
573 BoxTypeStorage() = delete;
BoxTypeStoragefir::detail::BoxTypeStorage574 explicit BoxTypeStorage(mlir::Type eleTy, mlir::AffineMapAttr map)
575 : eleTy{eleTy}, map{map} {}
576 };
577
578 /// Boxed CHARACTER object type
579 struct BoxCharTypeStorage : public mlir::TypeStorage {
580 using KeyTy = KindTy;
581
hashKeyfir::detail::BoxCharTypeStorage582 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
583
operator ==fir::detail::BoxCharTypeStorage584 bool operator==(const KeyTy &key) const { return key == getFKind(); }
585
constructfir::detail::BoxCharTypeStorage586 static BoxCharTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
587 KindTy kind) {
588 auto *storage = allocator.allocate<BoxCharTypeStorage>();
589 return new (storage) BoxCharTypeStorage{kind};
590 }
591
getFKindfir::detail::BoxCharTypeStorage592 KindTy getFKind() const { return kind; }
593
594 // a !fir.boxchar<k> always wraps a !fir.char<k>
getElementTypefir::detail::BoxCharTypeStorage595 CharacterType getElementType(mlir::MLIRContext *ctxt) const {
596 return CharacterType::get(ctxt, getFKind());
597 }
598
599 protected:
600 KindTy kind;
601
602 private:
603 BoxCharTypeStorage() = delete;
BoxCharTypeStoragefir::detail::BoxCharTypeStorage604 explicit BoxCharTypeStorage(KindTy kind) : kind{kind} {}
605 };
606
607 /// Boxed PROCEDURE POINTER object type
608 struct BoxProcTypeStorage : public mlir::TypeStorage {
609 using KeyTy = mlir::Type;
610
hashKeyfir::detail::BoxProcTypeStorage611 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
612
operator ==fir::detail::BoxProcTypeStorage613 bool operator==(const KeyTy &key) const { return key == getElementType(); }
614
constructfir::detail::BoxProcTypeStorage615 static BoxProcTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
616 mlir::Type eleTy) {
617 assert(eleTy && "element type is null");
618 auto *storage = allocator.allocate<BoxProcTypeStorage>();
619 return new (storage) BoxProcTypeStorage{eleTy};
620 }
621
getElementTypefir::detail::BoxProcTypeStorage622 mlir::Type getElementType() const { return eleTy; }
623
624 protected:
625 mlir::Type eleTy;
626
627 private:
628 BoxProcTypeStorage() = delete;
BoxProcTypeStoragefir::detail::BoxProcTypeStorage629 explicit BoxProcTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
630 };
631
632 /// Pointer-like object storage
633 struct ReferenceTypeStorage : public mlir::TypeStorage {
634 using KeyTy = mlir::Type;
635
hashKeyfir::detail::ReferenceTypeStorage636 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
637
operator ==fir::detail::ReferenceTypeStorage638 bool operator==(const KeyTy &key) const { return key == getElementType(); }
639
constructfir::detail::ReferenceTypeStorage640 static ReferenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
641 mlir::Type eleTy) {
642 assert(eleTy && "element type is null");
643 auto *storage = allocator.allocate<ReferenceTypeStorage>();
644 return new (storage) ReferenceTypeStorage{eleTy};
645 }
646
getElementTypefir::detail::ReferenceTypeStorage647 mlir::Type getElementType() const { return eleTy; }
648
649 protected:
650 mlir::Type eleTy;
651
652 private:
653 ReferenceTypeStorage() = delete;
ReferenceTypeStoragefir::detail::ReferenceTypeStorage654 explicit ReferenceTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
655 };
656
657 /// Pointer object storage
658 struct PointerTypeStorage : public mlir::TypeStorage {
659 using KeyTy = mlir::Type;
660
hashKeyfir::detail::PointerTypeStorage661 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
662
operator ==fir::detail::PointerTypeStorage663 bool operator==(const KeyTy &key) const { return key == getElementType(); }
664
constructfir::detail::PointerTypeStorage665 static PointerTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
666 mlir::Type eleTy) {
667 assert(eleTy && "element type is null");
668 auto *storage = allocator.allocate<PointerTypeStorage>();
669 return new (storage) PointerTypeStorage{eleTy};
670 }
671
getElementTypefir::detail::PointerTypeStorage672 mlir::Type getElementType() const { return eleTy; }
673
674 protected:
675 mlir::Type eleTy;
676
677 private:
678 PointerTypeStorage() = delete;
PointerTypeStoragefir::detail::PointerTypeStorage679 explicit PointerTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
680 };
681
682 /// Heap memory reference object storage
683 struct HeapTypeStorage : public mlir::TypeStorage {
684 using KeyTy = mlir::Type;
685
hashKeyfir::detail::HeapTypeStorage686 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
687
operator ==fir::detail::HeapTypeStorage688 bool operator==(const KeyTy &key) const { return key == getElementType(); }
689
constructfir::detail::HeapTypeStorage690 static HeapTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
691 mlir::Type eleTy) {
692 assert(eleTy && "element type is null");
693 auto *storage = allocator.allocate<HeapTypeStorage>();
694 return new (storage) HeapTypeStorage{eleTy};
695 }
696
getElementTypefir::detail::HeapTypeStorage697 mlir::Type getElementType() const { return eleTy; }
698
699 protected:
700 mlir::Type eleTy;
701
702 private:
703 HeapTypeStorage() = delete;
HeapTypeStoragefir::detail::HeapTypeStorage704 explicit HeapTypeStorage(mlir::Type eleTy) : eleTy{eleTy} {}
705 };
706
707 /// Sequence-like object storage
708 struct SequenceTypeStorage : public mlir::TypeStorage {
709 using KeyTy =
710 std::tuple<SequenceType::Shape, mlir::Type, mlir::AffineMapAttr>;
711
hashKeyfir::detail::SequenceTypeStorage712 static unsigned hashKey(const KeyTy &key) {
713 auto shapeHash{hash_value(std::get<SequenceType::Shape>(key))};
714 shapeHash = llvm::hash_combine(shapeHash, std::get<mlir::Type>(key));
715 return llvm::hash_combine(shapeHash, std::get<mlir::AffineMapAttr>(key));
716 }
717
operator ==fir::detail::SequenceTypeStorage718 bool operator==(const KeyTy &key) const {
719 return key == KeyTy{getShape(), getElementType(), getLayoutMap()};
720 }
721
constructfir::detail::SequenceTypeStorage722 static SequenceTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
723 const KeyTy &key) {
724 auto *storage = allocator.allocate<SequenceTypeStorage>();
725 return new (storage) SequenceTypeStorage{
726 std::get<SequenceType::Shape>(key), std::get<mlir::Type>(key),
727 std::get<mlir::AffineMapAttr>(key)};
728 }
729
getShapefir::detail::SequenceTypeStorage730 SequenceType::Shape getShape() const { return shape; }
getElementTypefir::detail::SequenceTypeStorage731 mlir::Type getElementType() const { return eleTy; }
getLayoutMapfir::detail::SequenceTypeStorage732 mlir::AffineMapAttr getLayoutMap() const { return map; }
733
734 protected:
735 SequenceType::Shape shape;
736 mlir::Type eleTy;
737 mlir::AffineMapAttr map;
738
739 private:
740 SequenceTypeStorage() = delete;
SequenceTypeStoragefir::detail::SequenceTypeStorage741 explicit SequenceTypeStorage(const SequenceType::Shape &shape,
742 mlir::Type eleTy, mlir::AffineMapAttr map)
743 : shape{shape}, eleTy{eleTy}, map{map} {}
744 };
745
746 /// Derived type storage
747 struct RecordTypeStorage : public mlir::TypeStorage {
748 using KeyTy = llvm::StringRef;
749
hashKeyfir::detail::RecordTypeStorage750 static unsigned hashKey(const KeyTy &key) {
751 return llvm::hash_combine(key.str());
752 }
753
operator ==fir::detail::RecordTypeStorage754 bool operator==(const KeyTy &key) const { return key == getName(); }
755
constructfir::detail::RecordTypeStorage756 static RecordTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
757 const KeyTy &key) {
758 auto *storage = allocator.allocate<RecordTypeStorage>();
759 return new (storage) RecordTypeStorage{key};
760 }
761
getNamefir::detail::RecordTypeStorage762 llvm::StringRef getName() const { return name; }
763
setLenParamListfir::detail::RecordTypeStorage764 void setLenParamList(llvm::ArrayRef<RecordType::TypePair> list) {
765 lens = list;
766 }
getLenParamListfir::detail::RecordTypeStorage767 llvm::ArrayRef<RecordType::TypePair> getLenParamList() const { return lens; }
768
setTypeListfir::detail::RecordTypeStorage769 void setTypeList(llvm::ArrayRef<RecordType::TypePair> list) { types = list; }
getTypeListfir::detail::RecordTypeStorage770 llvm::ArrayRef<RecordType::TypePair> getTypeList() const { return types; }
771
finalizefir::detail::RecordTypeStorage772 void finalize(llvm::ArrayRef<RecordType::TypePair> lenParamList,
773 llvm::ArrayRef<RecordType::TypePair> typeList) {
774 if (finalized)
775 return;
776 finalized = true;
777 setLenParamList(lenParamList);
778 setTypeList(typeList);
779 }
780
781 protected:
782 std::string name;
783 bool finalized;
784 std::vector<RecordType::TypePair> lens;
785 std::vector<RecordType::TypePair> types;
786
787 private:
788 RecordTypeStorage() = delete;
RecordTypeStoragefir::detail::RecordTypeStorage789 explicit RecordTypeStorage(llvm::StringRef name)
790 : name{name}, finalized{false} {}
791 };
792
793 /// Type descriptor type storage
794 struct TypeDescTypeStorage : public mlir::TypeStorage {
795 using KeyTy = mlir::Type;
796
hashKeyfir::detail::TypeDescTypeStorage797 static unsigned hashKey(const KeyTy &key) { return llvm::hash_combine(key); }
798
operator ==fir::detail::TypeDescTypeStorage799 bool operator==(const KeyTy &key) const { return key == getOfType(); }
800
constructfir::detail::TypeDescTypeStorage801 static TypeDescTypeStorage *construct(mlir::TypeStorageAllocator &allocator,
802 mlir::Type ofTy) {
803 assert(ofTy && "descriptor type is null");
804 auto *storage = allocator.allocate<TypeDescTypeStorage>();
805 return new (storage) TypeDescTypeStorage{ofTy};
806 }
807
808 // The type described by this type descriptor instance
getOfTypefir::detail::TypeDescTypeStorage809 mlir::Type getOfType() const { return ofTy; }
810
811 protected:
812 mlir::Type ofTy;
813
814 private:
815 TypeDescTypeStorage() = delete;
TypeDescTypeStoragefir::detail::TypeDescTypeStorage816 explicit TypeDescTypeStorage(mlir::Type ofTy) : ofTy{ofTy} {}
817 };
818
819 } // namespace detail
820
821 template <typename A, typename B>
inbounds(A v,B lb,B ub)822 bool inbounds(A v, B lb, B ub) {
823 return v >= lb && v < ub;
824 }
825
isa_fir_type(mlir::Type t)826 bool isa_fir_type(mlir::Type t) {
827 return llvm::isa<FIROpsDialect>(t.getDialect());
828 }
829
isa_std_type(mlir::Type t)830 bool isa_std_type(mlir::Type t) {
831 return t.getDialect().getNamespace().empty();
832 }
833
isa_fir_or_std_type(mlir::Type t)834 bool isa_fir_or_std_type(mlir::Type t) {
835 if (auto funcType = t.dyn_cast<mlir::FunctionType>())
836 return llvm::all_of(funcType.getInputs(), isa_fir_or_std_type) &&
837 llvm::all_of(funcType.getResults(), isa_fir_or_std_type);
838 return isa_fir_type(t) || isa_std_type(t);
839 }
840
isa_ref_type(mlir::Type t)841 bool isa_ref_type(mlir::Type t) {
842 return t.isa<ReferenceType>() || t.isa<PointerType>() || t.isa<HeapType>();
843 }
844
isa_box_type(mlir::Type t)845 bool isa_box_type(mlir::Type t) {
846 return t.isa<BoxType>() || t.isa<BoxCharType>() || t.isa<BoxProcType>();
847 }
848
isa_passbyref_type(mlir::Type t)849 bool isa_passbyref_type(mlir::Type t) {
850 return t.isa<ReferenceType>() || isa_box_type(t);
851 }
852
isa_aggregate(mlir::Type t)853 bool isa_aggregate(mlir::Type t) {
854 return t.isa<SequenceType>() || t.isa<RecordType>();
855 }
856
dyn_cast_ptrEleTy(mlir::Type t)857 mlir::Type dyn_cast_ptrEleTy(mlir::Type t) {
858 return llvm::TypeSwitch<mlir::Type, mlir::Type>(t)
859 .Case<fir::ReferenceType, fir::PointerType, fir::HeapType>(
860 [](auto p) { return p.getEleTy(); })
861 .Default([](mlir::Type) { return mlir::Type{}; });
862 }
863
864 } // namespace fir
865
866 // CHARACTER
867
get(mlir::MLIRContext * ctxt,KindTy kind)868 CharacterType fir::CharacterType::get(mlir::MLIRContext *ctxt, KindTy kind) {
869 return Base::get(ctxt, kind);
870 }
871
getFKind() const872 int fir::CharacterType::getFKind() const { return getImpl()->getFKind(); }
873
874 // Dims
875
get(mlir::MLIRContext * ctxt,unsigned rank)876 DimsType fir::DimsType::get(mlir::MLIRContext *ctxt, unsigned rank) {
877 return Base::get(ctxt, rank);
878 }
879
getRank() const880 unsigned fir::DimsType::getRank() const { return getImpl()->getRank(); }
881
882 // Field
883
get(mlir::MLIRContext * ctxt)884 FieldType fir::FieldType::get(mlir::MLIRContext *ctxt) {
885 return Base::get(ctxt, 0);
886 }
887
888 // Len
889
get(mlir::MLIRContext * ctxt)890 LenType fir::LenType::get(mlir::MLIRContext *ctxt) {
891 return Base::get(ctxt, 0);
892 }
893
894 // LOGICAL
895
get(mlir::MLIRContext * ctxt,KindTy kind)896 LogicalType fir::LogicalType::get(mlir::MLIRContext *ctxt, KindTy kind) {
897 return Base::get(ctxt, kind);
898 }
899
getFKind() const900 int fir::LogicalType::getFKind() const { return getImpl()->getFKind(); }
901
902 // INTEGER
903
get(mlir::MLIRContext * ctxt,KindTy kind)904 IntType fir::IntType::get(mlir::MLIRContext *ctxt, KindTy kind) {
905 return Base::get(ctxt, kind);
906 }
907
getFKind() const908 int fir::IntType::getFKind() const { return getImpl()->getFKind(); }
909
910 // COMPLEX
911
get(mlir::MLIRContext * ctxt,KindTy kind)912 CplxType fir::CplxType::get(mlir::MLIRContext *ctxt, KindTy kind) {
913 return Base::get(ctxt, kind);
914 }
915
getElementType() const916 mlir::Type fir::CplxType::getElementType() const {
917 return fir::RealType::get(getContext(), getFKind());
918 }
919
getFKind() const920 KindTy fir::CplxType::getFKind() const { return getImpl()->getFKind(); }
921
922 // REAL
923
get(mlir::MLIRContext * ctxt,KindTy kind)924 RealType fir::RealType::get(mlir::MLIRContext *ctxt, KindTy kind) {
925 return Base::get(ctxt, kind);
926 }
927
getFKind() const928 int fir::RealType::getFKind() const { return getImpl()->getFKind(); }
929
930 // Box<T>
931
get(mlir::Type elementType,mlir::AffineMapAttr map)932 BoxType fir::BoxType::get(mlir::Type elementType, mlir::AffineMapAttr map) {
933 return Base::get(elementType.getContext(), elementType, map);
934 }
935
getEleTy() const936 mlir::Type fir::BoxType::getEleTy() const {
937 return getImpl()->getElementType();
938 }
939
getLayoutMap() const940 mlir::AffineMapAttr fir::BoxType::getLayoutMap() const {
941 return getImpl()->getLayoutMap();
942 }
943
944 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location,mlir::Type eleTy,mlir::AffineMapAttr map)945 fir::BoxType::verifyConstructionInvariants(mlir::Location, mlir::Type eleTy,
946 mlir::AffineMapAttr map) {
947 // TODO
948 return mlir::success();
949 }
950
951 // BoxChar<C>
952
get(mlir::MLIRContext * ctxt,KindTy kind)953 BoxCharType fir::BoxCharType::get(mlir::MLIRContext *ctxt, KindTy kind) {
954 return Base::get(ctxt, kind);
955 }
956
getEleTy() const957 CharacterType fir::BoxCharType::getEleTy() const {
958 return getImpl()->getElementType(getContext());
959 }
960
961 // BoxProc<T>
962
get(mlir::Type elementType)963 BoxProcType fir::BoxProcType::get(mlir::Type elementType) {
964 return Base::get(elementType.getContext(), elementType);
965 }
966
getEleTy() const967 mlir::Type fir::BoxProcType::getEleTy() const {
968 return getImpl()->getElementType();
969 }
970
971 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,mlir::Type eleTy)972 fir::BoxProcType::verifyConstructionInvariants(mlir::Location loc,
973 mlir::Type eleTy) {
974 if (eleTy.isa<mlir::FunctionType>())
975 return mlir::success();
976 if (auto refTy = eleTy.dyn_cast<ReferenceType>())
977 if (refTy.isa<mlir::FunctionType>())
978 return mlir::success();
979 return mlir::emitError(loc, "invalid type for boxproc") << eleTy << '\n';
980 }
981
982 // Reference<T>
983
get(mlir::Type elementType)984 ReferenceType fir::ReferenceType::get(mlir::Type elementType) {
985 return Base::get(elementType.getContext(), elementType);
986 }
987
getEleTy() const988 mlir::Type fir::ReferenceType::getEleTy() const {
989 return getImpl()->getElementType();
990 }
991
992 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,mlir::Type eleTy)993 fir::ReferenceType::verifyConstructionInvariants(mlir::Location loc,
994 mlir::Type eleTy) {
995 if (eleTy.isa<DimsType>() || eleTy.isa<FieldType>() || eleTy.isa<LenType>() ||
996 eleTy.isa<ReferenceType>() || eleTy.isa<TypeDescType>())
997 return mlir::emitError(loc, "cannot build a reference to type: ")
998 << eleTy << '\n';
999 return mlir::success();
1000 }
1001
1002 // Pointer<T>
1003
get(mlir::Type elementType)1004 PointerType fir::PointerType::get(mlir::Type elementType) {
1005 assert(singleIndirectionLevel(elementType) && "invalid element type");
1006 return Base::get(elementType.getContext(), elementType);
1007 }
1008
getEleTy() const1009 mlir::Type fir::PointerType::getEleTy() const {
1010 return getImpl()->getElementType();
1011 }
1012
canBePointerOrHeapElementType(mlir::Type eleTy)1013 static bool canBePointerOrHeapElementType(mlir::Type eleTy) {
1014 return eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
1015 eleTy.isa<BoxProcType>() || eleTy.isa<DimsType>() ||
1016 eleTy.isa<FieldType>() || eleTy.isa<LenType>() ||
1017 eleTy.isa<HeapType>() || eleTy.isa<PointerType>() ||
1018 eleTy.isa<ReferenceType>() || eleTy.isa<TypeDescType>();
1019 }
1020
1021 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,mlir::Type eleTy)1022 fir::PointerType::verifyConstructionInvariants(mlir::Location loc,
1023 mlir::Type eleTy) {
1024 if (canBePointerOrHeapElementType(eleTy))
1025 return mlir::emitError(loc, "cannot build a pointer to type: ")
1026 << eleTy << '\n';
1027 return mlir::success();
1028 }
1029
1030 // Heap<T>
1031
get(mlir::Type elementType)1032 HeapType fir::HeapType::get(mlir::Type elementType) {
1033 assert(singleIndirectionLevel(elementType) && "invalid element type");
1034 return Base::get(elementType.getContext(), elementType);
1035 }
1036
getEleTy() const1037 mlir::Type fir::HeapType::getEleTy() const {
1038 return getImpl()->getElementType();
1039 }
1040
1041 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,mlir::Type eleTy)1042 fir::HeapType::verifyConstructionInvariants(mlir::Location loc,
1043 mlir::Type eleTy) {
1044 if (canBePointerOrHeapElementType(eleTy))
1045 return mlir::emitError(loc, "cannot build a heap pointer to type: ")
1046 << eleTy << '\n';
1047 return mlir::success();
1048 }
1049
1050 // Sequence<T>
1051
get(const Shape & shape,mlir::Type elementType,mlir::AffineMapAttr map)1052 SequenceType fir::SequenceType::get(const Shape &shape, mlir::Type elementType,
1053 mlir::AffineMapAttr map) {
1054 auto *ctxt = elementType.getContext();
1055 return Base::get(ctxt, shape, elementType, map);
1056 }
1057
getEleTy() const1058 mlir::Type fir::SequenceType::getEleTy() const {
1059 return getImpl()->getElementType();
1060 }
1061
getLayoutMap() const1062 mlir::AffineMapAttr fir::SequenceType::getLayoutMap() const {
1063 return getImpl()->getLayoutMap();
1064 }
1065
getShape() const1066 SequenceType::Shape fir::SequenceType::getShape() const {
1067 return getImpl()->getShape();
1068 }
1069
getConstantRows() const1070 unsigned fir::SequenceType::getConstantRows() const {
1071 auto shape = getShape();
1072 unsigned count = 0;
1073 for (auto d : shape) {
1074 if (d < 0)
1075 break;
1076 ++count;
1077 }
1078 return count;
1079 }
1080
1081 // This test helps us determine if we can degenerate an array to a
1082 // pointer to some interior section (possibly a single element) of the
1083 // sequence. This is used to determine if we can lower to the LLVM IR.
hasConstantInterior() const1084 bool fir::SequenceType::hasConstantInterior() const {
1085 if (hasUnknownShape())
1086 return true;
1087 auto rows = getConstantRows();
1088 auto dim = getDimension();
1089 if (rows == dim)
1090 return true;
1091 auto shape = getShape();
1092 for (unsigned i{rows}, size{dim}; i < size; ++i)
1093 if (shape[i] != getUnknownExtent())
1094 return false;
1095 return true;
1096 }
1097
verifyConstructionInvariants(mlir::Location loc,const SequenceType::Shape & shape,mlir::Type eleTy,mlir::AffineMapAttr map)1098 mlir::LogicalResult fir::SequenceType::verifyConstructionInvariants(
1099 mlir::Location loc, const SequenceType::Shape &shape, mlir::Type eleTy,
1100 mlir::AffineMapAttr map) {
1101 // DIMENSION attribute can only be applied to an intrinsic or record type
1102 if (eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
1103 eleTy.isa<BoxProcType>() || eleTy.isa<DimsType>() ||
1104 eleTy.isa<FieldType>() || eleTy.isa<LenType>() || eleTy.isa<HeapType>() ||
1105 eleTy.isa<PointerType>() || eleTy.isa<ReferenceType>() ||
1106 eleTy.isa<TypeDescType>() || eleTy.isa<SequenceType>())
1107 return mlir::emitError(loc, "cannot build an array of this element type: ")
1108 << eleTy << '\n';
1109 return mlir::success();
1110 }
1111
1112 // compare if two shapes are equivalent
operator ==(const SequenceType::Shape & sh_1,const SequenceType::Shape & sh_2)1113 bool fir::operator==(const SequenceType::Shape &sh_1,
1114 const SequenceType::Shape &sh_2) {
1115 if (sh_1.size() != sh_2.size())
1116 return false;
1117 auto e = sh_1.size();
1118 for (decltype(e) i = 0; i != e; ++i)
1119 if (sh_1[i] != sh_2[i])
1120 return false;
1121 return true;
1122 }
1123
1124 // compute the hash of a Shape
hash_value(const SequenceType::Shape & sh)1125 llvm::hash_code fir::hash_value(const SequenceType::Shape &sh) {
1126 if (sh.size()) {
1127 return llvm::hash_combine_range(sh.begin(), sh.end());
1128 }
1129 return llvm::hash_combine(0);
1130 }
1131
1132 /// RecordType
1133 ///
1134 /// This type captures a Fortran "derived type"
1135
get(mlir::MLIRContext * ctxt,llvm::StringRef name)1136 RecordType fir::RecordType::get(mlir::MLIRContext *ctxt, llvm::StringRef name) {
1137 return Base::get(ctxt, name);
1138 }
1139
finalize(llvm::ArrayRef<TypePair> lenPList,llvm::ArrayRef<TypePair> typeList)1140 void fir::RecordType::finalize(llvm::ArrayRef<TypePair> lenPList,
1141 llvm::ArrayRef<TypePair> typeList) {
1142 getImpl()->finalize(lenPList, typeList);
1143 }
1144
getName()1145 llvm::StringRef fir::RecordType::getName() { return getImpl()->getName(); }
1146
getTypeList()1147 RecordType::TypeList fir::RecordType::getTypeList() {
1148 return getImpl()->getTypeList();
1149 }
1150
getLenParamList()1151 RecordType::TypeList fir::RecordType::getLenParamList() {
1152 return getImpl()->getLenParamList();
1153 }
1154
uniqueKey() const1155 detail::RecordTypeStorage const *fir::RecordType::uniqueKey() const {
1156 return getImpl();
1157 }
1158
1159 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,llvm::StringRef name)1160 fir::RecordType::verifyConstructionInvariants(mlir::Location loc,
1161 llvm::StringRef name) {
1162 if (name.size() == 0)
1163 return mlir::emitError(loc, "record types must have a name");
1164 return mlir::success();
1165 }
1166
getType(llvm::StringRef ident)1167 mlir::Type fir::RecordType::getType(llvm::StringRef ident) {
1168 for (auto f : getTypeList())
1169 if (ident == f.first)
1170 return f.second;
1171 return {};
1172 }
1173
1174 /// Type descriptor type
1175 ///
1176 /// This is the type of a type descriptor object (similar to a class instance)
1177
get(mlir::Type ofType)1178 TypeDescType fir::TypeDescType::get(mlir::Type ofType) {
1179 assert(!ofType.isa<ReferenceType>());
1180 return Base::get(ofType.getContext(), ofType);
1181 }
1182
getOfTy() const1183 mlir::Type fir::TypeDescType::getOfTy() const { return getImpl()->getOfType(); }
1184
1185 mlir::LogicalResult
verifyConstructionInvariants(mlir::Location loc,mlir::Type eleTy)1186 fir::TypeDescType::verifyConstructionInvariants(mlir::Location loc,
1187 mlir::Type eleTy) {
1188 if (eleTy.isa<BoxType>() || eleTy.isa<BoxCharType>() ||
1189 eleTy.isa<BoxProcType>() || eleTy.isa<DimsType>() ||
1190 eleTy.isa<FieldType>() || eleTy.isa<LenType>() ||
1191 eleTy.isa<ReferenceType>() || eleTy.isa<TypeDescType>())
1192 return mlir::emitError(loc, "cannot build a type descriptor of type: ")
1193 << eleTy << '\n';
1194 return mlir::success();
1195 }
1196
1197 namespace {
1198
printBounds(llvm::raw_ostream & os,const SequenceType::Shape & bounds)1199 void printBounds(llvm::raw_ostream &os, const SequenceType::Shape &bounds) {
1200 os << '<';
1201 for (auto &b : bounds) {
1202 if (b >= 0) {
1203 os << b << 'x';
1204 } else {
1205 os << "?x";
1206 }
1207 }
1208 }
1209
1210 llvm::SmallPtrSet<detail::RecordTypeStorage const *, 4> recordTypeVisited;
1211
1212 } // namespace
1213
verifyIntegralType(mlir::Type type)1214 void fir::verifyIntegralType(mlir::Type type) {
1215 if (isaIntegerType(type) || type.isa<mlir::IndexType>())
1216 return;
1217 llvm::report_fatal_error("expected integral type");
1218 }
1219
printFirType(FIROpsDialect *,mlir::Type ty,mlir::DialectAsmPrinter & p)1220 void fir::printFirType(FIROpsDialect *, mlir::Type ty,
1221 mlir::DialectAsmPrinter &p) {
1222 auto &os = p.getStream();
1223 if (auto type = ty.dyn_cast<BoxType>()) {
1224 os << "box<";
1225 p.printType(type.getEleTy());
1226 if (auto map = type.getLayoutMap()) {
1227 os << ", ";
1228 p.printAttribute(map);
1229 }
1230 os << '>';
1231 return;
1232 }
1233 if (auto type = ty.dyn_cast<BoxCharType>()) {
1234 os << "boxchar<" << type.getEleTy().cast<fir::CharacterType>().getFKind()
1235 << '>';
1236 return;
1237 }
1238 if (auto type = ty.dyn_cast<BoxProcType>()) {
1239 os << "boxproc<";
1240 p.printType(type.getEleTy());
1241 os << '>';
1242 return;
1243 }
1244 if (auto type = ty.dyn_cast<CharacterType>()) {
1245 os << "char<" << type.getFKind() << '>';
1246 return;
1247 }
1248 if (auto type = ty.dyn_cast<CplxType>()) {
1249 os << "complex<" << type.getFKind() << '>';
1250 return;
1251 }
1252 if (auto type = ty.dyn_cast<RecordType>()) {
1253 os << "type<" << type.getName();
1254 if (!recordTypeVisited.count(type.uniqueKey())) {
1255 recordTypeVisited.insert(type.uniqueKey());
1256 if (type.getLenParamList().size()) {
1257 char ch = '(';
1258 for (auto p : type.getLenParamList()) {
1259 os << ch << p.first << ':';
1260 p.second.print(os);
1261 ch = ',';
1262 }
1263 os << ')';
1264 }
1265 if (type.getTypeList().size()) {
1266 char ch = '{';
1267 for (auto p : type.getTypeList()) {
1268 os << ch << p.first << ':';
1269 p.second.print(os);
1270 ch = ',';
1271 }
1272 os << '}';
1273 }
1274 recordTypeVisited.erase(type.uniqueKey());
1275 }
1276 os << '>';
1277 return;
1278 }
1279 if (auto type = ty.dyn_cast<DimsType>()) {
1280 os << "dims<" << type.getRank() << '>';
1281 return;
1282 }
1283 if (ty.isa<FieldType>()) {
1284 os << "field";
1285 return;
1286 }
1287 if (auto type = ty.dyn_cast<HeapType>()) {
1288 os << "heap<";
1289 p.printType(type.getEleTy());
1290 os << '>';
1291 return;
1292 }
1293 if (auto type = ty.dyn_cast<fir::IntType>()) {
1294 os << "int<" << type.getFKind() << '>';
1295 return;
1296 }
1297 if (auto type = ty.dyn_cast<LenType>()) {
1298 os << "len";
1299 return;
1300 }
1301 if (auto type = ty.dyn_cast<LogicalType>()) {
1302 os << "logical<" << type.getFKind() << '>';
1303 return;
1304 }
1305 if (auto type = ty.dyn_cast<PointerType>()) {
1306 os << "ptr<";
1307 p.printType(type.getEleTy());
1308 os << '>';
1309 return;
1310 }
1311 if (auto type = ty.dyn_cast<fir::RealType>()) {
1312 os << "real<" << type.getFKind() << '>';
1313 return;
1314 }
1315 if (auto type = ty.dyn_cast<ReferenceType>()) {
1316 os << "ref<";
1317 p.printType(type.getEleTy());
1318 os << '>';
1319 return;
1320 }
1321 if (auto type = ty.dyn_cast<SequenceType>()) {
1322 os << "array";
1323 auto shape = type.getShape();
1324 if (shape.size()) {
1325 printBounds(os, shape);
1326 } else {
1327 os << "<*:";
1328 }
1329 p.printType(ty.cast<SequenceType>().getEleTy());
1330 if (auto map = type.getLayoutMap()) {
1331 os << ", ";
1332 map.print(os);
1333 }
1334 os << '>';
1335 return;
1336 }
1337 if (auto type = ty.dyn_cast<TypeDescType>()) {
1338 os << "tdesc<";
1339 p.printType(type.getOfTy());
1340 os << '>';
1341 return;
1342 }
1343 }
1344