CIRCT  18.0.0git
MooreTypes.cpp
Go to the documentation of this file.
1 //===- MooreTypes.cpp - Implement the Moore types -------------------------===//
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 // This file implement the Moore dialect type system.
10 //
11 //===----------------------------------------------------------------------===//
12 
15 #include "mlir/IR/Builders.h"
16 #include "mlir/IR/DialectImplementation.h"
17 #include "llvm/ADT/TypeSwitch.h"
18 
19 using namespace circt;
20 using namespace circt::moore;
21 using mlir::DialectAsmParser;
22 using mlir::DialectAsmPrinter;
23 using mlir::LocationAttr;
24 using mlir::OptionalParseResult;
25 using mlir::StringSwitch;
26 using mlir::TypeStorage;
27 using mlir::TypeStorageAllocator;
28 
29 //===----------------------------------------------------------------------===//
30 // Generated logic
31 //===----------------------------------------------------------------------===//
32 
33 #define GET_TYPEDEF_CLASSES
34 #include "circt/Dialect/Moore/MooreTypes.cpp.inc"
35 
36 void MooreDialect::registerTypes() {
42 #define GET_TYPEDEF_LIST
43 #include "circt/Dialect/Moore/MooreTypes.cpp.inc"
44  >();
45 }
46 
47 //===----------------------------------------------------------------------===//
48 // Utilities
49 //===----------------------------------------------------------------------===//
50 
51 StringRef moore::getKeywordFromSign(const Sign &sign) {
52  switch (sign) {
53  case Sign::Unsigned:
54  return "unsigned";
55  case Sign::Signed:
56  return "signed";
57  }
58  llvm_unreachable("all signs should be handled");
59 }
60 
61 std::optional<Sign> moore::getSignFromKeyword(StringRef keyword) {
62  return StringSwitch<std::optional<Sign>>(keyword)
63  .Case("unsigned", Sign::Unsigned)
64  .Case("signed", Sign::Signed)
65  .Default({});
66 }
67 
68 //===----------------------------------------------------------------------===//
69 // Simple Bit Vector Type
70 //===----------------------------------------------------------------------===//
71 
72 PackedType SimpleBitVectorType::getType(MLIRContext *context) const {
73  if (!*this)
74  return {};
75  std::optional<Sign> maybeSign;
76  if (explicitSign)
77  maybeSign = sign;
78 
79  // If the type originally used an integer atom, try to reconstruct that.
80  if (usedAtom)
82  return IntType::get(context, *kind, maybeSign);
83 
84  // Build the core integer bit type.
86  auto intType = IntType::get(context, kind, maybeSign);
87 
88  // If the vector is wider than a single bit, or the dimension was explicit in
89  // the original type, add a dimension around the bit type.
90  if (size > 1 || explicitSize)
91  return PackedRangeDim::get(intType, size);
92  return intType;
93 }
94 
95 //===----------------------------------------------------------------------===//
96 // Unpacked Type
97 //===----------------------------------------------------------------------===//
98 
100  return TypeSwitch<UnpackedType, UnpackedType>(*this)
102  [&](auto type) { return type.resolved(); })
103  .Default([](auto type) { return type; });
104 }
105 
107  return TypeSwitch<UnpackedType, UnpackedType>(*this)
109  [&](auto type) { return type.fullyResolved(); })
110  .Default([](auto type) { return type; });
111 }
112 
114  return TypeSwitch<UnpackedType, Domain>(*this)
115  .Case<PackedType>([](auto type) { return type.getDomain(); })
116  .Case<UnpackedIndirectType, UnpackedDim>(
117  [&](auto type) { return type.getInner().getDomain(); })
118  .Case<UnpackedStructType>(
119  [](auto type) { return type.getStruct().domain; })
120  .Default([](auto) { return Domain::TwoValued; });
121 }
122 
124  return TypeSwitch<UnpackedType, Sign>(*this)
125  .Case<PackedType>([](auto type) { return type.getSign(); })
126  .Case<UnpackedIndirectType, UnpackedDim>(
127  [&](auto type) { return type.getInner().getSign(); })
128  .Default([](auto) { return Sign::Unsigned; });
129 }
130 
131 std::optional<unsigned> UnpackedType::getBitSize() const {
132  return TypeSwitch<UnpackedType, std::optional<unsigned>>(*this)
133  .Case<PackedType, RealType>([](auto type) { return type.getBitSize(); })
134  .Case<UnpackedUnsizedDim>([](auto) { return std::nullopt; })
135  .Case<UnpackedArrayDim>([](auto type) -> std::optional<unsigned> {
136  if (auto size = type.getInner().getBitSize())
137  return (*size) * type.getSize();
138  return {};
139  })
140  .Case<UnpackedRangeDim>([](auto type) -> std::optional<unsigned> {
141  if (auto size = type.getInner().getBitSize())
142  return (*size) * type.getRange().size;
143  return {};
144  })
145  .Case<UnpackedIndirectType>(
146  [](auto type) { return type.getInner().getBitSize(); })
147  .Case<UnpackedStructType>(
148  [](auto type) { return type.getStruct().bitSize; })
149  .Default([](auto) { return std::nullopt; });
150 }
151 
152 /// Map an `IntType` to the corresponding SBVT. Never returns a null type.
154  auto bitSize = type.getBitSize();
155  bool usedAtom = bitSize > 1;
156  return SimpleBitVectorType(type.getDomain(), type.getSign(), bitSize,
157  usedAtom, type.isSignExplicit(), false);
158 }
159 
161  return TypeSwitch<UnpackedType, SimpleBitVectorType>(fullyResolved())
162  .Case<IntType>([](auto type) {
163  // Integer types trivially map to SBVTs.
164  return getSimpleBitVectorFromIntType(type);
165  })
166  .Case<PackedRangeDim>([](auto rangeType) {
167  // Inner type must be an integer.
168  auto innerType =
169  rangeType.getInner().fullyResolved().template dyn_cast<IntType>();
170  if (!innerType)
171  return SimpleBitVectorType{};
172 
173  // Inner type must be a single-bit integer. Cannot have integer atom
174  // vectors like `int [31:0]`.
176  if (sbv.usedAtom)
177  return SimpleBitVectorType{};
178 
179  // Range must be have non-zero size, and go downwards to zero.
180  auto range = rangeType.getRange();
181  if (range.size == 0 || range.offset != 0 || range.dir != RangeDir::Down)
182  return SimpleBitVectorType{};
183  sbv.explicitSize = true;
184  sbv.size = range.size;
185  return sbv;
186  })
187  .Default([](auto) { return SimpleBitVectorType{}; });
188 }
189 
191  // If the type is already a valid SBVT, return that immediately without
192  // casting.
193  if (auto sbv = getSimpleBitVectorOrNull())
194  return sbv;
195 
196  // All packed types with a known size (i.e., with no `[]` dimensions) can be
197  // cast to an SBVT.
198  auto packed = fullyResolved().dyn_cast<PackedType>();
199  if (!packed)
200  return {};
201  auto bitSize = packed.getBitSize();
202  if (!bitSize || *bitSize == 0)
203  return {};
204 
205  return SimpleBitVectorType(packed.getDomain(), packed.getSign(), *bitSize,
206  /*usedAtom=*/false, /*explicitSign=*/false,
207  /*explicitSize=*/false);
208 }
209 
211  llvm::raw_ostream &os,
212  llvm::function_ref<void(llvm::raw_ostream &os)> around) const {
213  TypeSwitch<UnpackedType>(*this)
214  .Case<StringType>([&](auto) { os << "string"; })
215  .Case<ChandleType>([&](auto) { os << "chandle"; })
216  .Case<EventType>([&](auto) { os << "event"; })
217  .Case<RealType>([&](auto type) { os << type.getKeyword(); })
218  .Case<PackedType, UnpackedStructType>([&](auto type) { type.format(os); })
219  .Case<UnpackedDim>([&](auto type) { type.format(os, around); })
220  .Case<UnpackedNamedType>(
221  [&](auto type) { os << type.getName().getValue(); })
222  .Case<UnpackedRefType>(
223  [&](auto type) { os << "type(" << type.getInner() << ")"; })
224  .Default([](auto) { llvm_unreachable("all types should be handled"); });
225 
226  // In case there were no unpacked dimensions, the `around` function was never
227  // called. However, callers expect us to be able to format things like `bit
228  // [7:0] fieldName`, where `fieldName` would be printed by `around`. So in
229  // case `around` is non-null, but no unpacked dimension had a chance to print
230  // it, simply print it now.
231  if (!isa<UnpackedDim>() && around) {
232  os << " ";
233  around(os);
234  }
235 }
236 
237 //===----------------------------------------------------------------------===//
238 // Packed Type
239 //===----------------------------------------------------------------------===//
240 
242  return TypeSwitch<PackedType, PackedType>(*this)
244  [&](auto type) { return type.resolved(); })
245  .Default([](auto type) { return type; });
246 }
247 
249  return TypeSwitch<PackedType, PackedType>(*this)
251  [&](auto type) { return type.fullyResolved(); })
252  .Default([](auto type) { return type; });
253 }
254 
256  return TypeSwitch<PackedType, Domain>(*this)
257  .Case<VoidType>([](auto) { return Domain::TwoValued; })
258  .Case<IntType>([&](auto type) { return type.getDomain(); })
259  .Case<PackedIndirectType, PackedDim>(
260  [&](auto type) { return type.getInner().getDomain(); })
261  .Case<EnumType>([](auto type) { return type.getBase().getDomain(); })
262  .Case<PackedStructType>(
263  [](auto type) { return type.getStruct().domain; });
264 }
265 
267  return TypeSwitch<PackedType, Sign>(*this)
268  .Case<VoidType>([](auto) { return Sign::Unsigned; })
269  .Case<IntType, PackedStructType>(
270  [&](auto type) { return type.getSign(); })
271  .Case<PackedIndirectType, PackedDim>(
272  [&](auto type) { return type.getInner().getSign(); })
273  .Case<EnumType>([](auto type) { return type.getBase().getSign(); });
274 }
275 
276 std::optional<unsigned> PackedType::getBitSize() const {
277  return TypeSwitch<PackedType, std::optional<unsigned>>(*this)
278  .Case<VoidType>([](auto) { return 0; })
279  .Case<IntType>([](auto type) { return type.getBitSize(); })
280  .Case<PackedUnsizedDim>([](auto) { return std::nullopt; })
281  .Case<PackedRangeDim>([](auto type) -> std::optional<unsigned> {
282  if (auto size = type.getInner().getBitSize())
283  return (*size) * type.getRange().size;
284  return {};
285  })
286  .Case<PackedIndirectType>(
287  [](auto type) { return type.getInner().getBitSize(); })
288  .Case<EnumType>([](auto type) { return type.getBase().getBitSize(); })
289  .Case<PackedStructType>(
290  [](auto type) { return type.getStruct().bitSize; });
291 }
292 
293 void PackedType::format(llvm::raw_ostream &os) const {
294  TypeSwitch<PackedType>(*this)
295  .Case<VoidType>([&](auto) { os << "void"; })
297  PackedStructType>([&](auto type) { type.format(os); })
298  .Case<PackedNamedType>(
299  [&](auto type) { os << type.getName().getValue(); })
300  .Case<PackedRefType>(
301  [&](auto type) { os << "type(" << type.getInner() << ")"; })
302  .Default([](auto) { llvm_unreachable("all types should be handled"); });
303 }
304 
305 //===----------------------------------------------------------------------===//
306 // Unit Types
307 //===----------------------------------------------------------------------===//
308 
309 VoidType VoidType::get(MLIRContext *context) { return Base::get(context); }
310 
311 StringType StringType::get(MLIRContext *context) { return Base::get(context); }
312 
313 ChandleType ChandleType::get(MLIRContext *context) {
314  return Base::get(context);
315 }
316 
317 EventType EventType::get(MLIRContext *context) { return Base::get(context); }
318 
319 //===----------------------------------------------------------------------===//
320 // Packed Integers
321 //===----------------------------------------------------------------------===//
322 
323 namespace circt {
324 namespace moore {
325 namespace detail {
326 struct IntTypeStorage : TypeStorage {
327  using KeyTy = unsigned;
329 
331  : kind(static_cast<Kind>((key >> 16) & 0xFF)),
332  sign(static_cast<Sign>((key >> 8) & 0xFF)), explicitSign(key & 1) {}
333  static KeyTy pack(Kind kind, Sign sign, bool explicitSign) {
334  return static_cast<unsigned>(kind) << 16 |
335  static_cast<unsigned>(sign) << 8 | explicitSign;
336  }
337  bool operator==(const KeyTy &key) const {
338  return pack(kind, sign, explicitSign) == key;
339  }
340  static IntTypeStorage *construct(TypeStorageAllocator &allocator,
341  const KeyTy &key) {
342  return new (allocator.allocate<IntTypeStorage>()) IntTypeStorage(key);
343  }
344 
348 };
349 } // namespace detail
350 } // namespace moore
351 } // namespace circt
352 
353 std::optional<IntType::Kind> IntType::getKindFromKeyword(StringRef keyword) {
354  return StringSwitch<std::optional<Kind>>(keyword)
355  .Case("bit", IntType::Bit)
356  .Case("logic", IntType::Logic)
357  .Case("reg", IntType::Reg)
358  .Case("byte", IntType::Byte)
359  .Case("shortint", IntType::ShortInt)
360  .Case("int", IntType::Int)
361  .Case("longint", IntType::LongInt)
362  .Case("integer", IntType::Integer)
363  .Case("time", IntType::Time)
364  .Default({});
365 }
366 
367 StringRef IntType::getKeyword(Kind kind) {
368  switch (kind) {
369  case IntType::Bit:
370  return "bit";
371  case IntType::Logic:
372  return "logic";
373  case IntType::Reg:
374  return "reg";
375  case IntType::Byte:
376  return "byte";
377  case IntType::ShortInt:
378  return "shortint";
379  case IntType::Int:
380  return "int";
381  case IntType::LongInt:
382  return "longint";
383  case IntType::Integer:
384  return "integer";
385  case IntType::Time:
386  return "time";
387  }
388  llvm_unreachable("all kinds should be handled");
389 }
390 
392  switch (kind) {
393  case IntType::Bit:
394  case IntType::Logic:
395  case IntType::Reg:
396  case IntType::Time:
397  return Sign::Unsigned;
398  case IntType::Byte:
399  case IntType::ShortInt:
400  case IntType::Int:
401  case IntType::LongInt:
402  case IntType::Integer:
403  return Sign::Signed;
404  }
405  llvm_unreachable("all kinds should be handled");
406 }
407 
409  switch (kind) {
410  case IntType::Bit:
411  case IntType::Byte:
412  case IntType::ShortInt:
413  case IntType::Int:
414  case IntType::LongInt:
415  case IntType::Time:
416  return Domain::TwoValued;
417  case IntType::Logic:
418  case IntType::Reg:
419  case IntType::Integer:
420  return Domain::FourValued;
421  }
422  llvm_unreachable("all kinds should be handled");
423 }
424 
425 unsigned IntType::getBitSize(Kind kind) {
426  switch (kind) {
427  case IntType::Bit:
428  case IntType::Logic:
429  case IntType::Reg:
430  return 1;
431  case IntType::Byte:
432  return 8;
433  case IntType::ShortInt:
434  return 16;
435  case IntType::Int:
436  return 32;
437  case IntType::LongInt:
438  return 64;
439  case IntType::Integer:
440  return 32;
441  case IntType::Time:
442  return 64;
443  }
444  llvm_unreachable("all kinds should be handled");
445 }
446 
447 std::optional<IntType::Kind> IntType::getKindFromDomainAndSize(Domain domain,
448  unsigned size) {
449  switch (domain) {
450  case Domain::TwoValued:
451  switch (size) {
452  case 1:
453  return IntType::Bit;
454  case 8:
455  return IntType::Byte;
456  case 16:
457  return IntType::ShortInt;
458  case 32:
459  return IntType::Int;
460  case 64:
461  return IntType::LongInt;
462  default:
463  return {};
464  }
465  case Domain::FourValued:
466  switch (size) {
467  case 1:
468  return IntType::Logic;
469  case 32:
470  return IntType::Integer;
471  default:
472  return {};
473  }
474  }
475  llvm_unreachable("all domains should be handled");
476 }
477 
478 IntType IntType::get(MLIRContext *context, Kind kind,
479  std::optional<Sign> sign) {
480  return Base::get(context, detail::IntTypeStorage::pack(
481  kind, sign.value_or(getDefaultSign(kind)),
482  sign.has_value()));
483 }
484 
485 IntType::Kind IntType::getKind() const { return getImpl()->kind; }
486 
487 Sign IntType::getSign() const { return getImpl()->sign; }
488 
489 bool IntType::isSignExplicit() const { return getImpl()->explicitSign; }
490 
491 void IntType::format(llvm::raw_ostream &os) const {
492  os << getKeyword();
493  auto sign = getSign();
494  if (isSignExplicit() || sign != getDefaultSign())
495  os << " " << sign;
496 }
497 
498 //===----------------------------------------------------------------------===//
499 // Unpacked Reals
500 //===----------------------------------------------------------------------===//
501 
502 namespace circt {
503 namespace moore {
504 namespace detail {
505 struct RealTypeStorage : TypeStorage {
506  using KeyTy = unsigned;
508 
509  RealTypeStorage(KeyTy key) : kind(static_cast<Kind>(key)) {}
510  bool operator==(const KeyTy &key) const {
511  return kind == static_cast<Kind>(key);
512  }
513  static RealTypeStorage *construct(TypeStorageAllocator &allocator,
514  const KeyTy &key) {
515  return new (allocator.allocate<RealTypeStorage>()) RealTypeStorage(key);
516  }
517 
519 };
520 } // namespace detail
521 } // namespace moore
522 } // namespace circt
523 
524 std::optional<RealType::Kind> RealType::getKindFromKeyword(StringRef keyword) {
525  return StringSwitch<std::optional<Kind>>(keyword)
526  .Case("shortreal", ShortReal)
527  .Case("real", Real)
528  .Case("realtime", RealTime)
529  .Default({});
530 }
531 
532 StringRef RealType::getKeyword(Kind kind) {
533  switch (kind) {
534  case ShortReal:
535  return "shortreal";
536  case Real:
537  return "real";
538  case RealTime:
539  return "realtime";
540  }
541  llvm_unreachable("all kinds should be handled");
542 }
543 
544 unsigned RealType::getBitSize(Kind kind) {
545  switch (kind) {
546  case ShortReal:
547  return 32;
548  case Real:
549  return 64;
550  case RealTime:
551  return 64;
552  }
553  llvm_unreachable("all kinds should be handled");
554 }
555 
556 RealType RealType::get(MLIRContext *context, Kind kind) {
557  return Base::get(context, static_cast<unsigned>(kind));
558 }
559 
560 RealType::Kind RealType::getKind() const { return getImpl()->kind; }
561 
562 //===----------------------------------------------------------------------===//
563 // Packed Type Indirections
564 //===----------------------------------------------------------------------===//
565 
566 namespace circt {
567 namespace moore {
568 namespace detail {
569 
570 struct IndirectTypeStorage : TypeStorage {
571  using KeyTy = std::tuple<UnpackedType, StringAttr, LocationAttr>;
572 
574  : IndirectTypeStorage(std::get<0>(key), std::get<1>(key),
575  std::get<2>(key)) {}
576  IndirectTypeStorage(UnpackedType inner, StringAttr name, LocationAttr loc)
577  : inner(inner), name(name), loc(loc) {}
578  bool operator==(const KeyTy &key) const {
579  return std::get<0>(key) == inner && std::get<1>(key) == name &&
580  std::get<2>(key) == loc;
581  }
582  static IndirectTypeStorage *construct(TypeStorageAllocator &allocator,
583  const KeyTy &key) {
584  return new (allocator.allocate<IndirectTypeStorage>())
585  IndirectTypeStorage(key);
586  }
587 
589  StringAttr name;
590  LocationAttr loc;
591 };
592 
593 UnpackedType getIndirectTypeInner(const TypeStorage *impl) {
594  return static_cast<const IndirectTypeStorage *>(impl)->inner;
595 }
596 
597 Location getIndirectTypeLoc(const TypeStorage *impl) {
598  return static_cast<const IndirectTypeStorage *>(impl)->loc;
599 }
600 
601 StringAttr getIndirectTypeName(const TypeStorage *impl) {
602  return static_cast<const IndirectTypeStorage *>(impl)->name;
603 }
604 
605 } // namespace detail
606 } // namespace moore
607 } // namespace circt
608 
609 template <>
611  PackedType inner, StringAttr name, Location loc) {
612  return Base::get(inner.getContext(), inner, name, loc);
613 }
614 
615 template <>
617  UnpackedType inner, StringAttr name, Location loc) {
618  return Base::get(inner.getContext(), inner, name, loc);
619 }
620 
621 template <>
624  Location loc) {
625  return Base::get(inner.getContext(), inner, StringAttr{}, loc);
626 }
627 
628 template <>
631  Location loc) {
632  return Base::get(inner.getContext(), inner, StringAttr{}, loc);
633 }
634 
635 //===----------------------------------------------------------------------===//
636 // Packed Dimensions
637 //===----------------------------------------------------------------------===//
638 
639 namespace circt {
640 namespace moore {
641 namespace detail {
642 
643 struct DimStorage : TypeStorage {
645 
646  DimStorage(KeyTy key) : inner(key) {}
647  bool operator==(const KeyTy &key) const { return key == inner; }
648  static DimStorage *construct(TypeStorageAllocator &allocator,
649  const KeyTy &key) {
650  return new (allocator.allocate<DimStorage>()) DimStorage(key);
651  }
652 
653  // Mutation function to late-initialize the resolved versions of the type.
654  LogicalResult mutate(TypeStorageAllocator &allocator,
655  UnpackedType newResolved,
656  UnpackedType newFullyResolved) {
657  // Cannot set change resolved types once they've been initialized.
658  if (resolved && resolved != newResolved)
659  return failure();
660  if (fullyResolved && fullyResolved != newFullyResolved)
661  return failure();
662 
663  // Update the resolved types.
664  resolved = newResolved;
665  fullyResolved = newFullyResolved;
666  return success();
667  }
668 
669  /// Each dimension type calls this function from its `get` method. The first
670  /// argument, `dim`, is set to the type that was constructed by the call to
671  /// `Base::get`. If that type has just been created, its `resolved` and
672  /// `fullyResolved` fields are not yet set. If that is the case, the
673  /// `finalize` method constructs the these resolved types by resolving the
674  /// inner type appropriately and wrapping it in the dimension type. These
675  /// wrapped types, which are equivalent to the `dim` itself but with the inner
676  /// type resolved, are passed to `DimStorage::mutate` which fills in the
677  /// `resolved` and `fullyResolved` fields behind a storage lock in the
678  /// MLIRContext.
679  ///
680  /// This has been inspired by https://reviews.llvm.org/D84171.
681  template <class ConcreteDim, typename... Args>
682  void finalize(ConcreteDim dim, Args... args) const {
683  if (resolved && fullyResolved)
684  return;
685  auto inner = dim.getInner();
686  auto newResolved = dim;
687  auto newFullyResolved = dim;
688  if (inner != inner.resolved())
689  newResolved = ConcreteDim::get(inner.resolved(), args...);
690  if (inner != inner.fullyResolved())
691  newFullyResolved = ConcreteDim::get(inner.fullyResolved(), args...);
692  auto result = dim.mutate(newResolved, newFullyResolved);
693  (void)result; // Supress warning
694  assert(succeeded(result));
695  }
696 
700 };
701 
704  static UnsizedDimStorage *construct(TypeStorageAllocator &allocator,
705  const KeyTy &key) {
706  return new (allocator.allocate<UnsizedDimStorage>()) UnsizedDimStorage(key);
707  }
708 };
709 
711  using KeyTy = std::pair<UnpackedType, Range>;
712 
713  RangeDimStorage(KeyTy key) : DimStorage(key.first), range(key.second) {}
714  bool operator==(const KeyTy &key) const {
715  return key.first == inner && key.second == range;
716  }
717  static RangeDimStorage *construct(TypeStorageAllocator &allocator,
718  const KeyTy &key) {
719  return new (allocator.allocate<RangeDimStorage>()) RangeDimStorage(key);
720  }
721 
723 };
724 
725 } // namespace detail
726 } // namespace moore
727 } // namespace circt
728 
729 PackedType PackedDim::getInner() const {
730  return getImpl()->inner.cast<PackedType>();
731 }
732 
733 void PackedDim::format(llvm::raw_ostream &os) const {
734  SmallVector<PackedDim> dims;
735  dims.push_back(*this);
736  for (;;) {
737  PackedType inner = dims.back().getInner();
738  if (auto dim = inner.dyn_cast<PackedDim>()) {
739  dims.push_back(dim);
740  } else {
741  inner.format(os);
742  break;
743  }
744  }
745  os << " ";
746  for (auto dim : dims) {
747  dim.formatDim(os);
748  }
749 }
750 
751 void PackedDim::formatDim(llvm::raw_ostream &os) const {
752  TypeSwitch<PackedDim>(*this)
753  .Case<PackedRangeDim>(
754  [&](auto dim) { os << "[" << dim.getRange() << "]"; })
755  .Case<PackedUnsizedDim>([&](auto dim) { os << "[]"; })
756  .Default([&](auto) { llvm_unreachable("unhandled dim type"); });
757 }
758 
760  return getImpl()->resolved.cast<PackedType>();
761 }
762 
764  return getImpl()->fullyResolved.cast<PackedType>();
765 }
766 
767 std::optional<Range> PackedDim::getRange() const {
768  if (auto dim = dyn_cast<PackedRangeDim>())
769  return dim.getRange();
770  return {};
771 }
772 
773 std::optional<unsigned> PackedDim::getSize() const {
774  return llvm::transformOptional(getRange(), [](auto r) { return r.size; });
775 }
776 
778  return static_cast<detail::DimStorage *>(this->impl);
779 }
780 
782  auto type = Base::get(inner.getContext(), inner);
783  type.getImpl()->finalize<PackedUnsizedDim>(type);
784  return type;
785 }
786 
788  auto type = Base::get(inner.getContext(), inner, range);
789  type.getImpl()->finalize<PackedRangeDim>(type, range);
790  return type;
791 }
792 
793 Range PackedRangeDim::getRange() const { return getImpl()->range; }
794 
795 //===----------------------------------------------------------------------===//
796 // Unpacked Dimensions
797 //===----------------------------------------------------------------------===//
798 
799 namespace circt {
800 namespace moore {
801 namespace detail {
802 
804  using KeyTy = std::pair<UnpackedType, unsigned>;
805 
806  SizedDimStorage(KeyTy key) : DimStorage(key.first), size(key.second) {}
807  bool operator==(const KeyTy &key) const {
808  return key.first == inner && key.second == size;
809  }
810  static SizedDimStorage *construct(TypeStorageAllocator &allocator,
811  const KeyTy &key) {
812  return new (allocator.allocate<SizedDimStorage>()) SizedDimStorage(key);
813  }
814 
815  unsigned size;
816 };
817 
819  using KeyTy = std::pair<UnpackedType, UnpackedType>;
820 
821  AssocDimStorage(KeyTy key) : DimStorage(key.first), indexType(key.second) {}
822  bool operator==(const KeyTy &key) const {
823  return key.first == inner && key.second == indexType;
824  }
825  static AssocDimStorage *construct(TypeStorageAllocator &allocator,
826  const KeyTy &key) {
827  return new (allocator.allocate<AssocDimStorage>()) AssocDimStorage(key);
828  }
829 
831 };
832 
833 } // namespace detail
834 } // namespace moore
835 } // namespace circt
836 
838 
840  llvm::raw_ostream &os,
841  llvm::function_ref<void(llvm::raw_ostream &)> around) const {
842  SmallVector<UnpackedDim> dims;
843  dims.push_back(*this);
844  for (;;) {
845  UnpackedType inner = dims.back().getInner();
846  if (auto dim = inner.dyn_cast<UnpackedDim>()) {
847  dims.push_back(dim);
848  } else {
849  inner.format(os);
850  break;
851  }
852  }
853  os << " ";
854  if (around)
855  around(os);
856  else
857  os << "$";
858  os << " ";
859  for (auto dim : dims) {
860  dim.formatDim(os);
861  }
862 }
863 
864 void UnpackedDim::formatDim(llvm::raw_ostream &os) const {
865  TypeSwitch<UnpackedDim>(*this)
866  .Case<UnpackedUnsizedDim>([&](auto dim) { os << "[]"; })
867  .Case<UnpackedArrayDim>(
868  [&](auto dim) { os << "[" << dim.getSize() << "]"; })
869  .Case<UnpackedRangeDim>(
870  [&](auto dim) { os << "[" << dim.getRange() << "]"; })
871  .Case<UnpackedAssocDim>([&](auto dim) {
872  os << "[";
873  if (auto indexType = dim.getIndexType())
874  indexType.format(os);
875  else
876  os << "*";
877  os << "]";
878  })
879  .Case<UnpackedQueueDim>([&](auto dim) {
880  os << "[$";
881  if (auto bound = dim.getBound())
882  os << ":" << *bound;
883  os << "]";
884  })
885  .Default([&](auto) { llvm_unreachable("unhandled dim type"); });
886 }
887 
889 
891  return getImpl()->fullyResolved;
892 }
893 
895  return static_cast<detail::DimStorage *>(this->impl);
896 }
897 
899  auto type = Base::get(inner.getContext(), inner);
900  type.getImpl()->finalize<UnpackedUnsizedDim>(type);
901  return type;
902 }
903 
905  auto type = Base::get(inner.getContext(), inner, size);
906  type.getImpl()->finalize<UnpackedArrayDim>(type, size);
907  return type;
908 }
909 
910 unsigned UnpackedArrayDim::getSize() const { return getImpl()->size; }
911 
913  auto type = Base::get(inner.getContext(), inner, range);
914  type.getImpl()->finalize<UnpackedRangeDim>(type, range);
915  return type;
916 }
917 
918 Range UnpackedRangeDim::getRange() const { return getImpl()->range; }
919 
921  UnpackedType indexType) {
922  auto type = Base::get(inner.getContext(), inner, indexType);
923  type.getImpl()->finalize<UnpackedAssocDim>(type, indexType);
924  return type;
925 }
926 
928  return getImpl()->indexType;
929 }
930 
932  std::optional<unsigned> bound) {
933  auto type = Base::get(inner.getContext(), inner, bound.value_or(-1));
934  type.getImpl()->finalize<UnpackedQueueDim>(type, bound);
935  return type;
936 }
937 
938 std::optional<unsigned> UnpackedQueueDim::getBound() const {
939  unsigned bound = getImpl()->size;
940  if (bound == static_cast<unsigned>(-1))
941  return {};
942  return bound;
943 }
944 
945 //===----------------------------------------------------------------------===//
946 // Enumerations
947 //===----------------------------------------------------------------------===//
948 
949 namespace circt {
950 namespace moore {
951 namespace detail {
952 
953 struct EnumTypeStorage : TypeStorage {
954  using KeyTy = std::tuple<StringAttr, Location, PackedType, char>;
955 
957  : name(std::get<0>(key)), loc(std::get<1>(key)), base(std::get<2>(key)),
958  explicitBase(std::get<3>(key)) {}
959  bool operator==(const KeyTy &key) const {
960  return std::get<0>(key) == name && std::get<1>(key) == loc &&
961  std::get<2>(key) == base && std::get<3>(key) == explicitBase;
962  }
963  static EnumTypeStorage *construct(TypeStorageAllocator &allocator,
964  const KeyTy &key) {
965  return new (allocator.allocate<EnumTypeStorage>()) EnumTypeStorage(key);
966  }
967 
968  StringAttr name;
969  Location loc;
972 };
973 
974 } // namespace detail
975 } // namespace moore
976 } // namespace circt
977 
978 EnumType EnumType::get(StringAttr name, Location loc, PackedType base) {
979  return Base::get(loc.getContext(), name, loc,
980  base ? base : IntType::getInt(loc.getContext()), !!base);
981 }
982 
983 PackedType EnumType::getBase() const { return getImpl()->base; }
984 
985 bool EnumType::isBaseExplicit() const { return getImpl()->explicitBase; }
986 
987 StringAttr EnumType::getName() const { return getImpl()->name; }
988 
989 Location EnumType::getLoc() const { return getImpl()->loc; }
990 
991 void EnumType::format(llvm::raw_ostream &os) const {
992  os << "enum";
993 
994  // If the enum is part of a typedefm simply print it as `enum <name>`.
995  if (auto name = getName()) {
996  os << " " << name.getValue();
997  return;
998  }
999 
1000  // Otherwise print `enum <base-type>` or just `enum`.
1001  if (isBaseExplicit())
1002  os << " " << getBase();
1003 }
1004 
1005 //===----------------------------------------------------------------------===//
1006 // Packed and Unpacked Structs
1007 //===----------------------------------------------------------------------===//
1008 
1010  switch (kind) {
1011  case StructKind::Struct:
1012  return "struct";
1013  case StructKind::Union:
1014  return "union";
1016  return "tagged_union";
1017  }
1018  llvm_unreachable("all struct kinds should be handled");
1019 }
1020 
1021 std::optional<StructKind> moore::getStructKindFromMnemonic(StringRef mnemonic) {
1022  return StringSwitch<std::optional<StructKind>>(mnemonic)
1023  .Case("struct", StructKind::Struct)
1024  .Case("union", StructKind::Union)
1025  .Case("tagged_union", StructKind::TaggedUnion)
1026  .Default({});
1027 }
1028 
1029 Struct::Struct(StructKind kind, ArrayRef<StructMember> members, StringAttr name,
1030  Location loc)
1031  : kind(kind), members(members.begin(), members.end()), name(name),
1032  loc(loc) {
1033  // The struct's value domain is two-valued if all members are two-valued.
1034  // Otherwise it is four-valued.
1035  domain = llvm::all_of(members,
1036  [](auto &member) {
1037  return member.type.getDomain() == Domain::TwoValued;
1038  })
1041 
1042  // The bit size is the sum of all member bit sizes, or `None` if any of the
1043  // member bit sizes are `None`.
1044  bitSize = 0;
1045  for (const auto &member : members) {
1046  if (auto memberSize = member.type.getBitSize()) {
1047  *bitSize += *memberSize;
1048  } else {
1049  bitSize = std::nullopt;
1050  break;
1051  }
1052  }
1053 }
1054 
1055 void Struct::format(llvm::raw_ostream &os, bool packed,
1056  std::optional<Sign> signing) const {
1057  os << kind;
1058  if (packed)
1059  os << " packed";
1060  if (signing)
1061  os << " " << *signing;
1062 
1063  // If the struct is part of a typedef, simply print it as `struct <name>`.
1064  if (name) {
1065  os << " " << name.getValue();
1066  return;
1067  }
1068 
1069  // Otherwise actually print the struct definition inline.
1070  os << " {";
1071  for (auto &member : members)
1072  os << " " << member.type << " " << member.name.getValue() << ";";
1073  if (!members.empty())
1074  os << " ";
1075  os << "}";
1076 }
1077 
1078 namespace circt {
1079 namespace moore {
1080 namespace detail {
1081 
1082 struct StructTypeStorage : TypeStorage {
1083  using KeyTy =
1084  std::tuple<unsigned, ArrayRef<StructMember>, StringAttr, Location>;
1085 
1087  : strukt(static_cast<StructKind>((std::get<0>(key) >> 16) & 0xFF),
1088  std::get<1>(key), std::get<2>(key), std::get<3>(key)),
1089  sign(static_cast<Sign>((std::get<0>(key) >> 8) & 0xFF)),
1090  explicitSign((std::get<0>(key) >> 0) & 1) {}
1091  static unsigned pack(StructKind kind, Sign sign, bool explicitSign) {
1092  return static_cast<unsigned>(kind) << 16 |
1093  static_cast<unsigned>(sign) << 8 | explicitSign;
1094  }
1095  bool operator==(const KeyTy &key) const {
1096  return std::get<0>(key) == pack(strukt.kind, sign, explicitSign) &&
1097  std::get<1>(key) == ArrayRef<StructMember>(strukt.members) &&
1098  std::get<2>(key) == strukt.name && std::get<3>(key) == strukt.loc;
1099  }
1100  static StructTypeStorage *construct(TypeStorageAllocator &allocator,
1101  const KeyTy &key) {
1102  return new (allocator.allocate<StructTypeStorage>()) StructTypeStorage(key);
1103  }
1104 
1108 };
1109 
1110 } // namespace detail
1111 } // namespace moore
1112 } // namespace circt
1113 
1115  ArrayRef<StructMember> members,
1116  StringAttr name, Location loc,
1117  std::optional<Sign> sign) {
1118  assert(llvm::all_of(members,
1119  [](const StructMember &member) {
1120  return member.type.isa<PackedType>();
1121  }) &&
1122  "packed struct members must be packed");
1123  return Base::get(loc.getContext(),
1125  kind, sign.value_or(Sign::Unsigned), sign.has_value()),
1126  members, name, loc);
1127 }
1128 
1129 Sign PackedStructType::getSign() const { return getImpl()->sign; }
1130 
1132  return getImpl()->explicitSign;
1133 }
1134 
1135 const Struct &PackedStructType::getStruct() const { return getImpl()->strukt; }
1136 
1138  ArrayRef<StructMember> members,
1139  StringAttr name, Location loc) {
1140  return Base::get(loc.getContext(),
1142  members, name, loc);
1143 }
1144 
1146  return getImpl()->strukt;
1147 }
1148 
1149 //===----------------------------------------------------------------------===//
1150 // Parsing and Printing
1151 //===----------------------------------------------------------------------===//
1152 
1153 struct Subset {
1154  enum { None, Unpacked, Packed } implied = None;
1155  bool allowUnpacked = true;
1156 };
1157 
1158 static ParseResult parseMooreType(DialectAsmParser &parser, Subset subset,
1159  Type &type);
1160 static void printMooreType(Type type, DialectAsmPrinter &printer,
1161  Subset subset);
1162 
1163 /// Parse a type with custom syntax.
1164 static OptionalParseResult customTypeParser(DialectAsmParser &parser,
1165  StringRef mnemonic, Subset subset,
1166  llvm::SMLoc loc, Type &type) {
1167  auto *context = parser.getContext();
1168 
1169  auto yieldPacked = [&](PackedType x) {
1170  type = x;
1171  return success();
1172  };
1173  auto yieldUnpacked = [&](UnpackedType x) {
1174  if (!subset.allowUnpacked) {
1175  parser.emitError(loc)
1176  << "unpacked type " << x << " where only packed types are allowed";
1177  return failure();
1178  }
1179  type = x;
1180  return success();
1181  };
1182  auto yieldImplied =
1183  [&](llvm::function_ref<PackedType()> ifPacked,
1184  llvm::function_ref<UnpackedType()> ifUnpacked) {
1185  if (subset.implied == Subset::Packed)
1186  return yieldPacked(ifPacked());
1187  if (subset.implied == Subset::Unpacked)
1188  return yieldUnpacked(ifUnpacked());
1189  parser.emitError(loc)
1190  << "ambiguous packing; wrap `" << mnemonic
1191  << "` in `packed<...>` or `unpacked<...>` to disambiguate";
1192  return failure();
1193  };
1194 
1195  // Explicit packing indicators, like `unpacked.named`.
1196  if (mnemonic == "unpacked") {
1197  UnpackedType inner;
1198  if (parser.parseLess() ||
1199  parseMooreType(parser, {Subset::Unpacked, true}, inner) ||
1200  parser.parseGreater())
1201  return failure();
1202  return yieldUnpacked(inner);
1203  }
1204  if (mnemonic == "packed") {
1205  PackedType inner;
1206  if (parser.parseLess() ||
1207  parseMooreType(parser, {Subset::Packed, false}, inner) ||
1208  parser.parseGreater())
1209  return failure();
1210  return yieldPacked(inner);
1211  }
1212 
1213  // Packed primary types.
1214  if (mnemonic == "void")
1215  return yieldPacked(VoidType::get(context));
1216 
1217  if (auto kind = IntType::getKindFromKeyword(mnemonic)) {
1218  std::optional<Sign> sign;
1219  if (succeeded(parser.parseOptionalLess())) {
1220  StringRef signKeyword;
1221  if (parser.parseKeyword(&signKeyword) || parser.parseGreater())
1222  return failure();
1223  sign = getSignFromKeyword(signKeyword);
1224  if (!sign) {
1225  parser.emitError(parser.getCurrentLocation())
1226  << "expected keyword `unsigned` or `signed`";
1227  return failure();
1228  }
1229  }
1230  return yieldPacked(IntType::get(context, *kind, sign));
1231  }
1232 
1233  // Unpacked primary types.
1234  if (mnemonic == "string")
1235  return yieldUnpacked(StringType::get(context));
1236  if (mnemonic == "chandle")
1237  return yieldUnpacked(ChandleType::get(context));
1238  if (mnemonic == "event")
1239  return yieldUnpacked(EventType::get(context));
1240  if (auto kind = RealType::getKindFromKeyword(mnemonic))
1241  return yieldUnpacked(RealType::get(context, *kind));
1242 
1243  // Enums
1244  if (mnemonic == "enum") {
1245  if (parser.parseLess())
1246  return failure();
1247  StringAttr name;
1248  auto result = parser.parseOptionalAttribute(name);
1249  if (result.has_value())
1250  if (*result || parser.parseComma())
1251  return failure();
1252  LocationAttr loc;
1253  PackedType base;
1254  result = parser.parseOptionalAttribute(loc);
1255  if (result.has_value()) {
1256  if (*result)
1257  return failure();
1258  } else {
1259  if (parseMooreType(parser, {Subset::Packed, false}, base) ||
1260  parser.parseComma() || parser.parseAttribute(loc))
1261  return failure();
1262  }
1263  if (parser.parseGreater())
1264  return failure();
1265  return yieldPacked(EnumType::get(name, loc, base));
1266  }
1267 
1268  // Everything that follows can be packed or unpacked. The packing is inferred
1269  // from the last `packed<...>` or `unpacked<...>` that we've seen. The
1270  // `yieldImplied` function will call the first lambda to construct a packed
1271  // type, or the second lambda to construct an unpacked type. If the
1272  // `subset.implied` field is not set, which means there hasn't been any prior
1273  // `packed` or `unpacked`, the function will emit an error properly.
1274 
1275  // Packed and unpacked type indirections.
1276  if (mnemonic == "named") {
1277  UnpackedType inner;
1278  StringAttr name;
1279  LocationAttr loc;
1280  if (parser.parseLess() || parser.parseAttribute(name) ||
1281  parser.parseComma() || parseMooreType(parser, subset, inner) ||
1282  parser.parseComma() || parser.parseAttribute(loc) ||
1283  parser.parseGreater())
1284  return failure();
1285  return yieldImplied(
1286  [&]() {
1287  return PackedNamedType::get(inner.cast<PackedType>(), name, loc);
1288  },
1289  [&]() { return UnpackedNamedType::get(inner, name, loc); });
1290  }
1291  if (mnemonic == "ref") {
1292  UnpackedType inner;
1293  LocationAttr loc;
1294  if (parser.parseLess() || parseMooreType(parser, subset, inner) ||
1295  parser.parseComma() || parser.parseAttribute(loc) ||
1296  parser.parseGreater())
1297  return failure();
1298  return yieldImplied(
1299  [&]() { return PackedRefType::get(inner.cast<PackedType>(), loc); },
1300  [&]() { return UnpackedRefType::get(inner, loc); });
1301  }
1302 
1303  // Packed and unpacked ranges.
1304  if (mnemonic == "unsized") {
1305  UnpackedType inner;
1306  if (parser.parseLess() || parseMooreType(parser, subset, inner) ||
1307  parser.parseGreater())
1308  return failure();
1309  return yieldImplied(
1310  [&]() { return PackedUnsizedDim::get(inner.cast<PackedType>()); },
1311  [&]() { return UnpackedUnsizedDim::get(inner); });
1312  }
1313  if (mnemonic == "range") {
1314  UnpackedType inner;
1315  int left, right;
1316  if (parser.parseLess() || parseMooreType(parser, subset, inner) ||
1317  parser.parseComma() || parser.parseInteger(left) ||
1318  parser.parseColon() || parser.parseInteger(right) ||
1319  parser.parseGreater())
1320  return failure();
1321  return yieldImplied(
1322  [&]() {
1323  return PackedRangeDim::get(inner.cast<PackedType>(), left, right);
1324  },
1325  [&]() { return UnpackedRangeDim::get(inner, left, right); });
1326  }
1327  if (mnemonic == "array") {
1328  UnpackedType inner;
1329  unsigned size;
1330  if (parser.parseLess() || parseMooreType(parser, subset, inner) ||
1331  parser.parseComma() || parser.parseInteger(size) ||
1332  parser.parseGreater())
1333  return failure();
1334  return yieldUnpacked(UnpackedArrayDim::get(inner, size));
1335  }
1336  if (mnemonic == "assoc") {
1337  UnpackedType inner;
1338  UnpackedType index;
1339  if (parser.parseLess() || parseMooreType(parser, subset, inner))
1340  return failure();
1341  if (succeeded(parser.parseOptionalComma())) {
1342  if (parseMooreType(parser, {Subset::Unpacked, true}, index))
1343  return failure();
1344  }
1345  if (parser.parseGreater())
1346  return failure();
1347  return yieldUnpacked(UnpackedAssocDim::get(inner, index));
1348  }
1349  if (mnemonic == "queue") {
1350  UnpackedType inner;
1351  std::optional<unsigned> size;
1352  if (parser.parseLess() || parseMooreType(parser, subset, inner))
1353  return failure();
1354  if (succeeded(parser.parseOptionalComma())) {
1355  unsigned tmpSize;
1356  if (parser.parseInteger(tmpSize))
1357  return failure();
1358  size = tmpSize;
1359  }
1360  if (parser.parseGreater())
1361  return failure();
1362  return yieldUnpacked(UnpackedQueueDim::get(inner, size));
1363  }
1364 
1365  // Structs
1366  if (auto kind = getStructKindFromMnemonic(mnemonic)) {
1367  if (parser.parseLess())
1368  return failure();
1369 
1370  StringAttr name;
1371  auto result = parser.parseOptionalAttribute(name);
1372  if (result.has_value())
1373  if (*result || parser.parseComma())
1374  return failure();
1375 
1376  std::optional<Sign> sign;
1377  StringRef keyword;
1378  if (succeeded(parser.parseOptionalKeyword(&keyword))) {
1379  sign = getSignFromKeyword(keyword);
1380  if (!sign) {
1381  parser.emitError(loc) << "expected keyword `unsigned` or `signed`";
1382  return failure();
1383  }
1384  if (subset.implied == Subset::Unpacked) {
1385  parser.emitError(loc) << "unpacked struct cannot have a sign";
1386  return failure();
1387  }
1388  if (parser.parseComma())
1389  return failure();
1390  }
1391 
1392  SmallVector<StructMember> members;
1393  auto result2 =
1394  parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Braces, [&]() {
1395  if (parser.parseKeyword(&keyword))
1396  return failure();
1397  UnpackedType type;
1398  LocationAttr loc;
1399  if (parser.parseColon() || parseMooreType(parser, subset, type) ||
1400  parser.parseAttribute(loc))
1401  return failure();
1402  members.push_back(
1403  {StringAttr::get(parser.getContext(), keyword), loc, type});
1404  return success();
1405  });
1406  if (result2)
1407  return failure();
1408 
1409  LocationAttr loc;
1410  if (parser.parseComma() || parser.parseAttribute(loc) ||
1411  parser.parseGreater())
1412  return failure();
1413 
1414  return yieldImplied(
1415  [&]() {
1416  return PackedStructType::get(*kind, members, name, loc, sign);
1417  },
1418  [&]() { return UnpackedStructType::get(*kind, members, name, loc); });
1419  }
1420 
1421  return {};
1422 }
1423 
1424 /// Print a type with custom syntax.
1425 static LogicalResult customTypePrinter(Type type, DialectAsmPrinter &printer,
1426  Subset subset) {
1427  // If we are printing a type that may be both packed or unpacked, emit a
1428  // wrapping `packed<...>` or `unpacked<...>` accordingly if not done so
1429  // previously, in order to disambiguate between the two.
1430  if (type.isa<PackedDim>() || type.isa<UnpackedDim>() ||
1431  type.isa<PackedIndirectType>() || type.isa<UnpackedIndirectType>() ||
1432  type.isa<PackedStructType>() || type.isa<UnpackedStructType>()) {
1433  auto needed = type.isa<PackedType>() ? Subset::Packed : Subset::Unpacked;
1434  if (needed != subset.implied) {
1435  printer << (needed == Subset::Packed ? "packed" : "unpacked") << "<";
1436  printMooreType(type, printer, {needed, true});
1437  printer << ">";
1438  return success();
1439  }
1440  }
1441 
1442  return TypeSwitch<Type, LogicalResult>(type)
1443  // Unit types
1444  .Case<VoidType>([&](auto) {
1445  printer << "void";
1446  return success();
1447  })
1448  .Case<StringType>([&](auto) {
1449  printer << "string";
1450  return success();
1451  })
1452  .Case<ChandleType>([&](auto) {
1453  printer << "chandle";
1454  return success();
1455  })
1456  .Case<EventType>([&](auto) {
1457  printer << "event";
1458  return success();
1459  })
1460 
1461  // Integers and reals
1462  .Case<IntType>([&](auto type) {
1463  printer << type.getKeyword();
1464  auto sign = type.getSign();
1465  if (type.isSignExplicit())
1466  printer << "<" << getKeywordFromSign(sign) << ">";
1467  return success();
1468  })
1469  .Case<RealType>(
1470  [&](auto type) { return printer << type.getKeyword(), success(); })
1471 
1472  // Enums
1473  .Case<EnumType>([&](auto type) {
1474  printer << "enum<";
1475  if (type.getName())
1476  printer << type.getName() << ", ";
1477  if (type.isBaseExplicit()) {
1478  printMooreType(type.getBase(), printer, subset);
1479  printer << ", ";
1480  }
1481  printer << type.getLoc() << ">";
1482  return success();
1483  })
1484 
1485  // Type indirections
1486  .Case<PackedNamedType, UnpackedNamedType>([&](auto type) {
1487  printer << "named<" << type.getName() << ", ";
1488  printMooreType(type.getInner(), printer, subset);
1489  printer << ", " << type.getLoc() << ">";
1490  return success();
1491  })
1492  .Case<PackedRefType, UnpackedRefType>([&](auto type) {
1493  printer << "ref<";
1494  printMooreType(type.getInner(), printer, subset);
1495  printer << ", " << type.getLoc() << ">";
1496  return success();
1497  })
1498 
1499  // Packed and unpacked dimensions
1500  .Case<PackedUnsizedDim, UnpackedUnsizedDim>([&](auto type) {
1501  printer << "unsized<";
1502  printMooreType(type.getInner(), printer, subset);
1503  printer << ">";
1504  return success();
1505  })
1506  .Case<PackedRangeDim, UnpackedRangeDim>([&](auto type) {
1507  printer << "range<";
1508  printMooreType(type.getInner(), printer, subset);
1509  printer << ", " << type.getRange() << ">";
1510  return success();
1511  })
1512  .Case<UnpackedArrayDim>([&](auto type) {
1513  printer << "array<";
1514  printMooreType(type.getInner(), printer, subset);
1515  printer << ", " << type.getSize() << ">";
1516  return success();
1517  })
1518  .Case<UnpackedAssocDim>([&](auto type) {
1519  printer << "assoc<";
1520  printMooreType(type.getInner(), printer, subset);
1521  if (auto indexType = type.getIndexType()) {
1522  printer << ", ";
1523  printMooreType(indexType, printer, {Subset::Unpacked, true});
1524  }
1525  printer << ">";
1526  return success();
1527  })
1528  .Case<UnpackedQueueDim>([&](auto type) {
1529  printer << "queue<";
1530  printMooreType(type.getInner(), printer, subset);
1531  if (auto bound = type.getBound())
1532  printer << ", " << *bound;
1533  printer << ">";
1534  return success();
1535  })
1536 
1537  // Structs
1538  .Case<PackedStructType, UnpackedStructType>([&](auto type) {
1539  const auto &strukt = type.getStruct();
1540  printer << getMnemonicFromStructKind(strukt.kind) << "<";
1541  if (strukt.name)
1542  printer << strukt.name << ", ";
1543  auto packed = type.template dyn_cast<PackedStructType>();
1544  if (packed && packed.isSignExplicit())
1545  printer << packed.getSign() << ", ";
1546  printer << "{";
1547  llvm::interleaveComma(strukt.members, printer, [&](const auto &member) {
1548  printer << member.name.getValue() << ": ";
1549  printMooreType(member.type, printer, subset);
1550  printer << " " << member.loc;
1551  });
1552  printer << "}, ";
1553  printer << strukt.loc << ">";
1554  return success();
1555  })
1556 
1557  .Default([](auto) { return failure(); });
1558 }
1559 
1560 /// Parse a type registered with this dialect.
1561 static ParseResult parseMooreType(DialectAsmParser &parser, Subset subset,
1562  Type &type) {
1563  llvm::SMLoc loc = parser.getCurrentLocation();
1564  StringRef mnemonic;
1565  OptionalParseResult result = generatedTypeParser(parser, &mnemonic, type);
1566  if (result.has_value())
1567  return result.value();
1568 
1569  result = customTypeParser(parser, mnemonic, subset, loc, type);
1570  if (result.has_value())
1571  return result.value();
1572 
1573  parser.emitError(loc) << "unknown type `" << mnemonic
1574  << "` in dialect `moore`";
1575  return failure();
1576 }
1577 
1578 /// Print a type registered with this dialect.
1579 static void printMooreType(Type type, DialectAsmPrinter &printer,
1580  Subset subset) {
1581  if (succeeded(generatedTypePrinter(type, printer)))
1582  return;
1583  if (succeeded(customTypePrinter(type, printer, subset)))
1584  return;
1585  assert(false && "no printer for unknown `moore` dialect type");
1586 }
1587 
1588 /// Parse a type registered with this dialect.
1589 Type MooreDialect::parseType(DialectAsmParser &parser) const {
1590  Type type;
1591  if (parseMooreType(parser, {Subset::None, true}, type))
1592  return {};
1593  return type;
1594 }
1595 
1596 /// Print a type registered with this dialect.
1597 void MooreDialect::printType(Type type, DialectAsmPrinter &printer) const {
1598  printMooreType(type, printer, {Subset::None, true});
1599 }
assert(baseType &&"element must be base type")
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static void printMooreType(Type type, DialectAsmPrinter &printer, Subset subset)
Print a type registered with this dialect.
static LogicalResult customTypePrinter(Type type, DialectAsmPrinter &printer, Subset subset)
Print a type with custom syntax.
static SimpleBitVectorType getSimpleBitVectorFromIntType(IntType type)
Map an IntType to the corresponding SBVT. Never returns a null type.
Definition: MooreTypes.cpp:153
static ParseResult parseMooreType(DialectAsmParser &parser, Subset subset, Type &type)
Parse a type registered with this dialect.
static OptionalParseResult customTypeParser(DialectAsmParser &parser, StringRef mnemonic, Subset subset, llvm::SMLoc loc, Type &type)
Parse a type with custom syntax.
The chandle type.
Definition: MooreTypes.h:479
static ChandleType get(MLIRContext *context)
Definition: MooreTypes.cpp:313
StringAttr getName() const
Get the name of the surrounding typedef, if this enum is embedded in a typedef.
Definition: MooreTypes.cpp:987
PackedType getBase() const
Get the base type of the enumeration.
Definition: MooreTypes.cpp:983
static EnumType get(StringAttr name, Location loc, PackedType base={})
Definition: MooreTypes.cpp:978
void format(llvm::raw_ostream &os) const
Format this enum in SystemVerilog syntax.
Definition: MooreTypes.cpp:991
Location getLoc() const
Get the location in the source text where the enum was declared.
Definition: MooreTypes.cpp:989
bool isBaseExplicit() const
Returns whether the base type was explicitly specified by the user.
Definition: MooreTypes.cpp:985
The event type.
Definition: MooreTypes.h:489
static EventType get(MLIRContext *context)
Definition: MooreTypes.cpp:317
An integer vector or atom type.
Definition: MooreTypes.h:503
Sign getDefaultSign() const
Get the default sign for this type.
Definition: MooreTypes.h:567
Sign getSign() const
Get the sign of this type.
Definition: MooreTypes.cpp:487
Domain getDomain() const
Get the value domain for this type.
Definition: MooreTypes.h:569
static std::optional< Kind > getKindFromDomainAndSize(Domain domain, unsigned size)
Get the integer type that corresponds to a domain and bit size.
Definition: MooreTypes.cpp:447
Kind getKind() const
Get the concrete integer vector or atom type.
Definition: MooreTypes.cpp:485
static IntType getInt(MLIRContext *context)
Create a int type.
Definition: MooreTypes.h:551
bool isSignExplicit() const
Whether the sign of the type was specified explicitly.
Definition: MooreTypes.cpp:489
static IntType get(MLIRContext *context, Kind kind, std::optional< Sign > sign={})
Definition: MooreTypes.cpp:478
static unsigned getBitSize(Kind kind)
Get the size of one of the integer types.
Definition: MooreTypes.cpp:425
unsigned getBitSize() const
Get the size of this type.
Definition: MooreTypes.h:571
static std::optional< Kind > getKindFromKeyword(StringRef keyword)
Get the integer type that corresponds to a keyword (like bit).
Definition: MooreTypes.cpp:353
StringRef getKeyword() const
Get the keyword (like bit) for this type.
Definition: MooreTypes.h:565
void format(llvm::raw_ostream &os) const
Format this type in SystemVerilog syntax.
Definition: MooreTypes.cpp:491
@ LongInt
A longint.
Definition: MooreTypes.h:522
@ Integer
An integer.
Definition: MooreTypes.h:524
@ ShortInt
A shortint.
Definition: MooreTypes.h:518
static Domain getDomain(Kind kind)
Get the value domain for one of the integer types.
Definition: MooreTypes.cpp:408
static ConcreteTy get(InnerType inner, StringAttr name, Location loc)
A packed dimension.
Definition: MooreTypes.h:782
std::optional< Range > getRange() const
Get the dimension's range, or None if it is unsized.
Definition: MooreTypes.cpp:767
void formatDim(llvm::raw_ostream &os) const
Format just the dimension part, [...].
Definition: MooreTypes.cpp:751
const detail::DimStorage * getImpl() const
Definition: MooreTypes.cpp:777
PackedType resolved() const
Resolve one level of name or type reference indirection.
Definition: MooreTypes.cpp:759
void format(llvm::raw_ostream &os) const
Format this type in SystemVerilog syntax.
Definition: MooreTypes.cpp:733
std::optional< unsigned > getSize() const
Get the dimension's size, or None if it is unsized.
Definition: MooreTypes.cpp:773
PackedType fullyResolved() const
Resolve all name or type reference indirections.
Definition: MooreTypes.cpp:763
A packed type indirection. See IndirectTypeBase for details.
Definition: MooreTypes.h:726
A packed named type. See NamedTypeBase for details.
Definition: MooreTypes.h:749
A packed range dimension, like [a:b].
Definition: MooreTypes.h:830
Range getRange() const
Get the range of this dimension.
Definition: MooreTypes.cpp:793
static PackedRangeDim get(PackedType inner, Range range)
Definition: MooreTypes.cpp:787
A packed named type. See NamedTypeBase for details.
Definition: MooreTypes.h:762
const Struct & getStruct() const
Get the struct definition.
static PackedStructType get(StructKind kind, ArrayRef< StructMember > members, StringAttr name, Location loc, std::optional< Sign > sign={})
Sign getSign() const
Get the sign of this struct.
bool isSignExplicit() const
Returns whether the sign was explicitly mentioned by the user.
A packed SystemVerilog type.
Definition: MooreTypes.h:414
Sign getSign() const
Get the sign for this type.
Definition: MooreTypes.cpp:266
PackedType resolved() const
Resolve one level of name or type reference indirection.
Definition: MooreTypes.cpp:241
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Definition: MooreTypes.cpp:276
Domain getDomain() const
Get the value domain of this type.
Definition: MooreTypes.cpp:255
void format(llvm::raw_ostream &os) const
Format this type in SystemVerilog syntax into an output stream.
Definition: MooreTypes.cpp:293
PackedType fullyResolved() const
Resolve all name or type reference indirections.
Definition: MooreTypes.cpp:248
A packed unsized dimension, like [].
Definition: MooreTypes.h:818
static PackedUnsizedDim get(PackedType inner)
Definition: MooreTypes.cpp:781
StringRef getKeyword() const
Get the keyword (like bit) for this type.
Definition: MooreTypes.h:611
static std::optional< Kind > getKindFromKeyword(StringRef keyword)
Get the integer type that corresponds to a keyword (like bit).
Definition: MooreTypes.cpp:524
static RealType get(MLIRContext *context, Kind kind)
Definition: MooreTypes.cpp:556
@ ShortReal
A shortreal.
Definition: MooreTypes.h:591
@ RealTime
A realtime.
Definition: MooreTypes.h:595
unsigned getBitSize() const
Get the size of this type.
Definition: MooreTypes.h:613
Kind getKind() const
Get the concrete integer vector or atom type.
Definition: MooreTypes.cpp:560
static PackedRefType get(InnerType inner, Location loc)
The string type.
Definition: MooreTypes.h:469
static StringType get(MLIRContext *context)
Definition: MooreTypes.cpp:311
An unpacked array dimension, like [a].
Definition: MooreTypes.h:915
static UnpackedArrayDim get(UnpackedType inner, unsigned size)
Definition: MooreTypes.cpp:904
unsigned getSize() const
Get the size of the array, i.e. the a in [a].
Definition: MooreTypes.cpp:910
An unpacked associative dimension, like [T] or [*].
Definition: MooreTypes.h:967
static UnpackedAssocDim get(UnpackedType inner, UnpackedType indexType={})
Definition: MooreTypes.cpp:920
UnpackedType getIndexType() const
Get the index type of the associative dimension.
Definition: MooreTypes.cpp:927
An unpacked dimension.
Definition: MooreTypes.h:863
UnpackedType resolved() const
Resolve one level of name or type reference indirection.
Definition: MooreTypes.cpp:888
void format(llvm::raw_ostream &os, llvm::function_ref< void(llvm::raw_ostream &)> around={}) const
Format this type in SystemVerilog syntax.
Definition: MooreTypes.cpp:839
const detail::DimStorage * getImpl() const
Definition: MooreTypes.cpp:894
UnpackedType fullyResolved() const
Resolve all name or type reference indirections.
Definition: MooreTypes.cpp:890
void formatDim(llvm::raw_ostream &os) const
Format just the dimension part, [...].
Definition: MooreTypes.cpp:864
UnpackedType getInner() const
Get the element type of the dimension. This is the x in x[a:b].
Definition: MooreTypes.cpp:837
An unpacked type indirection. See IndirectTypeBase for details.
Definition: MooreTypes.h:737
An unpacked named type. See NamedTypeBase for details.
Definition: MooreTypes.h:756
An unpacked queue dimension with optional bound, like [$] or [$:a].
Definition: MooreTypes.h:983
static UnpackedQueueDim get(UnpackedType inner, std::optional< unsigned > bound={})
Definition: MooreTypes.cpp:931
std::optional< unsigned > getBound() const
Get the bound of the queue, i.e.
Definition: MooreTypes.cpp:938
An unpacked range dimension, like [a:b].
Definition: MooreTypes.h:930
Range getRange() const
Get the range of this dimension.
Definition: MooreTypes.cpp:918
static UnpackedRangeDim get(UnpackedType inner, Range range)
Definition: MooreTypes.cpp:912
An unpacked named type. See NamedTypeBase for details.
Definition: MooreTypes.h:769
const Struct & getStruct() const
Get the struct definition.
static UnpackedStructType get(StructKind kind, ArrayRef< StructMember > members, StringAttr name, Location loc)
An unpacked SystemVerilog type.
Definition: MooreTypes.h:282
UnpackedType resolved() const
Resolve one level of name or type reference indirection.
Definition: MooreTypes.cpp:99
SimpleBitVectorType getSimpleBitVectorOrNull() const
Get this type as a simple bit vector, if it is one.
Definition: MooreTypes.cpp:160
SimpleBitVectorType castToSimpleBitVectorOrNull() const
Cast this type to a simple bit vector.
Definition: MooreTypes.cpp:190
UnpackedType fullyResolved() const
Resolve all name or type reference indirections.
Definition: MooreTypes.cpp:106
std::optional< unsigned > getBitSize() const
Get the size of this type in bits.
Definition: MooreTypes.cpp:131
Domain getDomain() const
Get the value domain of this type.
Definition: MooreTypes.cpp:113
Sign getSign() const
Get the sign for this type.
Definition: MooreTypes.cpp:123
void format(llvm::raw_ostream &os, llvm::function_ref< void(llvm::raw_ostream &os)> around={}) const
Format this type in SystemVerilog syntax into an output stream.
Definition: MooreTypes.cpp:210
An unpacked unsized dimension, like [].
Definition: MooreTypes.h:903
static UnpackedUnsizedDim get(UnpackedType inner)
Definition: MooreTypes.cpp:898
The void type.
Definition: MooreTypes.h:459
static VoidType get(MLIRContext *context)
Definition: MooreTypes.cpp:309
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:53
mlir::Type innerType(mlir::Type type)
Definition: ESITypes.cpp:184
UnpackedType getIndirectTypeInner(const TypeStorage *impl)
Definition: MooreTypes.cpp:593
StringAttr getIndirectTypeName(const TypeStorage *impl)
Definition: MooreTypes.cpp:601
Location getIndirectTypeLoc(const TypeStorage *impl)
Definition: MooreTypes.cpp:597
Domain
The number of values each bit of a type can assume.
Definition: MooreTypes.h:27
@ FourValued
Four-valued types such as logic or integer.
@ TwoValued
Two-valued types such as bit or int.
Sign
Whether a type is signed or unsigned.
Definition: MooreTypes.h:35
@ Signed
A signed type.
@ Unsigned
An unsigned type.
StringRef getKeywordFromSign(const Sign &sign)
Map a Sign to the corresponding keyword.
Definition: MooreTypes.cpp:51
StringRef getMnemonicFromStructKind(StructKind kind)
Map a StructKind to the corresponding mnemonic.
StructKind
Whether a struct is a struct, union, or union tagged.
Definition: MooreTypes.h:1033
@ TaggedUnion
A union tagged.
std::optional< StructKind > getStructKindFromMnemonic(StringRef mnemonic)
Map a mnemonic to the corresponding StructKind.
std::optional< Sign > getSignFromKeyword(StringRef keyword)
Map the keywords unsigned and signed to the corresponding Sign.
Definition: MooreTypes.cpp:61
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
Definition: DebugAnalysis.h:21
enum Subset::@7 implied
bool allowUnpacked
The [a:b] part in a vector/array type such as logic [a:b].
Definition: MooreTypes.h:62
A simple bit vector type.
Definition: MooreTypes.h:134
unsigned size
The size of the vector.
Definition: MooreTypes.h:184
bool explicitSize
Whether the single-bit vector had an explicit range in the source text.
Definition: MooreTypes.h:201
bool usedAtom
Whether the type used an integer atom like int in the source text.
Definition: MooreTypes.h:196
bool explicitSign
Whether the sign was explicit in the source text.
Definition: MooreTypes.h:198
PackedType getType(MLIRContext *context) const
Convert this SBVT to an actual type.
Definition: MooreTypes.cpp:72
Range getRange() const
Get the range of the type.
Definition: MooreTypes.h:158
Domain domain
The domain, which dictates whether this is a bit or logic vector.
Definition: MooreTypes.h:186
A member of a struct.
Definition: MooreTypes.h:1055
UnpackedType type
The type of this member.
Definition: MooreTypes.h:1061
std::optional< unsigned > bitSize
The size of this struct in bits.
Definition: MooreTypes.h:1090
StructKind kind
Whether this is a struct, union, or union tagged.
Definition: MooreTypes.h:1081
StringAttr name
The name of the surrounding typedef, if this struct is embedded in a typedef.
Definition: MooreTypes.h:1093
void format(llvm::raw_ostream &os, bool packed=false, std::optional< Sign > signing={}) const
Format this struct in SystemVerilog syntax.
Domain domain
The value domain of this struct.
Definition: MooreTypes.h:1086
SmallVector< StructMember, 4 > members
The list of members.
Definition: MooreTypes.h:1083
Struct(StructKind kind, ArrayRef< StructMember > members, StringAttr name, Location loc)
Create a new struct.
static AssocDimStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:825
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:822
static DimStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:648
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:647
void finalize(ConcreteDim dim, Args... args) const
Each dimension type calls this function from its get method.
Definition: MooreTypes.cpp:682
LogicalResult mutate(TypeStorageAllocator &allocator, UnpackedType newResolved, UnpackedType newFullyResolved)
Definition: MooreTypes.cpp:654
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:959
std::tuple< StringAttr, Location, PackedType, char > KeyTy
Definition: MooreTypes.cpp:954
static EnumTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:963
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:578
IndirectTypeStorage(UnpackedType inner, StringAttr name, LocationAttr loc)
Definition: MooreTypes.cpp:576
std::tuple< UnpackedType, StringAttr, LocationAttr > KeyTy
Definition: MooreTypes.cpp:571
static IndirectTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:582
static IntTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:340
static KeyTy pack(Kind kind, Sign sign, bool explicitSign)
Definition: MooreTypes.cpp:333
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:337
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:714
static RangeDimStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:717
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:510
static RealTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:513
bool operator==(const KeyTy &key) const
Definition: MooreTypes.cpp:807
static SizedDimStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:810
static StructTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
std::tuple< unsigned, ArrayRef< StructMember >, StringAttr, Location > KeyTy
bool operator==(const KeyTy &key) const
static unsigned pack(StructKind kind, Sign sign, bool explicitSign)
static UnsizedDimStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
Definition: MooreTypes.cpp:704