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