17 #include "mlir/IR/DialectImplementation.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringSwitch.h"
20 #include "llvm/ADT/TypeSwitch.h"
22 using namespace circt;
23 using namespace firrtl;
25 using mlir::OptionalParseResult;
26 using mlir::TypeStorageAllocator;
33 #define GET_TYPEDEF_CLASSES
34 #include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
50 auto printWidthQualifier = [&](std::optional<int32_t>
width) {
52 os << '<' << *width << '>
';
54 bool anyFailed = false;
55 TypeSwitch<Type>(type)
56 .Case<ClockType>([&](auto) { os << "clock"; })
57 .Case<ResetType>([&](auto) { os << "reset"; })
58 .Case<AsyncResetType>([&](auto) { os << "asyncreset"; })
59 .Case<SIntType>([&](auto sIntType) {
61 printWidthQualifier(sIntType.getWidth());
63 .Case<UIntType>([&](auto uIntType) {
65 printWidthQualifier(uIntType.getWidth());
67 .Case<AnalogType>([&](auto analogType) {
69 printWidthQualifier(analogType.getWidth());
71 .Case<BundleType, OpenBundleType>([&](auto bundleType) {
72 if (firrtl::type_isa<OpenBundleType>(bundleType))
75 llvm::interleaveComma(bundleType, os, [&](auto element) {
76 StringRef fieldName = element.name.getValue();
77 bool isLiteralIdentifier =
78 !fieldName.empty() && llvm::isDigit(fieldName.front());
79 if (isLiteralIdentifier)
81 os << element.name.getValue();
82 if (isLiteralIdentifier)
87 printNestedType(element.type, os);
91 .Case<FEnumType>([&](auto fenumType) {
93 llvm::interleaveComma(fenumType, os,
94 [&](FEnumType::EnumElement element) {
95 os << element.name.getValue();
97 printNestedType(element.type, os);
101 .Case<FVectorType, OpenVectorType>([&](auto vectorType) {
102 if (firrtl::type_isa<OpenVectorType>(vectorType))
105 printNestedType(vectorType.getElementType(), os);
106 os << ", " << vectorType.getNumElements() << '>
';
108 .Case<RefType>([&](RefType refType) {
109 if (refType.getForceable())
112 printNestedType(refType.getType(), os);
113 if (auto layer = refType.getLayer())
117 .Case<StringType>([&](auto stringType) { os << "string"; })
118 .Case<FIntegerType>([&](auto integerType) { os << "integer"; })
119 .Case<BoolType>([&](auto boolType) { os << "bool"; })
120 .Case<DoubleType>([&](auto doubleType) { os << "double"; })
121 .Case<ListType>([&](auto listType) {
123 printNestedType(listType.getElementType(), os);
126 .Case<PathType>([&](auto pathType) { os << "path"; })
127 .Case<BaseTypeAliasType>([&](BaseTypeAliasType alias) {
128 os << "alias<" << alias.getName().getValue() << ", ";
129 printNestedType(alias.getInnerType(), os);
132 .Case<ClassType>([&](ClassType type) {
134 type.printInterface(os);
137 .Case<AnyRefType>([&](AnyRefType type) { os << "anyref"; })
138 .Default([&](auto) { anyFailed = true; });
139 return failure(anyFailed);
141 // NOLINTEND(misc-no-recursion)
144 void circt::firrtl::printNestedType(Type type, AsmPrinter &os) {
145 // Try the custom type printer.
146 if (succeeded(customTypePrinter(type, os)))
149 // None of the above recognized the type, so we bail.
150 assert(false && "type to print unknown to FIRRTL dialect");
153 //===----------------------------------------------------------------------===//
155 //===----------------------------------------------------------------------===//
182 static OptionalParseResult customTypeParser(AsmParser &parser, StringRef name,
184 bool isConst = false;
185 const char constPrefix[] = "const.";
186 if (name.starts_with(constPrefix)) {
188 name = name.drop_front(std::size(constPrefix) - 1);
191 auto *context = parser.getContext();
192 if (name.equals("clock"))
193 return result = ClockType::get(context, isConst), success();
194 if (name.equals("reset"))
195 return result = ResetType::get(context, isConst), success();
196 if (name.equals("asyncreset"))
197 return result = AsyncResetType::get(context, isConst), success();
199 if (name.equals("sint") || name.equals("uint") || name.equals("analog")) {
200 // Parse the width specifier if it exists.
202 if (!parser.parseOptionalLess()) {
203 if (parser.parseInteger(width) || parser.parseGreater())
207 return parser.emitError(parser.getNameLoc(), "unknown width"),
211 if (name.equals("sint"))
212 result = SIntType::get(context, width, isConst);
213 else if (name.equals("uint"))
214 result = UIntType::get(context, width, isConst);
216 assert(name.equals("analog"));
217 result = AnalogType::get(context, width, isConst);
222 if (name.equals("bundle")) {
223 SmallVector<BundleType::BundleElement, 4> elements;
225 auto parseBundleElement = [&]() -> ParseResult {
230 if (failed(parser.parseKeywordOrString(&nameStr)))
234 bool isFlip = succeeded(parser.parseOptionalKeyword("flip"));
235 if (parser.parseColon() || parseNestedBaseType(type, parser))
238 elements.push_back({StringAttr::get(context, name), isFlip, type});
242 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
246 return result = BundleType::get(context, elements, isConst), success();
248 if (name.equals("openbundle")) {
249 SmallVector<OpenBundleType::BundleElement, 4> elements;
251 auto parseBundleElement = [&]() -> ParseResult {
256 if (failed(parser.parseKeywordOrString(&nameStr)))
260 bool isFlip = succeeded(parser.parseOptionalKeyword("flip"));
261 if (parser.parseColon() || parseNestedType(type, parser))
264 elements.push_back({StringAttr::get(context, name), isFlip, type});
268 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
272 result = parser.getChecked<OpenBundleType>(context, elements, isConst);
273 return failure(!result);
276 if (name.equals("enum")) {
277 SmallVector<FEnumType::EnumElement, 4> elements;
279 auto parseEnumElement = [&]() -> ParseResult {
284 if (failed(parser.parseKeywordOrString(&nameStr)))
288 if (parser.parseColon() || parseNestedBaseType(type, parser))
291 elements.push_back({StringAttr::get(context, name), type});
295 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
298 if (failed(FEnumType::verify(
299 [&]() { return parser.emitError(parser.getNameLoc()); }, elements,
303 return result = FEnumType::get(context, elements, isConst), success();
306 if (name.equals("vector")) {
307 FIRRTLBaseType elementType;
310 if (parser.parseLess() || parseNestedBaseType(elementType, parser) ||
311 parser.parseComma() || parser.parseInteger(width) ||
312 parser.parseGreater())
315 return result = FVectorType::get(elementType, width, isConst), success();
317 if (name.equals("openvector")) {
318 FIRRTLType elementType;
321 if (parser.parseLess() || parseNestedType(elementType, parser) ||
322 parser.parseComma() || parser.parseInteger(width) ||
323 parser.parseGreater())
327 parser.getChecked<OpenVectorType>(context, elementType, width, isConst);
328 return failure(!result);
331 // For now, support both firrtl.ref and firrtl.probe.
332 if (name.equals("ref") || name.equals("probe")) {
339 if (parser.parseOptionalComma().succeeded())
340 if (parser.parseOptionalAttribute(layer).value())
341 return parser.emitError(parser.getNameLoc(),
342 "expected symbol reference");
343 if (parser.parseGreater())
346 if (failed(RefType::verify(
347 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
351 return result =
RefType::get(type,
false, layer), success();
353 if (name.equals(
"rwprobe")) {
358 if (parser.parseOptionalComma().succeeded())
359 if (parser.parseOptionalAttribute(layer).value())
360 return parser.emitError(parser.getNameLoc(),
361 "expected symbol reference");
362 if (parser.parseGreater())
365 if (failed(RefType::verify(
366 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
true,
370 return result =
RefType::get(type,
true, layer), success();
372 if (name.equals(
"class")) {
374 return parser.emitError(parser.getNameLoc(),
"classes cannot be const");
376 if (parser.parseLess() || ClassType::parseInterface(parser, classType) ||
377 parser.parseGreater())
382 if (name.equals(
"anyref")) {
384 return parser.emitError(parser.getNameLoc(),
"any refs cannot be const");
389 if (name.equals(
"string")) {
391 parser.emitError(parser.getNameLoc(),
"strings cannot be const");
397 if (name.equals(
"integer")) {
399 parser.emitError(parser.getNameLoc(),
"bigints cannot be const");
405 if (name.equals(
"bool")) {
407 parser.emitError(parser.getNameLoc(),
"bools cannot be const");
413 if (name.equals(
"double")) {
415 parser.emitError(parser.getNameLoc(),
"doubles cannot be const");
421 if (name.equals(
"list")) {
423 parser.emitError(parser.getNameLoc(),
"lists cannot be const");
428 parser.parseGreater())
430 result = parser.getChecked<ListType>(context,
elementType);
435 if (name.equals(
"path")) {
437 parser.emitError(parser.getNameLoc(),
"path cannot be const");
443 if (name.equals(
"alias")) {
446 if (parser.parseLess() || parser.parseKeyword(&name) ||
448 parser.parseGreater())
464 static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
467 if (parseResult.has_value())
468 return parseResult.value();
471 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL dialect type: \"")
483 if (failed(
parseType(type, name, parser)))
485 result = type_dyn_cast<FIRRTLType>(type);
488 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL type: \"")
498 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type)) {
502 parser.emitError(parser.getNameLoc(),
"expected base type, found ") << type;
511 if (
auto prop = type_dyn_cast<PropertyType>(type)) {
515 parser.emitError(parser.getNameLoc(),
"expected property type, found ")
528 if (parser.parseKeyword(&name))
538 if (parser.parseKeyword(&name))
548 if (parser.parseKeyword(&name))
559 void FIRRTLDialect::printType(Type type, DialectAsmPrinter &os)
const {
567 if (parser.parseKeyword(&name) || ::
parseType(result, name, parser))
611 return TypeSwitch<FIRRTLType, bool>(*
this)
612 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
613 AnalogType>([](Type) {
return true; })
614 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType>(
615 [](Type) {
return false; })
616 .Case<BaseTypeAliasType>([](BaseTypeAliasType alias) {
617 return alias.getAnonymousType().isGround();
620 .Case<PropertyType, RefType>([](Type) {
return false; })
622 llvm_unreachable(
"unknown FIRRTL type");
628 return TypeSwitch<FIRRTLType, bool>(*
this)
630 [](
auto type) {
return type.
isConst(); })
637 return TypeSwitch<FIRRTLType, RecursiveTypeProperties>(*
this)
638 .Case<ClockType, ResetType, AsyncResetType>([](
FIRRTLBaseType type) {
645 firrtl::type_isa<ResetType>(type)};
647 .Case<SIntType, UIntType>([](
auto type) {
649 true,
false,
false, type.
isConst(),
false, !type.hasWidth(),
false};
651 .Case<AnalogType>([](
auto type) {
653 true,
false,
true, type.
isConst(),
false, !type.hasWidth(),
false};
655 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType,
656 RefType, BaseTypeAliasType>(
657 [](
auto type) {
return type.getRecursiveTypeProperties(); })
658 .Case<PropertyType>([](
auto type) {
660 false,
false,
false};
663 llvm_unreachable(
"unknown FIRRTL type");
670 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
671 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
672 AnalogType>([&](Type) {
return *
this; })
673 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
676 llvm_unreachable(
"unknown FIRRTL type");
683 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
684 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
685 AnalogType, FEnumType>([&](Type) {
return *
this; })
686 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
689 llvm_unreachable(
"unknown FIRRTL type");
696 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
697 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
698 UIntType, BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
701 llvm_unreachable(
"unknown FIRRTL type");
708 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
709 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
710 UIntType>([&](
auto type) {
return type.
getConstType(
false); })
711 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
714 llvm_unreachable(
"unknown FIRRTL type");
722 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
723 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
724 AnalogType>([&](Type) {
727 .Case<BundleType>([&](BundleType bundleType) {
728 SmallVector<BundleType::BundleElement, 4> newElements;
729 newElements.reserve(bundleType.getElements().size());
730 for (
auto elt : bundleType)
731 newElements.push_back(
732 {elt.name,
false , elt.type.getMaskType()});
734 bundleType.isConst());
736 .Case<FVectorType>([](FVectorType vectorType) {
738 vectorType.getNumElements(),
739 vectorType.isConst());
741 .Case<BaseTypeAliasType>([](BaseTypeAliasType base) {
742 return base.getModifiedType(base.getInnerType().getMaskType());
745 llvm_unreachable(
"unknown FIRRTL type");
753 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
754 .Case<ClockType, ResetType, AsyncResetType>([](
auto a) {
return a; })
755 .Case<UIntType, SIntType, AnalogType>(
756 [&](
auto a) {
return a.get(this->getContext(), -1, a.isConst()); })
757 .Case<BundleType>([&](
auto a) {
758 SmallVector<BundleType::BundleElement, 4> newElements;
759 newElements.reserve(a.getElements().size());
761 newElements.push_back(
762 {elt.name, elt.isFlip, elt.type.getWidthlessType()});
765 .Case<FVectorType>([](
auto a) {
767 a.getNumElements(), a.isConst());
769 .Case<FEnumType>([&](FEnumType a) {
770 SmallVector<FEnumType::EnumElement, 4> newElements;
771 newElements.reserve(a.getNumElements());
773 newElements.push_back({elt.name, elt.type.getWidthlessType()});
774 return FEnumType::get(this->getContext(), newElements, a.isConst());
776 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
777 return type.getModifiedType(type.getInnerType().getWidthlessType());
780 llvm_unreachable(
"unknown FIRRTL type");
790 return TypeSwitch<FIRRTLBaseType, int32_t>(*
this)
791 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
792 .Case<SIntType, UIntType>(
795 [](AnalogType analogType) {
return analogType.getWidthOrSentinel(); })
796 .Case<BundleType, FVectorType, FEnumType>([](Type) {
return -2; })
797 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
799 return type.getAnonymousType().getBitWidthOrSentinel();
802 llvm_unreachable(
"unknown FIRRTL type");
811 return TypeSwitch<FIRRTLType, bool>(*
this)
812 .Case<ResetType, AsyncResetType>([](Type) {
return true; })
814 [](UIntType a) {
return !a.hasWidth() || a.getWidth() == 1; })
815 .Case<BaseTypeAliasType>(
816 [](
auto type) {
return type.getInnerType().
isResetType(); })
817 .Default([](Type) {
return false; });
821 return TypeSwitch<Type, bool>(type)
823 [](
auto base) {
return base.isConst(); })
828 return TypeSwitch<Type, bool>(type)
830 [](
auto base) {
return base.containsConst(); })
837 .
Case<BundleType>([&](
auto bundle) {
838 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
839 auto elt = bundle.getElement(i);
843 return bundle.getNumElements() == 0;
845 .Case<FVectorType>([&](
auto vector) {
846 if (vector.getNumElements() == 0)
850 .Case<FIRRTLBaseType>([](
auto groundType) {
853 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
854 .Default([](
auto) {
return false; });
864 BundleType::BundleElement srcElement,
865 bool destOuterTypeIsConst,
866 bool srcOuterTypeIsConst,
867 bool requiresSameWidth) {
868 if (destElement.name != srcElement.name)
870 if (destElement.isFlip != srcElement.isFlip)
873 if (destElement.isFlip) {
874 std::swap(destElement, srcElement);
875 std::swap(destOuterTypeIsConst, srcOuterTypeIsConst);
879 destOuterTypeIsConst, srcOuterTypeIsConst,
888 bool destOuterTypeIsConst,
889 bool srcOuterTypeIsConst,
890 bool requireSameWidths) {
891 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
892 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
895 if (!destType || !srcType)
896 return destFType == srcFType;
898 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
899 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
902 auto destVectorType = type_dyn_cast<FVectorType>(destType);
903 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
904 if (destVectorType && srcVectorType)
905 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
907 srcVectorType.getElementType(), destIsConst,
908 srcIsConst, requireSameWidths);
912 auto destBundleType = type_dyn_cast<BundleType>(destType);
913 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
914 if (destBundleType && srcBundleType) {
915 auto destElements = destBundleType.getElements();
916 auto srcElements = srcBundleType.getElements();
917 size_t numDestElements = destElements.size();
918 if (numDestElements != srcElements.size())
921 for (
size_t i = 0; i < numDestElements; ++i) {
922 auto destElement = destElements[i];
923 auto srcElement = srcElements[i];
925 srcIsConst, requireSameWidths))
933 auto dstEnumType = type_dyn_cast<FEnumType>(destType);
934 auto srcEnumType = type_dyn_cast<FEnumType>(srcType);
936 if (dstEnumType && srcEnumType) {
937 if (dstEnumType.getNumElements() != srcEnumType.getNumElements())
940 for (
const auto &[dst, src] : llvm::zip(dstEnumType, srcEnumType)) {
942 if (dst.name != src.name)
954 if (destIsConst && !srcIsConst)
958 if (firrtl::type_isa<ResetType>(destType))
959 return srcType.isResetType();
962 if (firrtl::type_isa<ResetType>(srcType))
963 return destType.isResetType();
967 if (!requireSameWidths || destType.getBitWidthOrSentinel() == -1)
968 srcType = srcType.getWidthlessType();
969 if (!requireSameWidths || srcType.getBitWidthOrSentinel() == -1)
970 destType = destType.getWidthlessType();
973 return destType.getConstType(
false) == srcType.getConstType(
false);
978 bool destFlip,
bool srcFlip,
979 bool destOuterTypeIsConst,
980 bool srcOuterTypeIsConst) {
981 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
982 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
985 if (!destType || !srcType)
986 return destFType == srcFType;
988 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
989 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
993 auto destVectorType = type_dyn_cast<FVectorType>(destType);
994 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
995 if (destVectorType && srcVectorType)
997 srcVectorType.getElementType(), destFlip,
998 srcFlip, destIsConst, srcIsConst);
1003 auto destBundleType = type_dyn_cast<BundleType>(destType);
1004 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1005 if (destBundleType && srcBundleType)
1006 return llvm::all_of(destBundleType, [&](
auto destElt) ->
bool {
1007 auto destField = destElt.name.getValue();
1008 auto srcElt = srcBundleType.getElement(destField);
1014 destElt.type, srcElt->type, destFlip ^ destElt.isFlip,
1015 srcFlip ^ srcElt->isFlip, destOuterTypeIsConst, srcOuterTypeIsConst);
1019 if (destFlip != srcFlip)
1021 if (destFlip && srcIsConst && !destIsConst)
1023 if (srcFlip && destIsConst && !srcIsConst)
1027 if (type_isa<ResetType>(destType))
1028 return srcType.isResetType();
1031 if (type_isa<ResetType>(srcType))
1032 return destType.isResetType();
1036 auto widthlessDestType = destType.getWidthlessType();
1037 auto widthlessSrcType = srcType.getWidthlessType();
1038 return widthlessDestType.getConstType(
false) ==
1039 widthlessSrcType.getConstType(
false);
1044 bool srcOuterTypeIsConst) {
1046 if (destFType == srcFType)
1049 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
1050 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
1053 if (!destType || !srcType)
1057 if (!destType.isPassive() || !srcType.isPassive())
1060 bool srcIsConst = srcType.isConst() || srcOuterTypeIsConst;
1063 if (destType.isConst() && !srcIsConst)
1068 auto destVectorType = type_dyn_cast<FVectorType>(destType);
1069 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
1070 if (destVectorType && srcVectorType)
1071 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1073 srcVectorType.getElementType(), srcIsConst);
1074 if (destVectorType != srcVectorType)
1079 auto destBundleType = type_dyn_cast<BundleType>(destType);
1080 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1081 if (destBundleType && srcBundleType) {
1082 auto destElements = destBundleType.getElements();
1083 auto srcElements = srcBundleType.getElements();
1084 size_t numDestElements = destElements.size();
1085 if (numDestElements != srcElements.size())
1088 return llvm::all_of_zip(
1089 destElements, srcElements,
1090 [&](
const auto &destElement,
const auto &srcElement) {
1091 return destElement.name == srcElement.name &&
1096 if (destBundleType != srcBundleType)
1101 return destType == srcType.getConstType(destType.isConst());
1105 auto dstRefType = type_dyn_cast<RefType>(dstType);
1106 auto srcRefType = type_dyn_cast<RefType>(srcType);
1107 if (!dstRefType || !srcRefType)
1109 if (dstRefType == srcRefType)
1111 if (dstRefType.getForceable() && !srcRefType.getForceable())
1123 bool srcOuterTypeIsConst) ->
bool {
1129 assert(dest.isPassive() && src.isPassive());
1131 bool srcIsConst = src.isConst() || srcOuterTypeIsConst;
1134 if (dest.isConst() && !srcIsConst)
1140 if (
auto destVectorType = type_dyn_cast<FVectorType>(dest)) {
1141 auto srcVectorType = type_dyn_cast<FVectorType>(src);
1142 return srcVectorType &&
1143 destVectorType.getNumElements() ==
1144 srcVectorType.getNumElements() &&
1145 f(f, destVectorType.getElementType(),
1146 srcVectorType.getElementType(), srcIsConst);
1149 if (
auto destBundleType = type_dyn_cast<BundleType>(dest)) {
1150 auto srcBundleType = type_dyn_cast<BundleType>(src);
1154 auto destElements = destBundleType.getElements();
1155 auto srcElements = srcBundleType.getElements();
1157 return destElements.size() == srcElements.size() &&
1159 destElements, srcElements,
1160 [&](
const auto &destElement,
const auto &srcElement) {
1161 return destElement.name == srcElement.name &&
1162 f(f, destElement.type, srcElement.type, srcIsConst);
1166 if (
auto destEnumType = type_dyn_cast<FEnumType>(dest)) {
1167 auto srcEnumType = type_dyn_cast<FEnumType>(src);
1170 auto destElements = destEnumType.getElements();
1171 auto srcElements = srcEnumType.getElements();
1173 return destElements.size() == srcElements.size() &&
1175 destElements, srcElements,
1176 [&](
const auto &destElement,
const auto &srcElement) {
1177 return destElement.name == srcElement.name &&
1178 f(f, destElement.type, srcElement.type, srcIsConst);
1183 if (type_isa<ResetType>(dest))
1184 return src.isResetType();
1188 src = src.getConstType(dest.isConst());
1191 if (dest.getBitWidthOrSentinel() == -1)
1192 src = src.getWidthlessType();
1197 return recurse(recurse, dstRefType.getType(), srcRefType.getType(),
false);
1204 return TypeSwitch<FIRRTLBaseType, bool>(dstType)
1205 .Case<BundleType>([&](
auto dstBundle) {
1206 auto srcBundle = type_cast<BundleType>(srcType);
1207 for (
size_t i = 0, n = dstBundle.getNumElements(); i < n; ++i) {
1208 auto srcElem = srcBundle.getElement(i);
1209 auto dstElem = dstBundle.getElement(i);
1210 if (dstElem.isFlip) {
1220 .Case<FVectorType>([&](
auto vector) {
1222 type_cast<FVectorType>(srcType).getElementType());
1224 .Default([&](
auto dstGround) {
1227 return destWidth <= -1 || srcWidth <= -1 || destWidth >= srcWidth;
1238 if (
auto destBaseType = type_dyn_cast<FIRRTLBaseType>(lhs))
1239 if (
auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(rhs))
1242 if (
auto destRefType = type_dyn_cast<RefType>(lhs))
1243 if (
auto srcRefType = type_dyn_cast<RefType>(rhs))
1245 srcRefType.getType());
1253 return type_cast<FIRRTLBaseType>(anyBaseFIRRTLType).getPassiveType();
1257 return llvm::TypeSwitch<Type, bool>(type)
1259 return !type.containsReference() &&
1260 (!type.isPassive() || type.containsAnalog());
1272 int32_t widthOrSentinel,
bool isConst) {
1279 if (
auto sintType = type_dyn_cast<SIntType>(*
this))
1280 return sintType.getWidthOrSentinel();
1281 if (
auto uintType = type_dyn_cast<UIntType>(*
this))
1282 return uintType.getWidthOrSentinel();
1310 if (
auto sIntType = type_dyn_cast<SIntType>(*
this))
1319 SIntType
SIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1326 LogicalResult SIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1327 int32_t widthOrSentinel,
bool isConst) {
1328 if (widthOrSentinel < -1)
1329 return emitError() <<
"invalid width";
1333 int32_t SIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1335 SIntType SIntType::getConstType(
bool isConst) {
1338 return get(getContext(), getWidthOrSentinel(),
isConst);
1352 LogicalResult UIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1353 int32_t widthOrSentinel,
bool isConst) {
1354 if (widthOrSentinel < -1)
1355 return emitError() <<
"invalid width";
1359 int32_t UIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1361 UIntType UIntType::getConstType(
bool isConst) {
1364 return get(getContext(), getWidthOrSentinel(),
isConst);
1373 using KeyTy = std::pair<ArrayRef<BundleType::BundleElement>,
char>;
1380 uint64_t fieldID = 0;
1383 auto type = element.type;
1384 auto eltInfo = type.getRecursiveTypeProperties();
1405 return llvm::hash_combine(
1406 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1428 ArrayRef<BundleElement> elements,
bool isConst) {
1432 auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1433 return getImpl()->elements;
1438 return getImpl()->props;
1443 auto *impl = getImpl();
1446 if (impl->passiveType)
1447 return impl->passiveType;
1450 if (impl->props.isPassive) {
1451 impl->passiveType = *
this;
1456 SmallVector<BundleType::BundleElement, 16> newElements;
1457 newElements.reserve(impl->elements.size());
1458 for (
auto &elt : impl->elements) {
1459 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1463 impl->passiveType = passiveType;
1467 BundleType BundleType::getConstType(
bool isConst) {
1470 return get(getContext(), getElements(),
isConst);
1473 BundleType BundleType::getAllConstDroppedType() {
1477 SmallVector<BundleElement> constDroppedElements(
1478 llvm::map_range(getElements(), [](BundleElement element) {
1479 element.type = element.type.getAllConstDroppedType();
1482 return get(getContext(), constDroppedElements,
false);
1485 std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1486 for (
const auto &it : llvm::enumerate(getElements())) {
1487 auto element = it.value();
1488 if (element.name == name) {
1489 return unsigned(it.index());
1492 return std::nullopt;
1495 std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1496 for (
const auto &it : llvm::enumerate(getElements())) {
1497 auto element = it.value();
1498 if (element.name.getValue() == name) {
1499 return unsigned(it.index());
1502 return std::nullopt;
1505 StringAttr BundleType::getElementNameAttr(
size_t index) {
1506 assert(index < getNumElements() &&
1507 "index must be less than number of fields in bundle");
1508 return getElements()[index].name;
1511 StringRef BundleType::getElementName(
size_t index) {
1512 return getElementNameAttr(index).getValue();
1515 std::optional<BundleType::BundleElement>
1516 BundleType::getElement(StringAttr name) {
1517 if (
auto maybeIndex = getElementIndex(name))
1518 return getElements()[*maybeIndex];
1519 return std::nullopt;
1522 std::optional<BundleType::BundleElement>
1523 BundleType::getElement(StringRef name) {
1524 if (
auto maybeIndex = getElementIndex(name))
1525 return getElements()[*maybeIndex];
1526 return std::nullopt;
1530 BundleType::BundleElement BundleType::getElement(
size_t index) {
1531 assert(index < getNumElements() &&
1532 "index must be less than number of fields in bundle");
1533 return getElements()[index];
1537 auto element = getElement(name);
1542 auto element = getElement(name);
1547 assert(index < getNumElements() &&
1548 "index must be less than number of fields in bundle");
1549 return getElements()[index].type;
1553 return getImpl()->fieldIDs[index];
1557 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1558 auto fieldIDs = getImpl()->fieldIDs;
1559 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1560 return std::distance(fieldIDs.begin(), it);
1563 std::pair<uint64_t, uint64_t>
1567 return {index, fieldID - elementFieldID};
1570 std::pair<Type, uint64_t>
1575 auto subfieldType = getElementType(subfieldIndex);
1576 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1577 return {subfieldType, subfieldID};
1582 std::pair<uint64_t, bool>
1585 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1587 return std::make_pair(fieldID - childRoot,
1588 fieldID >= childRoot && fieldID <= rangeEnd);
1593 BundleType::ElementType
1594 BundleType::getElementTypePreservingConst(
size_t index) {
1595 auto type = getElementType(index);
1596 return type.getConstType(type.isConst() ||
isConst());
1601 auto *impl = getImpl();
1604 if (impl->anonymousType)
1605 return impl->anonymousType;
1608 if (!impl->props.containsTypeAlias) {
1609 impl->anonymousType = *
this;
1615 SmallVector<BundleType::BundleElement, 16> newElements;
1616 newElements.reserve(impl->elements.size());
1617 for (
auto &elt : impl->elements)
1618 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1621 impl->anonymousType = anonymousType;
1622 return anonymousType;
1630 using KeyTy = std::pair<ArrayRef<OpenBundleType::BundleElement>,
char>;
1638 uint64_t fieldID = 0;
1641 auto type = element.type;
1642 auto eltInfo = type.getRecursiveTypeProperties();
1662 return llvm::hash_combine(
1663 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1675 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1688 ArrayRef<BundleElement> elements,
1693 auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1694 return getImpl()->elements;
1699 return getImpl()->props;
1702 OpenBundleType OpenBundleType::getConstType(
bool isConst) {
1705 return get(getContext(), getElements(),
isConst);
1708 std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1709 for (
const auto &it : llvm::enumerate(getElements())) {
1710 auto element = it.value();
1711 if (element.name == name) {
1712 return unsigned(it.index());
1715 return std::nullopt;
1718 std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1719 for (
const auto &it : llvm::enumerate(getElements())) {
1720 auto element = it.value();
1721 if (element.name.getValue() == name) {
1722 return unsigned(it.index());
1725 return std::nullopt;
1728 StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1729 assert(index < getNumElements() &&
1730 "index must be less than number of fields in bundle");
1731 return getElements()[index].name;
1734 StringRef OpenBundleType::getElementName(
size_t index) {
1735 return getElementNameAttr(index).getValue();
1738 std::optional<OpenBundleType::BundleElement>
1739 OpenBundleType::getElement(StringAttr name) {
1740 if (
auto maybeIndex = getElementIndex(name))
1741 return getElements()[*maybeIndex];
1742 return std::nullopt;
1745 std::optional<OpenBundleType::BundleElement>
1746 OpenBundleType::getElement(StringRef name) {
1747 if (
auto maybeIndex = getElementIndex(name))
1748 return getElements()[*maybeIndex];
1749 return std::nullopt;
1753 OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1754 assert(index < getNumElements() &&
1755 "index must be less than number of fields in bundle");
1756 return getElements()[index];
1759 OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1760 auto element = getElement(name);
1764 OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1765 auto element = getElement(name);
1769 OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1770 assert(index < getNumElements() &&
1771 "index must be less than number of fields in bundle");
1772 return getElements()[index].type;
1776 return getImpl()->fieldIDs[index];
1780 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1781 auto fieldIDs = getImpl()->fieldIDs;
1782 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1783 return std::distance(fieldIDs.begin(), it);
1786 std::pair<uint64_t, uint64_t>
1790 return {index, fieldID - elementFieldID};
1793 std::pair<Type, uint64_t>
1798 auto subfieldType = getElementType(subfieldIndex);
1799 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1800 return {subfieldType, subfieldID};
1805 std::pair<uint64_t, bool>
1808 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1810 return std::make_pair(fieldID - childRoot,
1811 fieldID >= childRoot && fieldID <= rangeEnd);
1816 OpenBundleType::ElementType
1817 OpenBundleType::getElementTypePreservingConst(
size_t index) {
1818 auto type = getElementType(index);
1820 return TypeSwitch<FIRRTLType, ElementType>(type)
1821 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1822 return type.getConstType(type.isConst() ||
isConst());
1828 OpenBundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1829 ArrayRef<BundleElement> elements,
bool isConst) {
1830 for (
auto &element : elements) {
1832 return emitErrorFn()
1833 <<
"'const' bundle cannot have references, but element "
1834 << element.name <<
" has type " << element.type;
1846 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1864 static_cast<bool>(std::get<2>(key)));
1883 return getImpl()->elementType;
1886 size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
1890 return getImpl()->props;
1895 auto *impl = getImpl();
1898 if (impl->passiveType)
1899 return impl->passiveType;
1902 if (impl->elementType.getRecursiveTypeProperties().isPassive)
1903 return impl->passiveType = *
this;
1908 impl->passiveType = passiveType;
1912 FVectorType FVectorType::getConstType(
bool isConst) {
1915 return get(getElementType(), getNumElements(),
isConst);
1918 FVectorType FVectorType::getAllConstDroppedType() {
1921 return get(getElementType().getAllConstDroppedType(), getNumElements(),
1927 auto *impl = getImpl();
1929 if (impl->anonymousType)
1930 return impl->anonymousType;
1933 if (!impl->props.containsTypeAlias)
1934 return impl->anonymousType = *
this;
1939 impl->anonymousType = anonymousType;
1940 return anonymousType;
1948 assert(fieldID &&
"fieldID must be at least 1");
1953 std::pair<uint64_t, uint64_t>
1957 return {index, fieldID - elementFieldID};
1960 std::pair<Type, uint64_t>
1968 return getNumElements() *
1972 std::pair<uint64_t, bool>
1977 return std::make_pair(fieldID - childRoot,
1978 fieldID >= childRoot && fieldID <= rangeEnd);
1983 FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
1984 auto type = getElementType();
1985 return type.getConstType(type.isConst() ||
isConst());
1993 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
2011 static_cast<bool>(std::get<2>(key)));
2026 FIRRTLType OpenVectorType::getElementType()
const {
2027 return getImpl()->elementType;
2030 size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
2034 return getImpl()->props;
2037 OpenVectorType OpenVectorType::getConstType(
bool isConst) {
2040 return get(getElementType(), getNumElements(),
isConst);
2048 assert(fieldID &&
"fieldID must be at least 1");
2053 std::pair<uint64_t, uint64_t>
2057 return {index, fieldID - elementFieldID};
2060 std::pair<Type, uint64_t>
2069 return getNumElements() *
2073 std::pair<uint64_t, bool>
2078 return std::make_pair(fieldID - childRoot,
2079 fieldID >= childRoot && fieldID <= rangeEnd);
2084 OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2085 auto type = getElementType();
2087 return TypeSwitch<FIRRTLType, ElementType>(type)
2088 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2089 return type.getConstType(type.isConst() ||
isConst());
2095 OpenVectorType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2099 return emitErrorFn() <<
"vector cannot be const with references";
2108 using KeyTy = std::pair<ArrayRef<FEnumType::EnumElement>,
char>;
2114 false,
false,
false};
2115 uint64_t fieldID = 0;
2118 auto type = element.type;
2119 auto eltInfo = type.getRecursiveTypeProperties();
2120 props.isPassive &= eltInfo.isPassive;
2121 props.containsAnalog |= eltInfo.containsAnalog;
2122 props.containsConst |= eltInfo.containsConst;
2123 props.containsReference |= eltInfo.containsReference;
2124 props.containsTypeAlias |= eltInfo.containsTypeAlias;
2125 props.hasUninferredReset |= eltInfo.hasUninferredReset;
2126 props.hasUninferredWidth |= eltInfo.hasUninferredWidth;
2141 return llvm::hash_combine(
2142 llvm::hash_combine_range(key.first.begin(), key.first.end()),
2161 ArrayRef<EnumElement> elements,
bool isConst) {
2165 ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2166 return getImpl()->elements;
2169 FEnumType FEnumType::getConstType(
bool isConst) {
2170 return get(getContext(), getElements(),
isConst);
2173 FEnumType FEnumType::getAllConstDroppedType() {
2177 SmallVector<EnumElement> constDroppedElements(
2178 llvm::map_range(getElements(), [](EnumElement element) {
2179 element.type = element.type.getAllConstDroppedType();
2182 return get(getContext(), constDroppedElements,
false);
2187 return getImpl()->recProps;
2190 std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2191 for (
const auto &it : llvm::enumerate(getElements())) {
2192 auto element = it.value();
2193 if (element.name == name) {
2194 return unsigned(it.index());
2197 return std::nullopt;
2200 std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2201 for (
const auto &it : llvm::enumerate(getElements())) {
2202 auto element = it.value();
2203 if (element.name.getValue() == name) {
2204 return unsigned(it.index());
2207 return std::nullopt;
2210 StringAttr FEnumType::getElementNameAttr(
size_t index) {
2211 assert(index < getNumElements() &&
2212 "index must be less than number of fields in enum");
2213 return getElements()[index].name;
2216 StringRef FEnumType::getElementName(
size_t index) {
2217 return getElementNameAttr(index).getValue();
2220 std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2221 if (
auto maybeIndex = getElementIndex(name))
2222 return getElements()[*maybeIndex];
2223 return std::nullopt;
2226 std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2227 if (
auto maybeIndex = getElementIndex(name))
2228 return getElements()[*maybeIndex];
2229 return std::nullopt;
2233 FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2234 assert(index < getNumElements() &&
2235 "index must be less than number of fields in enum");
2236 return getElements()[index];
2240 auto element = getElement(name);
2245 auto element = getElement(name);
2250 assert(index < getNumElements() &&
2251 "index must be less than number of fields in enum");
2252 return getElements()[index].type;
2255 FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2256 auto type = getElementType(index);
2257 return type.getConstType(type.isConst() ||
isConst());
2261 return getImpl()->fieldIDs[index];
2265 assert(!getElements().
empty() &&
"Enum must have >0 fields");
2266 auto fieldIDs = getImpl()->fieldIDs;
2267 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2268 return std::distance(fieldIDs.begin(), it);
2271 std::pair<uint64_t, uint64_t>
2275 return {index, fieldID - elementFieldID};
2278 std::pair<Type, uint64_t>
2283 auto subfieldType = getElementType(subfieldIndex);
2284 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2285 return {subfieldType, subfieldID};
2290 std::pair<uint64_t, bool>
2293 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2295 return std::make_pair(fieldID - childRoot,
2296 fieldID >= childRoot && fieldID <= rangeEnd);
2299 auto FEnumType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2300 ArrayRef<EnumElement> elements,
bool isConst)
2302 for (
auto &elt : elements) {
2303 auto r = elt.type.getRecursiveTypeProperties();
2305 return emitErrorFn() <<
"enum field '" << elt.name <<
"' not passive";
2306 if (r.containsAnalog)
2307 return emitErrorFn() <<
"enum field '" << elt.name <<
"' contains analog";
2308 if (r.containsConst && !
isConst)
2309 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2317 auto *impl = getImpl();
2319 if (impl->anonymousType)
2320 return impl->anonymousType;
2322 if (!impl->recProps.containsTypeAlias)
2323 return impl->anonymousType = *
this;
2325 SmallVector<FEnumType::EnumElement, 4> elements;
2327 for (
auto element : getElements())
2328 elements.push_back({element.name, element.type.getAnonymousType()});
2329 return impl->anonymousType =
FEnumType::get(getContext(), elements);
2338 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2349 return llvm::hash_combine(key);
2363 -> BaseTypeAliasType {
2368 return getImpl()->name;
2372 return getImpl()->innerType;
2376 auto *impl = getImpl();
2377 if (impl->anonymousType)
2378 return impl->anonymousType;
2379 return impl->anonymousType = getInnerType().getAnonymousType();
2387 auto rtp = getInnerType().getRecursiveTypeProperties();
2395 if (newInnerType == getInnerType())
2397 return newInnerType;
2402 return getModifiedType(getInnerType().getAllConstDroppedType());
2406 return getModifiedType(getInnerType().getConstType(
isConst));
2409 std::pair<Type, uint64_t>
2418 std::pair<uint64_t, bool>
2420 uint64_t index)
const {
2432 std::pair<uint64_t, uint64_t>
2443 return Base::get(type.getContext(), type, forceable, layer);
2446 auto RefType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2449 if (!base.isPassive())
2450 return emitErrorFn() <<
"reference base type must be passive";
2451 if (forceable && base.containsConst())
2452 return emitErrorFn()
2453 <<
"forceable reference base type cannot contain const";
2458 auto rtp = getType().getRecursiveTypeProperties();
2461 rtp.isPassive =
false;
2478 LogicalResult AnalogType::verify(function_ref<InFlightDiagnostic()> emitError,
2479 int32_t widthOrSentinel,
bool isConst) {
2480 if (widthOrSentinel < -1)
2481 return emitError() <<
"invalid width";
2485 int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2487 AnalogType AnalogType::getConstType(
bool isConst) {
2490 return get(getContext(), getWidthOrSentinel(),
isConst);
2497 ClockType ClockType::getConstType(
bool isConst) {
2507 ResetType ResetType::getConstType(
bool isConst) {
2517 AsyncResetType AsyncResetType::getConstType(
bool isConst) {
2528 using KeyTy = std::pair<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2532 auto name = key.first;
2533 auto elements = allocator.copyInto(key.second);
2536 SmallVector<uint64_t, 4> ids;
2545 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2568 ArrayRef<ClassElement> elements) {
2569 return get(name.getContext(), name, elements);
2573 return getNameAttr().getAttr().getValue();
2576 FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2578 ArrayRef<ClassElement> ClassType::getElements()
const {
2579 return getImpl()->elements;
2582 const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2583 return getElement(index.getValue().getZExtValue());
2586 const ClassElement &ClassType::getElement(
size_t index)
const {
2587 return getElements()[index];
2590 std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2591 for (
const auto [i, e] : llvm::enumerate(getElements()))
2592 if (fieldName == e.name)
2597 void ClassType::printInterface(AsmPrinter &p)
const {
2601 for (
const auto &element : getElements()) {
2605 p.printKeywordOrString(element.name);
2606 p <<
": " << element.type;
2613 return getImpl()->fieldIDs[index];
2617 assert(!getElements().
empty() &&
"Class must have >0 fields");
2618 auto fieldIDs = getImpl()->fieldIDs;
2619 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2620 return std::distance(fieldIDs.begin(), it);
2623 std::pair<uint64_t, uint64_t>
2627 return {index, fieldID - elementFieldID};
2630 std::pair<Type, uint64_t>
2635 auto subfieldType = getElement(subfieldIndex).type;
2636 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2637 return {subfieldType, subfieldID};
2642 std::pair<uint64_t, bool>
2645 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2647 return std::make_pair(fieldID - childRoot,
2648 fieldID >= childRoot && fieldID <= rangeEnd);
2651 ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2652 StringAttr className;
2653 if (parser.parseSymbolName(className))
2656 SmallVector<ClassElement> elements;
2657 if (parser.parseCommaSeparatedList(
2658 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
2660 Direction direction;
2661 if (succeeded(parser.parseOptionalKeyword(
"out")))
2662 direction = Direction::Out;
2663 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2664 direction = Direction::In;
2669 std::string keyword;
2670 if (parser.parseKeywordOrString(&keyword))
2672 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2676 if (parser.parseColonType(type))
2679 elements.emplace_back(name, type, direction);
2692 void FIRRTLDialect::registerTypes() {
2694 #define GET_TYPEDEF_LIST
2695 #include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
2709 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
2710 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
2712 for (
auto &elt : bundle) {
2713 if (elt.isFlip && !ignoreFlip)
2714 return std::nullopt;
2717 return std::nullopt;
2722 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
2724 for (
auto &elt : fenum) {
2727 return std::nullopt;
2730 return width + llvm::Log2_32_Ceil(fenum.getNumElements());
2732 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
2735 return std::nullopt;
2736 return *w * vector.getNumElements();
2739 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
2740 .Default([&](
auto t) {
return std::nullopt; });
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
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.
@ 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 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.
static ParseResult parseFIRRTLType(FIRRTLType &result, StringRef name, AsmParser &parser)
Parse a FIRRTLType with a name that has already been parsed.
static unsigned getIndexForFieldID(BundleType type, unsigned fieldID)
static unsigned getMaxFieldID(FIRRTLBaseType type)
static InstancePath empty
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...
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
FIRRTLBaseType getConstType(bool isConst)
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getWidthlessType()
Return this type with widths of all ground types removed.
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.
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
RecursiveTypeProperties getRecursiveTypeProperties() const
Return the recursive properties of the type, containing the isPassive, containsAnalog,...
This is the common base class between SIntType and UIntType.
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.
IntType getConstType(bool isConst)
Return a 'const' or non-'const' version of this type.
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....
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
uint64_t getWidth(Type t)
mlir::Type innerType(mlir::Type type)
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.
bool areTypesWeaklyEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destFlip=false, bool srcFlip=false, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false)
Returns true if two types are weakly 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.
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 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.
A collection of bits indicating the recursive properties of a type.
bool containsReference
Whether the type contains a reference type.
bool isPassive
Whether the type only contains passive elements.
bool containsAnalog
Whether the type contains an analog type.
bool hasUninferredReset
Whether the type has any uninferred reset.
bool containsTypeAlias
Whether the type contains a type alias.
bool containsConst
Whether the type contains a const type.
bool hasUninferredWidth
Whether the type has any uninferred bit widths.
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
SmallVector< BundleType::BundleElement, 4 > elements
static BundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
std::pair< ArrayRef< BundleType::BundleElement >, char > KeyTy
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::pair< FlatSymbolRefAttr, ArrayRef< ClassElement > > KeyTy
bool operator==(const KeyTy &key) const
static ClassTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
ArrayRef< uint64_t > fieldIDs
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
FEnumTypeStorage(ArrayRef< FEnumType::EnumElement > elements, bool isConst)
std::pair< ArrayRef< FEnumType::EnumElement >, char > KeyTy
RecursiveTypeProperties recProps
FIRRTLBaseType anonymousType
static FEnumTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
SmallVector< uint64_t, 4 > fieldIDs
static FIRRTLBaseTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
bool operator==(const KeyTy &key) const
FIRRTLBaseTypeStorage(bool isConst)
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
FIRRTLBaseType anonymousType
static FVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
std::tuple< FIRRTLBaseType, size_t, char > KeyTy
FVectorTypeStorage(FIRRTLBaseType elementType, size_t numElements, bool isConst)
SmallVector< OpenBundleType::BundleElement, 4 > elements
static OpenBundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
bool operator==(const KeyTy &key) const
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::pair< ArrayRef< OpenBundleType::BundleElement >, char > KeyTy
std::tuple< FIRRTLType, size_t, char > KeyTy
bool operator==(const KeyTy &key) const
RecursiveTypeProperties props
OpenVectorTypeStorage(FIRRTLType elementType, size_t numElements, bool isConst)
static OpenVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
WidthTypeStorage(int32_t width, bool isConst)
static WidthTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)
bool operator==(const KeyTy &key) const
std::pair< int32_t, char > KeyTy