17#include "mlir/IR/DialectImplementation.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/ADT/TypeSwitch.h"
25using mlir::OptionalParseResult;
26using mlir::TypeStorageAllocator;
33#define GET_TYPEDEF_CLASSES
34#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
49 auto printWidthQualifier = [&](std::optional<int32_t> width) {
51 os <<
'<' << *width <<
'>';
53 bool anyFailed =
false;
54 TypeSwitch<Type>(type)
55 .Case<ClockType>([&](
auto) { os <<
"clock"; })
56 .Case<ResetType>([&](
auto) { os <<
"reset"; })
57 .Case<AsyncResetType>([&](
auto) { os <<
"asyncreset"; })
58 .Case<SIntType>([&](
auto sIntType) {
60 printWidthQualifier(sIntType.getWidth());
62 .Case<UIntType>([&](
auto uIntType) {
64 printWidthQualifier(uIntType.getWidth());
66 .Case<AnalogType>([&](
auto analogType) {
68 printWidthQualifier(analogType.getWidth());
70 .Case<BundleType, OpenBundleType>([&](
auto bundleType) {
74 llvm::interleaveComma(bundleType, os, [&](
auto element) {
75 StringRef fieldName = element.name.getValue();
76 bool isLiteralIdentifier =
77 !fieldName.empty() && llvm::isDigit(fieldName.front());
78 if (isLiteralIdentifier)
80 os << element.name.getValue();
81 if (isLiteralIdentifier)
90 .Case<FEnumType>([&](
auto fenumType) {
92 std::optional<APInt> previous;
93 llvm::interleaveComma(
94 fenumType, os, [&](FEnumType::EnumElement element) {
96 os << element.name.getValue();
99 auto value = element.value.getValue();
104 if (value != previous) {
106 os.printAttributeWithoutType(element.value);
108 }
else if (!element.value.getValue().isZero()) {
110 os.printAttributeWithoutType(element.value);
115 bool skipType =
false;
116 if (
auto type = dyn_cast<UIntType>(element.type))
117 if (type.getWidth() == 0)
126 .Case<FVectorType, OpenVectorType>([&](
auto vectorType) {
131 os <<
", " << vectorType.getNumElements() <<
'>';
133 .Case<RefType>([&](RefType refType) {
134 if (refType.getForceable())
138 if (
auto layer = refType.getLayer())
142 .Case<LHSType>([&](LHSType lhstype) {
147 .Case<StringType>([&](
auto stringType) { os <<
"string"; })
148 .Case<FIntegerType>([&](
auto integerType) { os <<
"integer"; })
149 .Case<BoolType>([&](
auto boolType) { os <<
"bool"; })
150 .Case<DoubleType>([&](
auto doubleType) { os <<
"double"; })
151 .Case<ListType>([&](
auto listType) {
156 .Case<RegistryType>([&](
auto registryType) {
161 .Case<PathType>([&](
auto pathType) { os <<
"path"; })
162 .Case<BaseTypeAliasType>([&](BaseTypeAliasType alias) {
163 os <<
"alias<" << alias.getName().getValue() <<
", ";
167 .Case<ClassType>([&](ClassType type) {
169 type.printInterface(os);
172 .Case<AnyRefType>([&](AnyRefType type) { os <<
"anyref"; })
173 .Case<FStringType>([&](
auto) { os <<
"fstring"; })
174 .Case<DomainType>([&](DomainType type) {
176 os.printSymbolName(type.getName().getValue());
178 llvm::interleaveComma(type.getFields(), os, [&](Attribute attr) {
179 auto field = cast<DomainFieldAttr>(attr);
180 os << field.getName().getValue() <<
": ";
181 os.printType(field.getType());
186 .Default([&](
auto) { anyFailed =
true; });
198 assert(
false &&
"type to print unknown to FIRRTL dialect");
233 const char constPrefix[] =
"const.";
234 if (name.starts_with(constPrefix)) {
236 name = name.drop_front(std::size(constPrefix) - 1);
239 auto *
context = parser.getContext();
244 if (name ==
"asyncreset")
247 if (name ==
"sint" || name ==
"uint" || name ==
"analog") {
250 if (!parser.parseOptionalLess()) {
251 if (parser.parseInteger(width) || parser.parseGreater())
255 return parser.emitError(parser.getNameLoc(),
"unknown width"),
261 else if (name ==
"uint")
270 if (name ==
"bundle") {
271 SmallVector<BundleType::BundleElement, 4> elements;
273 auto parseBundleElement = [&]() -> ParseResult {
278 if (failed(parser.parseKeywordOrString(&nameStr)))
282 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
286 elements.push_back({StringAttr::get(
context, name), isFlip, type});
290 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
294 result = parser.getChecked<BundleType>(
context, elements,
isConst);
297 if (name ==
"openbundle") {
298 SmallVector<OpenBundleType::BundleElement, 4> elements;
300 auto parseBundleElement = [&]() -> ParseResult {
305 if (failed(parser.parseKeywordOrString(&nameStr)))
309 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
313 elements.push_back({StringAttr::get(
context, name), isFlip, type});
317 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
321 result = parser.getChecked<OpenBundleType>(
context, elements,
isConst);
325 if (name ==
"enum") {
326 SmallVector<StringAttr> names;
327 SmallVector<APInt> values;
328 SmallVector<FIRRTLBaseType> types;
329 auto parseEnumElement = [&]() -> ParseResult {
332 if (failed(parser.parseKeywordOrString(&nameStr)))
334 names.push_back(StringAttr::get(
context, nameStr));
340 if (succeeded(parser.parseOptionalEqual())) {
341 if (parser.parseInteger(value))
343 }
else if (values.empty()) {
349 auto &prev = values.back();
350 if (prev.isMaxValue())
351 value = prev.zext(prev.getBitWidth() + 1);
356 values.push_back(std::move(value));
360 if (succeeded(parser.parseOptionalColon())) {
364 type = UIntType::get(parser.getContext(), 0);
366 types.push_back(type);
371 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
376 unsigned bitwidth = 0;
377 for (
auto &value : values)
378 bitwidth = std::max(bitwidth, value.getActiveBits());
379 auto tagType = IntegerType::get(
context, bitwidth, IntegerType::Unsigned);
381 SmallVector<FEnumType::EnumElement, 4> elements;
382 for (
auto [name, value, type] : llvm::zip(names, values, types)) {
383 auto tagValue = value.zextOrTrunc(bitwidth);
384 elements.push_back({name, IntegerAttr::get(tagType, tagValue), type});
387 if (failed(FEnumType::verify(
388 [&]() {
return parser.emitError(parser.getNameLoc()); }, elements,
392 result = parser.getChecked<FEnumType>(
context, elements,
isConst);
396 if (name ==
"vector") {
401 parser.parseComma() || parser.parseInteger(width) ||
402 parser.parseGreater())
407 if (name ==
"openvector") {
412 parser.parseComma() || parser.parseInteger(width) ||
413 parser.parseGreater())
422 if (name ==
"ref" || name ==
"probe") {
429 if (parser.parseOptionalComma().succeeded())
430 if (parser.parseOptionalAttribute(layer).value())
431 return parser.emitError(parser.getNameLoc(),
432 "expected symbol reference");
433 if (parser.parseGreater())
436 if (failed(RefType::verify(
437 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
441 return result = RefType::get(type,
false, layer),
success();
446 parser.parseGreater())
448 if (!isa<FIRRTLBaseType>(type))
449 return parser.emitError(parser.getNameLoc(),
"expected base type");
450 result = parser.getChecked<LHSType>(
context, cast<FIRRTLBaseType>(type));
453 if (name ==
"rwprobe") {
458 if (parser.parseOptionalComma().succeeded())
459 if (parser.parseOptionalAttribute(layer).value())
460 return parser.emitError(parser.getNameLoc(),
461 "expected symbol reference");
462 if (parser.parseGreater())
465 if (failed(RefType::verify(
466 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
true,
470 return result = RefType::get(type,
true, layer),
success();
472 if (name ==
"class") {
474 return parser.emitError(parser.getNameLoc(),
"classes cannot be const");
476 if (parser.parseLess() || ClassType::parseInterface(parser, classType) ||
477 parser.parseGreater())
482 if (name ==
"anyref") {
484 return parser.emitError(parser.getNameLoc(),
"any refs cannot be const");
486 result = AnyRefType::get(parser.getContext());
489 if (name ==
"string") {
491 parser.emitError(parser.getNameLoc(),
"strings cannot be const");
494 result = StringType::get(parser.getContext());
497 if (name ==
"integer") {
499 parser.emitError(parser.getNameLoc(),
"bigints cannot be const");
502 result = FIntegerType::get(parser.getContext());
505 if (name ==
"bool") {
507 parser.emitError(parser.getNameLoc(),
"bools cannot be const");
510 result = BoolType::get(parser.getContext());
513 if (name ==
"double") {
515 parser.emitError(parser.getNameLoc(),
"doubles cannot be const");
518 result = DoubleType::get(parser.getContext());
521 if (name ==
"list") {
523 parser.emitError(parser.getNameLoc(),
"lists cannot be const");
528 parser.parseGreater())
535 if (name ==
"registry") {
537 parser.emitError(parser.getNameLoc(),
"registries cannot be const");
542 parser.parseGreater())
549 if (name ==
"path") {
551 parser.emitError(parser.getNameLoc(),
"path cannot be const");
554 result = PathType::get(parser.getContext());
557 if (name ==
"alias") {
560 if (parser.parseLess() || parser.parseKeyword(&name) ||
562 parser.parseGreater())
566 BaseTypeAliasType::get(StringAttr::get(
context, name), type),
569 if (name ==
"fstring") {
572 if (name ==
"domain") {
575 DomainType domainType;
576 if (parser.parseLess() || DomainType::parseInterface(parser, domainType) ||
577 parser.parseGreater())
592static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
595 if (parseResult.has_value())
596 return parseResult.value();
599 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL dialect type: \"")
611 if (failed(
parseType(type, name, parser)))
616 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL type: \"")
630 parser.emitError(parser.getNameLoc(),
"expected base type, found ") << type;
643 parser.emitError(parser.getNameLoc(),
"expected property type, found ")
656 if (parser.parseKeyword(&name))
666 if (parser.parseKeyword(&name))
676 if (parser.parseKeyword(&name))
687void FIRRTLDialect::printType(Type type, DialectAsmPrinter &os)
const {
692Type FIRRTLDialect::parseType(DialectAsmParser &parser)
const {
695 if (parser.parseKeyword(&name) ||
::parseType(result, name, parser))
739 return TypeSwitch<FIRRTLType, bool>(*
this)
740 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
741 AnalogType>([](Type) {
return true; })
742 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType>(
743 [](Type) {
return false; })
744 .Case<BaseTypeAliasType>([](BaseTypeAliasType alias) {
745 return alias.getAnonymousType().isGround();
748 .Case<PropertyType, RefType>([](Type) {
return false; })
750 llvm_unreachable(
"unknown FIRRTL type");
756 return TypeSwitch<FIRRTLType, bool>(*
this)
757 .Case<FIRRTLBaseType, OpenBundleType, OpenVectorType>(
758 [](
auto type) {
return type.isConst(); })
765 return TypeSwitch<FIRRTLType, RecursiveTypeProperties>(*
this)
766 .Case<ClockType, ResetType, AsyncResetType>([](
FIRRTLBaseType type) {
775 .Case<SIntType, UIntType>([](
auto type) {
777 true,
false,
false, type.isConst(),
false, !type.hasWidth(),
false};
779 .Case<AnalogType>([](
auto type) {
780 return RecursiveTypeProperties{
781 true,
false,
true, type.isConst(),
false, !type.hasWidth(),
false};
783 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType,
784 RefType, BaseTypeAliasType>(
785 [](
auto type) {
return type.getRecursiveTypeProperties(); })
786 .Case<PropertyType>([](
auto type) {
787 return RecursiveTypeProperties{
true,
false,
false,
false,
788 false,
false,
false};
791 [](
auto type) {
return type.getType().getRecursiveTypeProperties(); })
792 .Case<FStringType>([](
auto type) {
793 return RecursiveTypeProperties{
true,
false,
false,
false,
794 false,
false,
false};
796 .Case<DomainType>([](
auto type) {
797 return RecursiveTypeProperties{
true,
false,
false,
false,
798 false,
false,
false};
801 llvm_unreachable(
"unknown FIRRTL type");
802 return RecursiveTypeProperties{};
808 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
809 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
810 AnalogType>([&](Type) {
return *
this; })
811 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
812 [](
auto type) {
return type.getAnonymousType(); })
814 llvm_unreachable(
"unknown FIRRTL type");
821 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
822 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
823 AnalogType, FEnumType>([&](Type) {
return *
this; })
824 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
825 [](
auto type) {
return type.getPassiveType(); })
827 llvm_unreachable(
"unknown FIRRTL type");
834 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
835 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
836 UIntType, BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
837 [&](
auto type) {
return type.getConstType(
isConst); })
839 llvm_unreachable(
"unknown FIRRTL type");
846 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
847 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
848 UIntType>([&](
auto type) {
return type.getConstType(
false); })
849 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
850 [&](
auto type) {
return type.getAllConstDroppedType(); })
852 llvm_unreachable(
"unknown FIRRTL type");
860 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
861 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
862 AnalogType, FEnumType>([&](Type) {
863 return UIntType::get(this->getContext(), 1, this->
isConst());
865 .Case<BundleType>([&](BundleType bundleType) {
866 SmallVector<BundleType::BundleElement, 4> newElements;
867 newElements.reserve(bundleType.getElements().size());
868 for (
auto elt : bundleType)
869 newElements.push_back(
870 {elt.name,
false , elt.type.getMaskType()});
871 return BundleType::get(this->getContext(), newElements,
872 bundleType.isConst());
874 .Case<FVectorType>([](FVectorType vectorType) {
875 return FVectorType::get(vectorType.getElementType().getMaskType(),
876 vectorType.getNumElements(),
877 vectorType.isConst());
879 .Case<BaseTypeAliasType>([](BaseTypeAliasType base) {
880 return base.getModifiedType(base.getInnerType().getMaskType());
883 llvm_unreachable(
"unknown FIRRTL type");
891 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
892 .Case<ClockType, ResetType, AsyncResetType>([](
auto a) {
return a; })
893 .Case<UIntType, SIntType, AnalogType>(
894 [&](
auto a) {
return a.get(this->getContext(), -1, a.isConst()); })
895 .Case<BundleType>([&](
auto a) {
896 SmallVector<BundleType::BundleElement, 4> newElements;
897 newElements.reserve(a.getElements().size());
899 newElements.push_back(
900 {elt.name, elt.isFlip, elt.type.getWidthlessType()});
901 return BundleType::get(this->getContext(), newElements, a.isConst());
903 .Case<FVectorType>([](
auto a) {
904 return FVectorType::get(a.getElementType().getWidthlessType(),
905 a.getNumElements(), a.isConst());
907 .Case<FEnumType>([&](FEnumType a) {
908 SmallVector<FEnumType::EnumElement, 4> newElements;
909 newElements.reserve(a.getNumElements());
911 newElements.push_back(
912 {elt.name, elt.value, elt.type.getWidthlessType()});
913 return FEnumType::get(this->getContext(), newElements, a.isConst());
915 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
916 return type.getModifiedType(type.getInnerType().getWidthlessType());
919 llvm_unreachable(
"unknown FIRRTL type");
929 return TypeSwitch<FIRRTLBaseType, int32_t>(*
this)
930 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
931 .Case<SIntType, UIntType>(
934 [](AnalogType analogType) {
return analogType.getWidthOrSentinel(); })
935 .Case<FEnumType>([&](FEnumType fenum) {
return fenum.getBitWidth(); })
936 .Case<BundleType, FVectorType>([](Type) {
return -2; })
937 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
939 return type.getAnonymousType().getBitWidthOrSentinel();
942 llvm_unreachable(
"unknown FIRRTL type");
951 return TypeSwitch<FIRRTLType, bool>(*
this)
952 .Case<ResetType, AsyncResetType>([](Type) {
return true; })
954 [](UIntType a) {
return !a.hasWidth() || a.getWidth() == 1; })
955 .Case<BaseTypeAliasType>(
956 [](
auto type) {
return type.getInnerType().isResetType(); })
957 .Default([](Type) {
return false; });
961 return TypeSwitch<Type, bool>(type)
963 [](
auto base) {
return base.isConst(); })
968 return TypeSwitch<Type, bool>(type)
970 [](
auto base) {
return base.containsConst(); })
977 .
Case<BundleType>([&](
auto bundle) {
978 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
979 auto elt = bundle.getElement(i);
983 return bundle.getNumElements() == 0;
985 .Case<FVectorType>([&](
auto vector) {
986 if (vector.getNumElements() == 0)
990 .Case<FIRRTLBaseType>([](
auto groundType) {
993 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
994 .Default([](
auto) {
return false; });
1004 BundleType::BundleElement srcElement,
1005 bool destOuterTypeIsConst,
1006 bool srcOuterTypeIsConst,
1007 bool requiresSameWidth) {
1008 if (destElement.name != srcElement.name)
1010 if (destElement.isFlip != srcElement.isFlip)
1013 if (destElement.isFlip) {
1014 std::swap(destElement, srcElement);
1015 std::swap(destOuterTypeIsConst, srcOuterTypeIsConst);
1019 destOuterTypeIsConst, srcOuterTypeIsConst,
1028 bool destOuterTypeIsConst,
1029 bool srcOuterTypeIsConst,
1030 bool requireSameWidths) {
1035 if (!destType || !srcType)
1036 return destFType == srcFType;
1038 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
1039 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
1044 if (destVectorType && srcVectorType)
1045 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1047 srcVectorType.getElementType(), destIsConst,
1048 srcIsConst, requireSameWidths);
1054 if (destBundleType && srcBundleType) {
1055 auto destElements = destBundleType.getElements();
1056 auto srcElements = srcBundleType.getElements();
1057 size_t numDestElements = destElements.size();
1058 if (numDestElements != srcElements.size())
1061 for (
size_t i = 0; i < numDestElements; ++i) {
1062 auto destElement = destElements[i];
1063 auto srcElement = srcElements[i];
1065 srcIsConst, requireSameWidths))
1076 if (dstEnumType && srcEnumType) {
1077 if (dstEnumType.getNumElements() != srcEnumType.getNumElements())
1080 for (
const auto &[dst, src] : llvm::zip(dstEnumType, srcEnumType)) {
1082 if (dst.name != src.name)
1094 if (destIsConst && !srcIsConst)
1099 return srcType.isResetType();
1103 return destType.isResetType();
1107 if (!requireSameWidths || destType.getBitWidthOrSentinel() == -1)
1108 srcType = srcType.getWidthlessType();
1109 if (!requireSameWidths || srcType.getBitWidthOrSentinel() == -1)
1110 destType = destType.getWidthlessType();
1113 return destType.getConstType(
false) == srcType.getConstType(
false);
1118 bool srcOuterTypeIsConst) {
1120 if (destFType == srcFType)
1127 if (!destType || !srcType)
1131 if (!destType.isPassive() || !srcType.isPassive())
1134 bool srcIsConst = srcType.isConst() || srcOuterTypeIsConst;
1137 if (destType.isConst() && !srcIsConst)
1144 if (destVectorType && srcVectorType)
1145 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1147 srcVectorType.getElementType(), srcIsConst);
1148 if (destVectorType != srcVectorType)
1155 if (destBundleType && srcBundleType) {
1156 auto destElements = destBundleType.getElements();
1157 auto srcElements = srcBundleType.getElements();
1158 size_t numDestElements = destElements.size();
1159 if (numDestElements != srcElements.size())
1162 return llvm::all_of_zip(
1163 destElements, srcElements,
1164 [&](
const auto &destElement,
const auto &srcElement) {
1165 return destElement.name == srcElement.name &&
1170 if (destBundleType != srcBundleType)
1175 return destType == srcType.getConstType(destType.isConst());
1181 if (!dstRefType || !srcRefType)
1183 if (dstRefType == srcRefType)
1185 if (dstRefType.getForceable() && !srcRefType.getForceable())
1197 bool srcOuterTypeIsConst) ->
bool {
1203 assert(dest.isPassive() && src.isPassive());
1205 bool srcIsConst = src.isConst() || srcOuterTypeIsConst;
1208 if (dest.isConst() && !srcIsConst)
1216 return srcVectorType &&
1217 destVectorType.getNumElements() ==
1218 srcVectorType.getNumElements() &&
1219 f(f, destVectorType.getElementType(),
1220 srcVectorType.getElementType(), srcIsConst);
1228 auto destElements = destBundleType.getElements();
1229 auto srcElements = srcBundleType.getElements();
1231 return destElements.size() == srcElements.size() &&
1233 destElements, srcElements,
1234 [&](
const auto &destElement,
const auto &srcElement) {
1235 return destElement.name == srcElement.name &&
1236 f(f, destElement.type, srcElement.type, srcIsConst);
1244 auto destElements = destEnumType.getElements();
1245 auto srcElements = srcEnumType.getElements();
1247 return destElements.size() == srcElements.size() &&
1249 destElements, srcElements,
1250 [&](
const auto &destElement,
const auto &srcElement) {
1251 return destElement.name == srcElement.name &&
1252 f(f, destElement.type, srcElement.type, srcIsConst);
1258 return src.isResetType();
1262 src = src.getConstType(dest.isConst());
1265 if (dest.getBitWidthOrSentinel() == -1)
1266 src = src.getWidthlessType();
1271 return recurse(recurse, dstRefType.getType(), srcRefType.getType(),
false);
1278 return TypeSwitch<FIRRTLBaseType, bool>(dstType)
1279 .Case<BundleType>([&](
auto dstBundle) {
1281 for (
size_t i = 0, n = dstBundle.getNumElements(); i < n; ++i) {
1282 auto srcElem = srcBundle.getElement(i);
1283 auto dstElem = dstBundle.getElement(i);
1284 if (dstElem.isFlip) {
1294 .Case<FVectorType>([&](
auto vector) {
1298 .Default([&](
auto dstGround) {
1301 return destWidth <= -1 || srcWidth <= -1 || destWidth >= srcWidth;
1319 srcRefType.getType());
1331 return llvm::TypeSwitch<Type, bool>(type)
1333 return !type.containsReference() &&
1334 (!type.isPassive() || type.containsAnalog());
1342 if (isa<FIRRTLBaseType>(type))
1345 if (
auto bundle = dyn_cast<OpenBundleType>(type))
1346 return llvm::any_of(bundle,
1348 if (
auto vector = dyn_cast<OpenVectorType>(type))
1361 int32_t widthOrSentinel,
bool isConst) {
1369 return sintType.getWidthOrSentinel();
1371 return uintType.getWidthOrSentinel();
1382 using KeyTy = std::tuple<int32_t, char>;
1408SIntType SIntType::get(MLIRContext *
context) {
return get(
context, -1,
false); }
1410SIntType SIntType::get(MLIRContext *
context, std::optional<int32_t> width,
1415LogicalResult SIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1416 int32_t widthOrSentinel,
bool isConst) {
1417 if (widthOrSentinel < -1)
1418 return emitError() <<
"invalid width";
1422int32_t SIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1424SIntType SIntType::getConstType(
bool isConst)
const {
1427 return get(getContext(), getWidthOrSentinel(),
isConst);
1441LogicalResult UIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1442 int32_t widthOrSentinel,
bool isConst) {
1443 if (widthOrSentinel < -1)
1444 return emitError() <<
"invalid width";
1448int32_t UIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1450UIntType UIntType::getConstType(
bool isConst)
const {
1453 return get(getContext(), getWidthOrSentinel(),
isConst);
1462 using KeyTy = std::tuple<ArrayRef<BundleType::BundleElement>,
char>;
1467 props{true, false, false,
isConst, false, false, false} {
1468 uint64_t fieldID = 0;
1471 auto type = element.type;
1472 auto eltInfo = type.getRecursiveTypeProperties();
1473 props.isPassive &= eltInfo.isPassive & !element.isFlip;
1474 props.containsAnalog |= eltInfo.containsAnalog;
1475 props.containsReference |= eltInfo.containsReference;
1476 props.containsConst |= eltInfo.containsConst;
1477 props.containsTypeAlias |= eltInfo.containsTypeAlias;
1478 props.hasUninferredWidth |= eltInfo.hasUninferredWidth;
1479 props.hasUninferredReset |= eltInfo.hasUninferredReset;
1499 std::get<0>(key),
static_cast<bool>(std::get<1>(key)));
1513BundleType BundleType::get(MLIRContext *
context,
1514 ArrayRef<BundleElement> elements,
bool isConst) {
1518auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1519 return getImpl()->elements;
1524 return getImpl()->props;
1529 auto *
impl = getImpl();
1532 if (
impl->passiveType)
1533 return impl->passiveType;
1536 if (
impl->props.isPassive) {
1537 impl->passiveType = *
this;
1542 SmallVector<BundleType::BundleElement, 16> newElements;
1543 newElements.reserve(
impl->elements.size());
1544 for (
auto &elt :
impl->elements) {
1545 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1548 auto passiveType = BundleType::get(getContext(), newElements,
isConst());
1549 impl->passiveType = passiveType;
1553BundleType BundleType::getConstType(
bool isConst)
const {
1556 return get(getContext(), getElements(),
isConst);
1559BundleType BundleType::getAllConstDroppedType() {
1563 SmallVector<BundleElement> constDroppedElements(
1564 llvm::map_range(getElements(), [](BundleElement element) {
1565 element.type = element.type.getAllConstDroppedType();
1568 return get(getContext(), constDroppedElements,
false);
1571std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1572 for (
const auto &it : llvm::enumerate(getElements())) {
1573 auto element = it.value();
1574 if (element.name == name) {
1575 return unsigned(it.index());
1578 return std::nullopt;
1581std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1582 for (
const auto &it : llvm::enumerate(getElements())) {
1583 auto element = it.value();
1584 if (element.name.getValue() == name) {
1585 return unsigned(it.index());
1588 return std::nullopt;
1591StringAttr BundleType::getElementNameAttr(
size_t index) {
1592 assert(index < getNumElements() &&
1593 "index must be less than number of fields in bundle");
1594 return getElements()[index].name;
1597StringRef BundleType::getElementName(
size_t index) {
1598 return getElementNameAttr(index).getValue();
1601std::optional<BundleType::BundleElement>
1602BundleType::getElement(StringAttr name) {
1603 if (
auto maybeIndex = getElementIndex(name))
1604 return getElements()[*maybeIndex];
1605 return std::nullopt;
1608std::optional<BundleType::BundleElement>
1609BundleType::getElement(StringRef name) {
1610 if (
auto maybeIndex = getElementIndex(name))
1611 return getElements()[*maybeIndex];
1612 return std::nullopt;
1616BundleType::BundleElement BundleType::getElement(
size_t index) {
1617 assert(index < getNumElements() &&
1618 "index must be less than number of fields in bundle");
1619 return getElements()[index];
1623 auto element = getElement(name);
1628 auto element = getElement(name);
1633 assert(index < getNumElements() &&
1634 "index must be less than number of fields in bundle");
1635 return getElements()[index].type;
1638uint64_t BundleType::getFieldID(uint64_t index)
const {
1639 return getImpl()->fieldIDs[index];
1642uint64_t BundleType::getIndexForFieldID(uint64_t fieldID)
const {
1643 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1644 auto fieldIDs = getImpl()->fieldIDs;
1645 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1646 return std::distance(fieldIDs.begin(), it);
1649std::pair<uint64_t, uint64_t>
1650BundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1653 return {index, fieldID - elementFieldID};
1656std::pair<Type, uint64_t>
1657BundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1661 auto subfieldType = getElementType(subfieldIndex);
1662 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1663 return {subfieldType, subfieldID};
1666uint64_t BundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1668std::pair<uint64_t, bool>
1669BundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1671 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1673 return std::make_pair(fieldID - childRoot,
1674 fieldID >= childRoot && fieldID <= rangeEnd);
1677bool BundleType::isConst()
const {
return getImpl()->isConst; }
1679BundleType::ElementType
1680BundleType::getElementTypePreservingConst(
size_t index) {
1681 auto type = getElementType(index);
1682 return type.getConstType(type.isConst() ||
isConst());
1687 auto *
impl = getImpl();
1690 if (
impl->anonymousType)
1691 return impl->anonymousType;
1694 if (!
impl->props.containsTypeAlias) {
1695 impl->anonymousType = *
this;
1701 SmallVector<BundleType::BundleElement, 16> newElements;
1702 newElements.reserve(
impl->elements.size());
1703 for (
auto &elt :
impl->elements)
1704 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1706 auto anonymousType = BundleType::get(getContext(), newElements,
isConst());
1707 impl->anonymousType = anonymousType;
1708 return anonymousType;
1711LogicalResult BundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1712 ArrayRef<BundleElement> elements,
1714 SmallPtrSet<StringAttr, 4> nameSet;
1715 for (
auto &element : elements) {
1716 if (!nameSet.insert(element.name).second)
1717 return emitErrorFn() <<
"duplicate field name " << element.name
1729 using KeyTy = std::tuple<ArrayRef<OpenBundleType::BundleElement>,
char>;
1734 props{true, false, false,
isConst, false, false, false},
1736 uint64_t fieldID = 0;
1739 auto type = element.type;
1740 auto eltInfo = type.getRecursiveTypeProperties();
1741 props.isPassive &= eltInfo.isPassive & !element.isFlip;
1742 props.containsAnalog |= eltInfo.containsAnalog;
1743 props.containsReference |= eltInfo.containsReference;
1744 props.containsConst |= eltInfo.containsConst;
1745 props.containsTypeAlias |= eltInfo.containsTypeAlias;
1746 props.hasUninferredWidth |= eltInfo.hasUninferredWidth;
1747 props.hasUninferredReset |= eltInfo.hasUninferredReset;
1769 static_cast<bool>(std::get<1>(key)));
1772 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1784OpenBundleType OpenBundleType::get(MLIRContext *
context,
1785 ArrayRef<BundleElement> elements,
1791OpenBundleType::getChecked(function_ref<InFlightDiagnostic()> emitErrorFn,
1793 ArrayRef<BundleElement> elements,
bool isConst) {
1794 if (failed(verify(emitErrorFn, elements,
isConst)))
1799auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1800 return getImpl()->elements;
1805 return getImpl()->props;
1808OpenBundleType OpenBundleType::getConstType(
bool isConst)
const {
1811 return get(getContext(), getElements(),
isConst);
1814std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1815 for (
const auto &it : llvm::enumerate(getElements())) {
1816 auto element = it.value();
1817 if (element.name == name) {
1818 return unsigned(it.index());
1821 return std::nullopt;
1824std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1825 for (
const auto &it : llvm::enumerate(getElements())) {
1826 auto element = it.value();
1827 if (element.name.getValue() == name) {
1828 return unsigned(it.index());
1831 return std::nullopt;
1834StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1835 assert(index < getNumElements() &&
1836 "index must be less than number of fields in bundle");
1837 return getElements()[index].name;
1840StringRef OpenBundleType::getElementName(
size_t index) {
1841 return getElementNameAttr(index).getValue();
1844std::optional<OpenBundleType::BundleElement>
1845OpenBundleType::getElement(StringAttr name) {
1846 if (
auto maybeIndex = getElementIndex(name))
1847 return getElements()[*maybeIndex];
1848 return std::nullopt;
1851std::optional<OpenBundleType::BundleElement>
1852OpenBundleType::getElement(StringRef name) {
1853 if (
auto maybeIndex = getElementIndex(name))
1854 return getElements()[*maybeIndex];
1855 return std::nullopt;
1859OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1860 assert(index < getNumElements() &&
1861 "index must be less than number of fields in bundle");
1862 return getElements()[index];
1865OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1866 auto element = getElement(name);
1870OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1871 auto element = getElement(name);
1875OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1876 assert(index < getNumElements() &&
1877 "index must be less than number of fields in bundle");
1878 return getElements()[index].type;
1881uint64_t OpenBundleType::getFieldID(uint64_t index)
const {
1882 return getImpl()->fieldIDs[index];
1885uint64_t OpenBundleType::getIndexForFieldID(uint64_t fieldID)
const {
1886 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1887 auto fieldIDs = getImpl()->fieldIDs;
1888 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1889 return std::distance(fieldIDs.begin(), it);
1892std::pair<uint64_t, uint64_t>
1893OpenBundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1896 return {index, fieldID - elementFieldID};
1899std::pair<Type, uint64_t>
1900OpenBundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1904 auto subfieldType = getElementType(subfieldIndex);
1905 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1906 return {subfieldType, subfieldID};
1909uint64_t OpenBundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1911std::pair<uint64_t, bool>
1912OpenBundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1914 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1916 return std::make_pair(fieldID - childRoot,
1917 fieldID >= childRoot && fieldID <= rangeEnd);
1920bool OpenBundleType::isConst()
const {
return getImpl()->isConst; }
1922OpenBundleType::ElementType
1923OpenBundleType::getElementTypePreservingConst(
size_t index) {
1924 auto type = getElementType(index);
1926 return TypeSwitch<FIRRTLType, ElementType>(type)
1927 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1928 return type.getConstType(type.isConst() ||
isConst());
1934OpenBundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1935 ArrayRef<BundleElement> elements,
bool isConst) {
1936 SmallPtrSet<StringAttr, 4> nameSet;
1937 for (
auto &element : elements) {
1938 if (!nameSet.insert(element.name).second)
1939 return emitErrorFn() <<
"duplicate field name " << element.name
1940 <<
" in openbundle";
1942 return emitErrorFn()
1943 <<
"'const' bundle cannot have references, but element "
1944 << element.name <<
" has type " << element.type;
1946 return emitErrorFn() <<
"bundle element " << element.name
1947 <<
" cannot have a left-hand side type";
1949 return emitErrorFn() <<
"bundle element " << element.name
1950 <<
" cannot have a domain type";
1962 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1980 static_cast<bool>(std::get<2>(key)));
1999 return getImpl()->elementType;
2002size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
2006 return getImpl()->props;
2011 auto *
impl = getImpl();
2014 if (
impl->passiveType)
2015 return impl->passiveType;
2018 if (
impl->elementType.getRecursiveTypeProperties().isPassive)
2019 return impl->passiveType = *
this;
2022 auto passiveType = FVectorType::get(getElementType().
getPassiveType(),
2024 impl->passiveType = passiveType;
2028FVectorType FVectorType::getConstType(
bool isConst)
const {
2031 return get(getElementType(), getNumElements(),
isConst);
2034FVectorType FVectorType::getAllConstDroppedType() {
2037 return get(getElementType().getAllConstDroppedType(), getNumElements(),
2043 auto *
impl = getImpl();
2045 if (
impl->anonymousType)
2046 return impl->anonymousType;
2049 if (!
impl->props.containsTypeAlias)
2050 return impl->anonymousType = *
this;
2053 auto anonymousType = FVectorType::get(getElementType().getAnonymousType(),
2055 impl->anonymousType = anonymousType;
2056 return anonymousType;
2059uint64_t FVectorType::getFieldID(uint64_t index)
const {
2063uint64_t FVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2064 assert(fieldID &&
"fieldID must be at least 1");
2069std::pair<uint64_t, uint64_t>
2070FVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2073 return {index, fieldID - elementFieldID};
2076std::pair<Type, uint64_t>
2077FVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2083uint64_t FVectorType::getMaxFieldID()
const {
2084 return getNumElements() *
2088std::pair<uint64_t, bool>
2089FVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2093 return std::make_pair(fieldID - childRoot,
2094 fieldID >= childRoot && fieldID <= rangeEnd);
2097bool FVectorType::isConst()
const {
return getImpl()->isConst; }
2099FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
2100 auto type = getElementType();
2101 return type.getConstType(type.isConst() ||
isConst());
2109 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
2127 static_cast<bool>(std::get<2>(key)));
2143OpenVectorType::getChecked(function_ref<InFlightDiagnostic()> emitErrorFn,
2151FIRRTLType OpenVectorType::getElementType()
const {
2152 return getImpl()->elementType;
2155size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
2159 return getImpl()->props;
2162OpenVectorType OpenVectorType::getConstType(
bool isConst)
const {
2165 return get(getElementType(), getNumElements(),
isConst);
2168uint64_t OpenVectorType::getFieldID(uint64_t index)
const {
2172uint64_t OpenVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2173 assert(fieldID &&
"fieldID must be at least 1");
2178std::pair<uint64_t, uint64_t>
2179OpenVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2182 return {index, fieldID - elementFieldID};
2185std::pair<Type, uint64_t>
2186OpenVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2192uint64_t OpenVectorType::getMaxFieldID()
const {
2194 return getNumElements() *
2198std::pair<uint64_t, bool>
2199OpenVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2203 return std::make_pair(fieldID - childRoot,
2204 fieldID >= childRoot && fieldID <= rangeEnd);
2207bool OpenVectorType::isConst()
const {
return getImpl()->isConst; }
2209OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2210 auto type = getElementType();
2212 return TypeSwitch<FIRRTLType, ElementType>(type)
2213 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2214 return type.getConstType(type.isConst() ||
isConst());
2220OpenVectorType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2224 return emitErrorFn() <<
"vector cannot be const with references";
2226 return emitErrorFn() <<
"vector cannot have a left-hand side type";
2228 return emitErrorFn() <<
"vector cannot have a domain type";
2237 using KeyTy = std::tuple<ArrayRef<FEnumType::EnumElement>,
char>;
2243 false,
false,
false};
2246 auto type = element.type;
2247 auto eltInfo = type.getRecursiveTypeProperties();
2276FEnumType FEnumType::get(::mlir::MLIRContext *
context,
2277 ArrayRef<EnumElement> elements,
bool isConst) {
2281ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2282 return getImpl()->elements;
2285FEnumType FEnumType::getConstType(
bool isConst)
const {
2286 return get(getContext(), getElements(),
isConst);
2289FEnumType FEnumType::getAllConstDroppedType() {
2293 SmallVector<EnumElement> constDroppedElements(
2294 llvm::map_range(getElements(), [](EnumElement element) {
2295 element.type = element.type.getAllConstDroppedType();
2298 return get(getContext(), constDroppedElements,
false);
2303 return getImpl()->recProps;
2306std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2307 for (
const auto &it : llvm::enumerate(getElements())) {
2308 auto element = it.value();
2309 if (element.name == name) {
2310 return unsigned(it.index());
2313 return std::nullopt;
2316size_t FEnumType::getBitWidth() {
return getDataWidth() + getTagWidth(); }
2318size_t FEnumType::getDataWidth() {
return getImpl()->dataSize; }
2320size_t FEnumType::getTagWidth() {
2321 if (getElements().size() == 0)
2324 return cast<IntegerType>(getElements()[0].value.getType()).getWidth();
2327std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2328 for (
const auto &it : llvm::enumerate(getElements())) {
2329 auto element = it.value();
2330 if (element.name.getValue() == name) {
2331 return unsigned(it.index());
2334 return std::nullopt;
2337StringAttr FEnumType::getElementNameAttr(
size_t index) {
2338 assert(index < getNumElements() &&
2339 "index must be less than number of fields in enum");
2340 return getElements()[index].name;
2343StringRef FEnumType::getElementName(
size_t index) {
2344 return getElementNameAttr(index).getValue();
2347IntegerAttr FEnumType::getElementValueAttr(
size_t index) {
2348 return getElements()[index].value;
2351APInt FEnumType::getElementValue(
size_t index) {
2352 return getElementValueAttr(index).getValue();
2356 return getElements()[index].type;
2359std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2360 if (
auto maybeIndex = getElementIndex(name))
2361 return getElements()[*maybeIndex];
2362 return std::nullopt;
2365std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2366 if (
auto maybeIndex = getElementIndex(name))
2367 return getElements()[*maybeIndex];
2368 return std::nullopt;
2372FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2373 assert(index < getNumElements() &&
2374 "index must be less than number of fields in enum");
2375 return getElements()[index];
2379 auto element = getElement(name);
2384 auto element = getElement(name);
2389 assert(index < getNumElements() &&
2390 "index must be less than number of fields in enum");
2391 return getElements()[index].type;
2394FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2395 auto type = getElementType(index);
2396 return type.getConstType(type.isConst() ||
isConst());
2399LogicalResult FEnumType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2400 ArrayRef<EnumElement> elements,
bool isConst) {
2402 IntegerAttr previous;
2403 SmallPtrSet<Attribute, 4> nameSet;
2405 for (
auto &elt : elements) {
2406 auto r = elt.type.getRecursiveTypeProperties();
2408 return emitErrorFn() <<
"enum field " << elt.name <<
" not passive";
2409 if (r.containsAnalog)
2410 return emitErrorFn() <<
"enum field " << elt.name <<
" contains analog";
2411 if (r.hasUninferredWidth)
2412 return emitErrorFn() <<
"enum field " << elt.name
2413 <<
" has uninferred width";
2414 if (r.hasUninferredReset)
2415 return emitErrorFn() <<
"enum field " << elt.name
2416 <<
" has uninferred reset";
2417 if (r.containsConst && !
isConst)
2418 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2420 if (!nameSet.insert(elt.name).second)
2421 return emitErrorFn() <<
"duplicate variant name " << elt.name
2425 previous = elt.value;
2428 auto current = elt.value;
2429 if (previous.getType() != current.getType())
2430 return emitErrorFn() <<
"enum variant " << elt.name <<
" has type"
2431 << current.getType()
2432 <<
" which is different than previous variant "
2433 << previous.getType();
2435 if (previous.getValue().getBitWidth() != current.getValue().getBitWidth())
2436 return emitErrorFn() <<
"enum variant " << elt.name <<
" has bitwidth"
2437 << current.getValue().getBitWidth()
2438 <<
" which is different than previous variant "
2439 << previous.getValue().getBitWidth();
2440 if (previous.getValue().uge(current.getValue()))
2441 return emitErrorFn()
2442 <<
"enum variant " << elt.name <<
" has value " << current
2443 <<
" which is not greater than previous variant " << previous;
2452 auto *
impl = getImpl();
2454 if (
impl->anonymousType)
2455 return impl->anonymousType;
2457 if (!
impl->recProps.containsTypeAlias)
2458 return impl->anonymousType = *
this;
2460 SmallVector<FEnumType::EnumElement, 4> elements;
2462 for (
auto element : getElements())
2464 {element.name, element.value, element.type.getAnonymousType()});
2465 return impl->anonymousType = FEnumType::get(getContext(), elements);
2474 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2498auto BaseTypeAliasType::get(StringAttr name,
FIRRTLBaseType innerType)
2499 -> BaseTypeAliasType {
2500 return Base::get(name.getContext(), name, innerType);
2503auto BaseTypeAliasType::getName() const -> StringAttr {
2504 return getImpl()->name;
2508 return getImpl()->innerType;
2512 auto *
impl = getImpl();
2513 if (
impl->anonymousType)
2514 return impl->anonymousType;
2515 return impl->anonymousType = getInnerType().getAnonymousType();
2523 auto rtp = getInnerType().getRecursiveTypeProperties();
2531BaseTypeAliasType::getModifiedType(
FIRRTLBaseType newInnerType)
const {
2532 if (newInnerType == getInnerType())
2534 return newInnerType;
2539 return getModifiedType(getInnerType().getAllConstDroppedType());
2543 return getModifiedType(getInnerType().getConstType(
isConst));
2546std::pair<Type, uint64_t>
2547BaseTypeAliasType::getSubTypeByFieldID(uint64_t fieldID)
const {
2551uint64_t BaseTypeAliasType::getMaxFieldID()
const {
2555std::pair<uint64_t, bool>
2556BaseTypeAliasType::projectToChildFieldID(uint64_t fieldID,
2557 uint64_t index)
const {
2561uint64_t BaseTypeAliasType::getIndexForFieldID(uint64_t fieldID)
const {
2565uint64_t BaseTypeAliasType::getFieldID(uint64_t index)
const {
2569std::pair<uint64_t, uint64_t>
2570BaseTypeAliasType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2579 return LHSType::get(type.getContext(), type);
2582LogicalResult LHSType::verify(function_ref<InFlightDiagnostic()> emitError,
2584 if (type.containsAnalog())
2585 return emitError() <<
"lhs type cannot contain an AnalogType";
2587 return emitError() <<
"lhs type cannot contain a non-passive type";
2588 if (type.containsReference())
2589 return emitError() <<
"lhs type cannot contain a reference";
2591 return emitError() <<
"lhs type cannot contain a lhs type";
2600auto RefType::get(
FIRRTLBaseType type,
bool forceable, SymbolRefAttr layer)
2602 return Base::get(type.getContext(), type, forceable, layer);
2605auto RefType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2608 if (!base.isPassive())
2609 return emitErrorFn() <<
"reference base type must be passive";
2610 if (forceable && base.containsConst())
2611 return emitErrorFn()
2612 <<
"forceable reference base type cannot contain const";
2617 auto rtp = getType().getRecursiveTypeProperties();
2620 rtp.isPassive =
false;
2628AnalogType AnalogType::get(mlir::MLIRContext *
context) {
2629 return AnalogType::get(
context, -1,
false);
2632AnalogType AnalogType::get(mlir::MLIRContext *
context,
2633 std::optional<int32_t> width,
bool isConst) {
2637LogicalResult AnalogType::verify(function_ref<InFlightDiagnostic()> emitError,
2638 int32_t widthOrSentinel,
bool isConst) {
2639 if (widthOrSentinel < -1)
2640 return emitError() <<
"invalid width";
2644int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2646AnalogType AnalogType::getConstType(
bool isConst)
const {
2649 return get(getContext(), getWidthOrSentinel(),
isConst);
2656ClockType ClockType::getConstType(
bool isConst)
const {
2666ResetType ResetType::getConstType(
bool isConst)
const {
2676AsyncResetType AsyncResetType::getConstType(
bool isConst)
const {
2687 using KeyTy = std::tuple<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2691 auto name = std::get<0>(key);
2692 auto elements = allocator.copyInto(std::get<1>(key));
2695 SmallVector<uint64_t, 4> ids;
2704 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2726ClassType ClassType::get(FlatSymbolRefAttr name,
2727 ArrayRef<ClassElement> elements) {
2728 return get(name.getContext(), name, elements);
2731StringRef ClassType::getName()
const {
2732 return getNameAttr().getAttr().getValue();
2735FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2737ArrayRef<ClassElement> ClassType::getElements()
const {
2738 return getImpl()->elements;
2741const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2742 return getElement(index.getValue().getZExtValue());
2745const ClassElement &ClassType::getElement(
size_t index)
const {
2746 return getElements()[index];
2749std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2750 for (
const auto [i, e] : llvm::enumerate(getElements()))
2751 if (fieldName == e.name)
2756void ClassType::printInterface(AsmPrinter &p)
const {
2760 for (
const auto &element : getElements()) {
2763 p << element.direction <<
" ";
2764 p.printKeywordOrString(element.name);
2765 p <<
": " << element.type;
2771uint64_t ClassType::getFieldID(uint64_t index)
const {
2772 return getImpl()->fieldIDs[index];
2775uint64_t ClassType::getIndexForFieldID(uint64_t fieldID)
const {
2776 assert(!getElements().
empty() &&
"Class must have >0 fields");
2777 auto fieldIDs = getImpl()->fieldIDs;
2778 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2779 return std::distance(fieldIDs.begin(), it);
2782std::pair<uint64_t, uint64_t>
2783ClassType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2786 return {index, fieldID - elementFieldID};
2789std::pair<Type, uint64_t>
2790ClassType::getSubTypeByFieldID(uint64_t fieldID)
const {
2794 auto subfieldType = getElement(subfieldIndex).type;
2795 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2796 return {subfieldType, subfieldID};
2799uint64_t ClassType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
2801std::pair<uint64_t, bool>
2802ClassType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2804 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2806 return std::make_pair(fieldID - childRoot,
2807 fieldID >= childRoot && fieldID <= rangeEnd);
2814struct InterfaceParser {
2817 InterfaceParser(AsmParser &parser) : parser(parser) {}
2820 template <
typename FieldContainer>
2822 function_ref<ParseResult(FieldContainer &, AsmParser &parser)> parseField,
2823 StringAttr &symbolName, FieldContainer &fields) {
2825 if (parser.parseSymbolName(symbolName))
2829 if (parser.parseLParen())
2833 if (failed(parser.parseOptionalRParen())) {
2834 auto parseElement = [&]() -> ParseResult {
2835 return parseField(fields, parser);
2838 if (parser.parseCommaSeparatedList(parseElement) || parser.parseRParen())
2847ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2848 InterfaceParser helper(parser);
2850 auto parseField = [](SmallVector<ClassElement> &elements,
2851 AsmParser &parser) -> ParseResult {
2854 if (succeeded(parser.parseOptionalKeyword(
"out")))
2856 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2862 std::string keyword;
2863 if (parser.parseKeywordOrString(&keyword))
2865 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2869 if (parser.parseColonType(type))
2872 elements.emplace_back(name, type,
direction);
2876 StringAttr symbolName;
2877 SmallVector<ClassElement> elements;
2878 if (helper.parse<SmallVector<ClassElement>>(parseField, symbolName, elements))
2881 result = ClassType::get(FlatSymbolRefAttr::get(symbolName), elements);
2889ParseResult DomainType::parseInterface(AsmParser &parser, DomainType &result) {
2890 InterfaceParser helper(parser);
2892 auto parseField = [](SmallVector<Attribute> &fields,
2893 AsmParser &parser) -> ParseResult {
2894 std::string fieldNameStr;
2896 if (parser.parseKeywordOrString(&fieldNameStr) || parser.parseColon() ||
2897 parser.parseType(fieldTypeRaw))
2900 auto fieldType = dyn_cast<PropertyType>(fieldTypeRaw);
2902 return parser.emitError(parser.getCurrentLocation(),
2903 "expected property type");
2905 auto fieldName = StringAttr::get(parser.getContext(), fieldNameStr);
2907 DomainFieldAttr::get(parser.getContext(), fieldName, fieldType));
2911 StringAttr symbolName;
2912 SmallVector<Attribute> fields;
2913 if (helper.parse<SmallVector<Attribute>>(parseField, symbolName, fields))
2916 result = DomainType::get(FlatSymbolRefAttr::get(symbolName),
2917 ArrayAttr::get(parser.getContext(), fields));
2921DomainType DomainType::get(FlatSymbolRefAttr name, ArrayAttr fields) {
2922 return Base::get(name.getContext(), name, fields);
2925DomainType DomainType::getFromDomainOp(DomainOp domainOp) {
2926 auto name = FlatSymbolRefAttr::get(domainOp.getNameAttr());
2927 return DomainType::get(name, domainOp.getFieldsAttr());
2930DomainFieldAttr DomainType::getField(
size_t index)
const {
2931 assert(index < getNumFields() &&
"index out of bounds");
2932 return cast<DomainFieldAttr>(getFields()[index]);
2935std::optional<uint64_t> DomainType::getFieldIndex(StringRef fieldName)
const {
2936 for (
const auto [i, attr] : llvm::enumerate(getFields())) {
2937 auto field = cast<DomainFieldAttr>(attr);
2938 if (fieldName == field.getName())
2944std::pair<Type, uint64_t>
2945DomainType::getSubTypeByFieldID(uint64_t fieldID)
const {
2951 if (fieldID > getNumFields())
2952 return {Type(), fieldID};
2954 return {getField(fieldID - 1).getType(), 0};
2957uint64_t DomainType::getMaxFieldID()
const {
2959 return getNumFields();
2962std::pair<uint64_t, bool>
2963DomainType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2965 if (index >= getNumFields())
2968 uint64_t childFieldID = index + 1;
2969 return {0, fieldID == childFieldID};
2972uint64_t DomainType::getFieldID(uint64_t index)
const {
2974 assert(index < getNumFields() &&
"index out of bounds");
2978uint64_t DomainType::getIndexForFieldID(uint64_t fieldID)
const {
2980 assert(fieldID > 0 && fieldID <= getNumFields() &&
"fieldID out of bounds");
2984std::pair<uint64_t, uint64_t>
2985DomainType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2987 assert(fieldID > 0 && fieldID <= getNumFields() &&
"fieldID out of bounds");
2988 return {fieldID - 1, 0};
2992DomainType::verifySymbolUses(Operation *op,
2993 SymbolTableCollection &symbolTable)
const {
2995 auto circuitOp = op->getParentOfType<CircuitOp>();
2997 return op->emitError() <<
"domain type used outside of a circuit";
3000 auto *symbol = symbolTable.lookupSymbolIn(circuitOp,
getName());
3002 return op->emitError() <<
"domain type references undefined symbol '"
3003 <<
getName().getValue() <<
"'";
3006 auto domainOp = dyn_cast<DomainOp>(symbol);
3008 return op->emitError() <<
"domain type references symbol '"
3009 <<
getName().getValue() <<
"' which is not a domain";
3012 auto expectedFields = domainOp.getFieldsAttr();
3013 auto actualFields = getFields();
3016 if (actualFields.size() != expectedFields.size())
3017 return op->emitError() <<
"domain type has " << actualFields.size()
3018 <<
" fields but domain definition has "
3019 << expectedFields.size() <<
" fields";
3022 for (
size_t i = 0; i < actualFields.size(); ++i) {
3023 auto actualField = cast<DomainFieldAttr>(actualFields[i]);
3024 auto expectedField = cast<DomainFieldAttr>(expectedFields[i]);
3027 if (actualField.getName() != expectedField.getName())
3028 return op->emitError() <<
"domain type field " << i <<
" has name '"
3029 << actualField.getName().getValue()
3030 <<
"' but domain definition expects '"
3031 << expectedField.getName().getValue() <<
"'";
3034 if (actualField.getType() != expectedField.getType())
3035 return op->emitError()
3036 <<
"domain type field '" << actualField.getName().getValue()
3037 <<
"' has type " << actualField.getType()
3038 <<
" but domain definition expects " << expectedField.getType();
3048void FIRRTLDialect::registerTypes() {
3050#define GET_TYPEDEF_LIST
3051#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
3065 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
3066 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
3068 for (
auto &elt : bundle) {
3069 if (elt.isFlip && !ignoreFlip)
3070 return std::nullopt;
3073 return std::nullopt;
3078 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
3080 for (
auto &elt : fenum) {
3083 return std::nullopt;
3084 width = std::max(width, *w);
3086 return width + fenum.getTagWidth();
3088 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
3091 return std::nullopt;
3092 return *w * vector.getNumElements();
3095 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
3096 .Default([&](
auto t) {
return std::nullopt; });
3098 return getWidth(type);
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static std::unique_ptr< Context > context
static ParseResult parseFIRRTLBaseType(FIRRTLBaseType &result, StringRef name, AsmParser &parser)
static ParseResult parseFIRRTLPropertyType(PropertyType &result, StringRef name, AsmParser &parser)
static LogicalResult customTypePrinter(Type type, AsmPrinter &os)
Print a type with a custom printer implementation.
static OptionalParseResult customTypeParser(AsmParser &parser, StringRef name, Type &result)
Parse a type with a custom parser implementation.
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static bool areBundleElementsEquivalent(BundleType::BundleElement destElement, BundleType::BundleElement srcElement, bool destOuterTypeIsConst, bool srcOuterTypeIsConst, bool requiresSameWidth)
Helper to implement the equivalence logic for a pair of bundle elements.
@ ContainsAnalogBitMask
Bit set if the type contains an analog type.
@ HasUninferredWidthBitMask
Bit set fi the type has any uninferred bit widths.
@ IsPassiveBitMask
Bit set if the type only contains passive elements.
static ParseResult parseFIRRTLType(FIRRTLType &result, StringRef name, AsmParser &parser)
Parse a FIRRTLType with a name that has already been parsed.
static unsigned getFieldID(BundleType type, unsigned index)
static unsigned getIndexForFieldID(BundleType type, unsigned fieldID)
static unsigned getMaxFieldID(FIRRTLBaseType type)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static InstancePath empty
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getAnonymousType()
Return this type with any type alias types recursively removed from itself.
bool isResetType()
Return true if this is a valid "reset" type.
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
FIRRTLBaseType getPassiveType()
Return this type with any flip types recursively removed from itself.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
FIRRTLBaseType getWidthlessType()
Return this type with widths of all ground types removed.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
bool containsReference()
Return true if this is or contains a Reference type.
bool isGround()
Return true if this is a 'ground' type, aka a non-aggregate type.
RecursiveTypeProperties getRecursiveTypeProperties() const
Return the recursive properties of the type, containing the isPassive, containsAnalog,...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
This is the common base class between SIntType and UIntType.
IntType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
Represents a limited word-length unsigned integer in SystemC as described in IEEE 1666-2011 ยง7....
static UIntType get(MLIRContext *context, unsigned width)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
BaseTy type_cast(Type type)
Direction
This represents the direction of a single port.
ParseResult parseNestedType(FIRRTLType &result, AsmParser &parser)
Parse a FIRRTLType.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
ParseResult parseNestedBaseType(FIRRTLBaseType &result, AsmParser &parser)
bool isTypeInOut(mlir::Type type)
Returns true if the given type has some flipped (aka unaligned) dataflow.
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool hasZeroBitWidth(FIRRTLType type)
Return true if the type has zero bit width.
BaseTy type_dyn_cast(Type type)
void printNestedType(Type type, AsmPrinter &os)
Print a type defined by this dialect.
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool hasHardwareElements(FIRRTLType type)
Return true if the given type contains any elements of hardware types.
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
ParseResult parseNestedPropertyType(PropertyType &result, AsmParser &parser)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
std::pair< uint64_t, uint64_t > getIndexAndSubfieldID(Type type, uint64_t fieldID)
uint64_t getFieldID(Type type, uint64_t index)
std::pair<::mlir::Type, uint64_t > getSubTypeByFieldID(Type, uint64_t fieldID)
std::pair< uint64_t, bool > projectToChildFieldID(Type, uint64_t fieldID, uint64_t index)
uint64_t getIndexForFieldID(Type type, uint64_t fieldID)
uint64_t getMaxFieldID(Type)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::hash_code hash_value(const DenseSet< T > &set)
A collection of bits indicating the recursive properties of a type.
bool containsReference
Whether the type contains a reference type.
bool containsTypeAlias
Whether the type contains a type alias.
bool containsConst
Whether the type contains a const type.
bool operator==(const KeyTy &key) const
static BaseTypeAliasStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
BaseTypeAliasStorage(StringAttr name, FIRRTLBaseType innerType)
std::tuple< StringAttr, FIRRTLBaseType > KeyTy
static llvm::hash_code hashKey(const KeyTy &key)
FIRRTLBaseType anonymousType
static BundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
std::tuple< ArrayRef< BundleType::BundleElement >, char > KeyTy
SmallVector< BundleType::BundleElement, 4 > elements
static llvm::hash_code hashKey(const KeyTy &key)
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
BundleTypeStorage(ArrayRef< BundleType::BundleElement > elements, bool isConst)
bool operator==(const KeyTy &key) const
SmallVector< uint64_t, 4 > fieldIDs
std::tuple< FlatSymbolRefAttr, ArrayRef< ClassElement > > KeyTy
bool operator==(const KeyTy &key) const
ArrayRef< uint64_t > fieldIDs
static ClassTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
ArrayRef< ClassElement > elements
ClassTypeStorage(FlatSymbolRefAttr name, ArrayRef< ClassElement > elements, ArrayRef< uint64_t > fieldIDs, uint64_t maxFieldID)
SmallVector< FEnumType::EnumElement, 4 > elements
static llvm::hash_code hashKey(const KeyTy &key)
bool operator==(const KeyTy &key) const
static FEnumTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FEnumTypeStorage(ArrayRef< FEnumType::EnumElement > elements, bool isConst)
RecursiveTypeProperties recProps
FIRRTLBaseType anonymousType
std::tuple< ArrayRef< FEnumType::EnumElement >, char > KeyTy
bool operator==(const KeyTy &key) const
FIRRTLBaseTypeStorage(bool isConst)
static FIRRTLBaseTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
bool operator==(const KeyTy &key) const
FIRRTLBaseType elementType
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
FIRRTLBaseType passiveType
static FVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FIRRTLBaseType anonymousType
std::tuple< FIRRTLBaseType, size_t, char > KeyTy
FVectorTypeStorage(FIRRTLBaseType elementType, size_t numElements, bool isConst)
SmallVector< OpenBundleType::BundleElement, 4 > elements
bool operator==(const KeyTy &key) const
static OpenBundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
static llvm::hash_code hashKey(const KeyTy &key)
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
OpenBundleTypeStorage(ArrayRef< OpenBundleType::BundleElement > elements, bool isConst)
SmallVector< uint64_t, 4 > fieldIDs
std::tuple< ArrayRef< OpenBundleType::BundleElement >, char > KeyTy
std::tuple< FIRRTLType, size_t, char > KeyTy
bool operator==(const KeyTy &key) const
RecursiveTypeProperties props
static OpenVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
OpenVectorTypeStorage(FIRRTLType elementType, size_t numElements, bool isConst)
WidthTypeStorage(int32_t width, bool isConst)
std::tuple< int32_t, char > KeyTy
bool operator==(const KeyTy &key) const
static WidthTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)