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