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"
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) {
71 if (firrtl::type_isa<OpenBundleType>(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)
86 printNestedType(element.type, os);
90 .Case<FEnumType>([&](auto fenumType) {
92 llvm::interleaveComma(fenumType, os,
93 [&](FEnumType::EnumElement element) {
94 os << element.name.getValue();
96 printNestedType(element.type, os);
100 .Case<FVectorType, OpenVectorType>([&](auto vectorType) {
101 if (firrtl::type_isa<OpenVectorType>(vectorType))
104 printNestedType(vectorType.getElementType(), os);
105 os << ", " << vectorType.getNumElements() << '>
';
107 .Case<RefType>([&](RefType refType) {
108 if (refType.getForceable())
111 printNestedType(refType.getType(), os);
112 if (auto layer = refType.getLayer())
116 .Case<LHSType>([&](LHSType lhstype) {
118 printNestedType(lhstype.getType(), os);
121 .Case<StringType>([&](auto stringType) { os << "string"; })
122 .Case<FIntegerType>([&](auto integerType) { os << "integer"; })
123 .Case<BoolType>([&](auto boolType) { os << "bool"; })
124 .Case<DoubleType>([&](auto doubleType) { os << "double"; })
125 .Case<ListType>([&](auto listType) {
127 printNestedType(listType.getElementType(), os);
130 .Case<PathType>([&](auto pathType) { os << "path"; })
131 .Case<BaseTypeAliasType>([&](BaseTypeAliasType alias) {
132 os << "alias<" << alias.getName().getValue() << ", ";
133 printNestedType(alias.getInnerType(), os);
136 .Case<ClassType>([&](ClassType type) {
138 type.printInterface(os);
141 .Case<AnyRefType>([&](AnyRefType type) { os << "anyref"; })
142 .Default([&](auto) { anyFailed = true; });
143 return failure(anyFailed);
145 // NOLINTEND(misc-no-recursion)
148 void circt::firrtl::printNestedType(Type type, AsmPrinter &os) {
149 // Try the custom type printer.
150 if (succeeded(customTypePrinter(type, os)))
153 // None of the above recognized the type, so we bail.
154 assert(false && "type to print unknown to FIRRTL dialect");
157 //===----------------------------------------------------------------------===//
159 //===----------------------------------------------------------------------===//
186 static OptionalParseResult customTypeParser(AsmParser &parser, StringRef name,
188 bool isConst = false;
189 const char constPrefix[] = "const.";
190 if (name.starts_with(constPrefix)) {
192 name = name.drop_front(std::size(constPrefix) - 1);
195 auto *context = parser.getContext();
197 return result = ClockType::get(context, isConst), success();
199 return result = ResetType::get(context, isConst), success();
200 if (name == "asyncreset")
201 return result = AsyncResetType::get(context, isConst), success();
203 if (name == "sint" || name == "uint" || name == "analog") {
204 // Parse the width specifier if it exists.
206 if (!parser.parseOptionalLess()) {
207 if (parser.parseInteger(width) || parser.parseGreater())
211 return parser.emitError(parser.getNameLoc(), "unknown width"),
216 result = SIntType::get(context, width, isConst);
217 else if (name == "uint")
218 result = UIntType::get(context, width, isConst);
220 assert(name == "analog");
221 result = AnalogType::get(context, width, isConst);
226 if (name == "bundle") {
227 SmallVector<BundleType::BundleElement, 4> elements;
229 auto parseBundleElement = [&]() -> ParseResult {
234 if (failed(parser.parseKeywordOrString(&nameStr)))
238 bool isFlip = succeeded(parser.parseOptionalKeyword("flip"));
239 if (parser.parseColon() || parseNestedBaseType(type, parser))
242 elements.push_back({StringAttr::get(context, name), isFlip, type});
246 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
250 return result = BundleType::get(context, elements, isConst), success();
252 if (name == "openbundle") {
253 SmallVector<OpenBundleType::BundleElement, 4> elements;
255 auto parseBundleElement = [&]() -> ParseResult {
260 if (failed(parser.parseKeywordOrString(&nameStr)))
264 bool isFlip = succeeded(parser.parseOptionalKeyword("flip"));
265 if (parser.parseColon() || parseNestedType(type, parser))
268 elements.push_back({StringAttr::get(context, name), isFlip, type});
272 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
276 result = parser.getChecked<OpenBundleType>(context, elements, isConst);
277 return failure(!result);
280 if (name == "enum") {
281 SmallVector<FEnumType::EnumElement, 4> elements;
283 auto parseEnumElement = [&]() -> ParseResult {
288 if (failed(parser.parseKeywordOrString(&nameStr)))
292 if (parser.parseColon() || parseNestedBaseType(type, parser))
295 elements.push_back({StringAttr::get(context, name), type});
299 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
302 if (failed(FEnumType::verify(
303 [&]() { return parser.emitError(parser.getNameLoc()); }, elements,
307 return result = FEnumType::get(context, elements, isConst), success();
310 if (name == "vector") {
311 FIRRTLBaseType elementType;
314 if (parser.parseLess() || parseNestedBaseType(elementType, parser) ||
315 parser.parseComma() || parser.parseInteger(width) ||
316 parser.parseGreater())
319 return result = FVectorType::get(elementType, width, isConst), success();
321 if (name == "openvector") {
322 FIRRTLType elementType;
325 if (parser.parseLess() || parseNestedType(elementType, parser) ||
326 parser.parseComma() || parser.parseInteger(width) ||
327 parser.parseGreater())
331 parser.getChecked<OpenVectorType>(context, elementType, width, isConst);
332 return failure(!result);
335 // For now, support both firrtl.ref and firrtl.probe.
336 if (name == "ref" || name == "probe") {
343 if (parser.parseOptionalComma().succeeded())
344 if (parser.parseOptionalAttribute(layer).value())
345 return parser.emitError(parser.getNameLoc(),
346 "expected symbol reference");
347 if (parser.parseGreater())
351 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
355 return result =
RefType::get(type,
false, layer), success();
360 parser.parseGreater())
362 if (!isa<FIRRTLBaseType>(type))
363 return parser.emitError(parser.getNameLoc(),
"expected base type");
364 result = parser.getChecked<LHSType>(context, cast<FIRRTLBaseType>(type));
365 return failure(!result);
367 if (name ==
"rwprobe") {
372 if (parser.parseOptionalComma().succeeded())
373 if (parser.parseOptionalAttribute(layer).value())
374 return parser.emitError(parser.getNameLoc(),
375 "expected symbol reference");
376 if (parser.parseGreater())
380 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
true,
384 return result =
RefType::get(type,
true, layer), success();
386 if (name ==
"class") {
388 return parser.emitError(parser.getNameLoc(),
"classes cannot be const");
390 if (parser.parseLess() || ClassType::parseInterface(parser, classType) ||
391 parser.parseGreater())
396 if (name ==
"anyref") {
398 return parser.emitError(parser.getNameLoc(),
"any refs cannot be const");
403 if (name ==
"string") {
405 parser.emitError(parser.getNameLoc(),
"strings cannot be const");
411 if (name ==
"integer") {
413 parser.emitError(parser.getNameLoc(),
"bigints cannot be const");
419 if (name ==
"bool") {
421 parser.emitError(parser.getNameLoc(),
"bools cannot be const");
427 if (name ==
"double") {
429 parser.emitError(parser.getNameLoc(),
"doubles cannot be const");
435 if (name ==
"list") {
437 parser.emitError(parser.getNameLoc(),
"lists cannot be const");
442 parser.parseGreater())
444 result = parser.getChecked<ListType>(context,
elementType);
449 if (name ==
"path") {
451 parser.emitError(parser.getNameLoc(),
"path cannot be const");
457 if (name ==
"alias") {
460 if (parser.parseLess() || parser.parseKeyword(&name) ||
462 parser.parseGreater())
478 static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
481 if (parseResult.has_value())
482 return parseResult.value();
485 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL dialect type: \"")
497 if (failed(
parseType(type, name, parser)))
499 result = type_dyn_cast<FIRRTLType>(type);
502 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL type: \"")
512 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type)) {
516 parser.emitError(parser.getNameLoc(),
"expected base type, found ") << type;
525 if (
auto prop = type_dyn_cast<PropertyType>(type)) {
529 parser.emitError(parser.getNameLoc(),
"expected property type, found ")
542 if (parser.parseKeyword(&name))
552 if (parser.parseKeyword(&name))
562 if (parser.parseKeyword(&name))
573 void FIRRTLDialect::printType(Type type, DialectAsmPrinter &os)
const {
581 if (parser.parseKeyword(&name) || ::
parseType(result, name, parser))
625 return TypeSwitch<FIRRTLType, bool>(*
this)
626 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
627 AnalogType>([](Type) {
return true; })
628 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType>(
629 [](Type) {
return false; })
630 .Case<BaseTypeAliasType>([](BaseTypeAliasType alias) {
631 return alias.getAnonymousType().isGround();
634 .Case<PropertyType, RefType>([](Type) {
return false; })
636 llvm_unreachable(
"unknown FIRRTL type");
642 return TypeSwitch<FIRRTLType, bool>(*
this)
644 [](
auto type) {
return type.
isConst(); })
651 return TypeSwitch<FIRRTLType, RecursiveTypeProperties>(*
this)
652 .Case<ClockType, ResetType, AsyncResetType>([](
FIRRTLBaseType type) {
659 firrtl::type_isa<ResetType>(type)};
661 .Case<SIntType, UIntType>([](
auto type) {
663 true,
false,
false, type.
isConst(),
false, !type.hasWidth(),
false};
665 .Case<AnalogType>([](
auto type) {
667 true,
false,
true, type.
isConst(),
false, !type.hasWidth(),
false};
669 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType,
670 RefType, BaseTypeAliasType>(
671 [](
auto type) {
return type.getRecursiveTypeProperties(); })
672 .Case<PropertyType>([](
auto type) {
674 false,
false,
false};
677 [](
auto type) {
return type.getType().getRecursiveTypeProperties(); })
679 llvm_unreachable(
"unknown FIRRTL type");
686 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
687 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
688 AnalogType>([&](Type) {
return *
this; })
689 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
692 llvm_unreachable(
"unknown FIRRTL type");
699 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
700 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
701 AnalogType, FEnumType>([&](Type) {
return *
this; })
702 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
705 llvm_unreachable(
"unknown FIRRTL type");
712 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
713 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
714 UIntType, BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
717 llvm_unreachable(
"unknown FIRRTL type");
724 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
725 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
726 UIntType>([&](
auto type) {
return type.
getConstType(
false); })
727 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
730 llvm_unreachable(
"unknown FIRRTL type");
738 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
739 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
740 AnalogType>([&](Type) {
743 .Case<BundleType>([&](BundleType bundleType) {
744 SmallVector<BundleType::BundleElement, 4> newElements;
745 newElements.reserve(bundleType.getElements().size());
746 for (
auto elt : bundleType)
747 newElements.push_back(
748 {elt.name,
false , elt.type.getMaskType()});
750 bundleType.isConst());
752 .Case<FVectorType>([](FVectorType vectorType) {
754 vectorType.getNumElements(),
755 vectorType.isConst());
757 .Case<BaseTypeAliasType>([](BaseTypeAliasType base) {
758 return base.getModifiedType(base.getInnerType().getMaskType());
761 llvm_unreachable(
"unknown FIRRTL type");
769 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
770 .Case<ClockType, ResetType, AsyncResetType>([](
auto a) {
return a; })
771 .Case<UIntType, SIntType, AnalogType>(
772 [&](
auto a) {
return a.get(this->getContext(), -1, a.isConst()); })
773 .Case<BundleType>([&](
auto a) {
774 SmallVector<BundleType::BundleElement, 4> newElements;
775 newElements.reserve(a.getElements().size());
777 newElements.push_back(
778 {elt.name, elt.isFlip, elt.type.getWidthlessType()});
781 .Case<FVectorType>([](
auto a) {
783 a.getNumElements(), a.isConst());
785 .Case<FEnumType>([&](FEnumType a) {
786 SmallVector<FEnumType::EnumElement, 4> newElements;
787 newElements.reserve(a.getNumElements());
789 newElements.push_back({elt.name, elt.type.getWidthlessType()});
790 return FEnumType::get(this->getContext(), newElements, a.isConst());
792 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
793 return type.getModifiedType(type.getInnerType().getWidthlessType());
796 llvm_unreachable(
"unknown FIRRTL type");
806 return TypeSwitch<FIRRTLBaseType, int32_t>(*
this)
807 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
808 .Case<SIntType, UIntType>(
811 [](AnalogType analogType) {
return analogType.getWidthOrSentinel(); })
812 .Case<BundleType, FVectorType, FEnumType>([](Type) {
return -2; })
813 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
815 return type.getAnonymousType().getBitWidthOrSentinel();
818 llvm_unreachable(
"unknown FIRRTL type");
827 return TypeSwitch<FIRRTLType, bool>(*
this)
828 .Case<ResetType, AsyncResetType>([](Type) {
return true; })
830 [](UIntType a) {
return !a.hasWidth() || a.getWidth() == 1; })
831 .Case<BaseTypeAliasType>(
832 [](
auto type) {
return type.getInnerType().
isResetType(); })
833 .Default([](Type) {
return false; });
837 return TypeSwitch<Type, bool>(type)
839 [](
auto base) {
return base.isConst(); })
844 return TypeSwitch<Type, bool>(type)
846 [](
auto base) {
return base.containsConst(); })
853 .
Case<BundleType>([&](
auto bundle) {
854 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
855 auto elt = bundle.getElement(i);
859 return bundle.getNumElements() == 0;
861 .Case<FVectorType>([&](
auto vector) {
862 if (vector.getNumElements() == 0)
866 .Case<FIRRTLBaseType>([](
auto groundType) {
869 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
870 .Default([](
auto) {
return false; });
880 BundleType::BundleElement srcElement,
881 bool destOuterTypeIsConst,
882 bool srcOuterTypeIsConst,
883 bool requiresSameWidth) {
884 if (destElement.name != srcElement.name)
886 if (destElement.isFlip != srcElement.isFlip)
889 if (destElement.isFlip) {
890 std::swap(destElement, srcElement);
891 std::swap(destOuterTypeIsConst, srcOuterTypeIsConst);
895 destOuterTypeIsConst, srcOuterTypeIsConst,
904 bool destOuterTypeIsConst,
905 bool srcOuterTypeIsConst,
906 bool requireSameWidths) {
907 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
908 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
911 if (!destType || !srcType)
912 return destFType == srcFType;
914 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
915 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
918 auto destVectorType = type_dyn_cast<FVectorType>(destType);
919 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
920 if (destVectorType && srcVectorType)
921 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
923 srcVectorType.getElementType(), destIsConst,
924 srcIsConst, requireSameWidths);
928 auto destBundleType = type_dyn_cast<BundleType>(destType);
929 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
930 if (destBundleType && srcBundleType) {
931 auto destElements = destBundleType.getElements();
932 auto srcElements = srcBundleType.getElements();
933 size_t numDestElements = destElements.size();
934 if (numDestElements != srcElements.size())
937 for (
size_t i = 0; i < numDestElements; ++i) {
938 auto destElement = destElements[i];
939 auto srcElement = srcElements[i];
941 srcIsConst, requireSameWidths))
949 auto dstEnumType = type_dyn_cast<FEnumType>(destType);
950 auto srcEnumType = type_dyn_cast<FEnumType>(srcType);
952 if (dstEnumType && srcEnumType) {
953 if (dstEnumType.getNumElements() != srcEnumType.getNumElements())
956 for (
const auto &[dst, src] : llvm::zip(dstEnumType, srcEnumType)) {
958 if (dst.name != src.name)
970 if (destIsConst && !srcIsConst)
974 if (firrtl::type_isa<ResetType>(destType))
975 return srcType.isResetType();
978 if (firrtl::type_isa<ResetType>(srcType))
979 return destType.isResetType();
983 if (!requireSameWidths || destType.getBitWidthOrSentinel() == -1)
984 srcType = srcType.getWidthlessType();
985 if (!requireSameWidths || srcType.getBitWidthOrSentinel() == -1)
986 destType = destType.getWidthlessType();
989 return destType.getConstType(
false) == srcType.getConstType(
false);
994 bool srcOuterTypeIsConst) {
996 if (destFType == srcFType)
999 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
1000 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
1003 if (!destType || !srcType)
1007 if (!destType.isPassive() || !srcType.isPassive())
1010 bool srcIsConst = srcType.isConst() || srcOuterTypeIsConst;
1013 if (destType.isConst() && !srcIsConst)
1018 auto destVectorType = type_dyn_cast<FVectorType>(destType);
1019 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
1020 if (destVectorType && srcVectorType)
1021 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1023 srcVectorType.getElementType(), srcIsConst);
1024 if (destVectorType != srcVectorType)
1029 auto destBundleType = type_dyn_cast<BundleType>(destType);
1030 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1031 if (destBundleType && srcBundleType) {
1032 auto destElements = destBundleType.getElements();
1033 auto srcElements = srcBundleType.getElements();
1034 size_t numDestElements = destElements.size();
1035 if (numDestElements != srcElements.size())
1038 return llvm::all_of_zip(
1039 destElements, srcElements,
1040 [&](
const auto &destElement,
const auto &srcElement) {
1041 return destElement.name == srcElement.name &&
1046 if (destBundleType != srcBundleType)
1051 return destType == srcType.getConstType(destType.isConst());
1055 auto dstRefType = type_dyn_cast<RefType>(dstType);
1056 auto srcRefType = type_dyn_cast<RefType>(srcType);
1057 if (!dstRefType || !srcRefType)
1059 if (dstRefType == srcRefType)
1061 if (dstRefType.getForceable() && !srcRefType.getForceable())
1073 bool srcOuterTypeIsConst) ->
bool {
1079 assert(dest.isPassive() && src.isPassive());
1081 bool srcIsConst = src.isConst() || srcOuterTypeIsConst;
1084 if (dest.isConst() && !srcIsConst)
1090 if (
auto destVectorType = type_dyn_cast<FVectorType>(dest)) {
1091 auto srcVectorType = type_dyn_cast<FVectorType>(src);
1092 return srcVectorType &&
1093 destVectorType.getNumElements() ==
1094 srcVectorType.getNumElements() &&
1095 f(f, destVectorType.getElementType(),
1096 srcVectorType.getElementType(), srcIsConst);
1099 if (
auto destBundleType = type_dyn_cast<BundleType>(dest)) {
1100 auto srcBundleType = type_dyn_cast<BundleType>(src);
1104 auto destElements = destBundleType.getElements();
1105 auto srcElements = srcBundleType.getElements();
1107 return destElements.size() == srcElements.size() &&
1109 destElements, srcElements,
1110 [&](
const auto &destElement,
const auto &srcElement) {
1111 return destElement.name == srcElement.name &&
1112 f(f, destElement.type, srcElement.type, srcIsConst);
1116 if (
auto destEnumType = type_dyn_cast<FEnumType>(dest)) {
1117 auto srcEnumType = type_dyn_cast<FEnumType>(src);
1120 auto destElements = destEnumType.getElements();
1121 auto srcElements = srcEnumType.getElements();
1123 return destElements.size() == srcElements.size() &&
1125 destElements, srcElements,
1126 [&](
const auto &destElement,
const auto &srcElement) {
1127 return destElement.name == srcElement.name &&
1128 f(f, destElement.type, srcElement.type, srcIsConst);
1133 if (type_isa<ResetType>(dest))
1134 return src.isResetType();
1138 src = src.getConstType(dest.isConst());
1141 if (dest.getBitWidthOrSentinel() == -1)
1142 src = src.getWidthlessType();
1147 return recurse(recurse, dstRefType.getType(), srcRefType.getType(),
false);
1154 return TypeSwitch<FIRRTLBaseType, bool>(dstType)
1155 .Case<BundleType>([&](
auto dstBundle) {
1156 auto srcBundle = type_cast<BundleType>(srcType);
1157 for (
size_t i = 0, n = dstBundle.getNumElements(); i < n; ++i) {
1158 auto srcElem = srcBundle.getElement(i);
1159 auto dstElem = dstBundle.getElement(i);
1160 if (dstElem.isFlip) {
1170 .Case<FVectorType>([&](
auto vector) {
1172 type_cast<FVectorType>(srcType).getElementType());
1174 .Default([&](
auto dstGround) {
1177 return destWidth <= -1 || srcWidth <= -1 || destWidth >= srcWidth;
1188 if (
auto destBaseType = type_dyn_cast<FIRRTLBaseType>(lhs))
1189 if (
auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(rhs))
1192 if (
auto destRefType = type_dyn_cast<RefType>(lhs))
1193 if (
auto srcRefType = type_dyn_cast<RefType>(rhs))
1195 srcRefType.getType());
1203 return type_cast<FIRRTLBaseType>(anyBaseFIRRTLType).getPassiveType();
1207 return llvm::TypeSwitch<Type, bool>(type)
1209 return !type.containsReference() &&
1210 (!type.isPassive() || type.containsAnalog());
1222 int32_t widthOrSentinel,
bool isConst) {
1229 if (
auto sintType = type_dyn_cast<SIntType>(*
this))
1230 return sintType.getWidthOrSentinel();
1231 if (
auto uintType = type_dyn_cast<UIntType>(*
this))
1232 return uintType.getWidthOrSentinel();
1260 if (
auto sIntType = type_dyn_cast<SIntType>(*
this))
1269 SIntType
SIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1276 LogicalResult
SIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1277 int32_t widthOrSentinel,
bool isConst) {
1278 if (widthOrSentinel < -1)
1279 return emitError() <<
"invalid width";
1283 int32_t SIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1285 SIntType SIntType::getConstType(
bool isConst) {
1288 return get(getContext(), getWidthOrSentinel(),
isConst);
1302 LogicalResult
UIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1303 int32_t widthOrSentinel,
bool isConst) {
1304 if (widthOrSentinel < -1)
1305 return emitError() <<
"invalid width";
1309 int32_t UIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1311 UIntType UIntType::getConstType(
bool isConst) {
1314 return get(getContext(), getWidthOrSentinel(),
isConst);
1323 using KeyTy = std::pair<ArrayRef<BundleType::BundleElement>,
char>;
1330 uint64_t fieldID = 0;
1333 auto type = element.type;
1334 auto eltInfo = type.getRecursiveTypeProperties();
1356 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1378 ArrayRef<BundleElement> elements,
bool isConst) {
1382 auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1383 return getImpl()->elements;
1388 return getImpl()->props;
1393 auto *impl = getImpl();
1396 if (impl->passiveType)
1397 return impl->passiveType;
1400 if (impl->props.isPassive) {
1401 impl->passiveType = *
this;
1406 SmallVector<BundleType::BundleElement, 16> newElements;
1407 newElements.reserve(impl->elements.size());
1408 for (
auto &elt : impl->elements) {
1409 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1413 impl->passiveType = passiveType;
1417 BundleType BundleType::getConstType(
bool isConst) {
1420 return get(getContext(), getElements(),
isConst);
1423 BundleType BundleType::getAllConstDroppedType() {
1427 SmallVector<BundleElement> constDroppedElements(
1428 llvm::map_range(getElements(), [](BundleElement element) {
1429 element.type = element.type.getAllConstDroppedType();
1432 return get(getContext(), constDroppedElements,
false);
1435 std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1436 for (
const auto &it : llvm::enumerate(getElements())) {
1437 auto element = it.value();
1438 if (element.name == name) {
1439 return unsigned(it.index());
1442 return std::nullopt;
1445 std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1446 for (
const auto &it : llvm::enumerate(getElements())) {
1447 auto element = it.value();
1448 if (element.name.getValue() == name) {
1449 return unsigned(it.index());
1452 return std::nullopt;
1455 StringAttr BundleType::getElementNameAttr(
size_t index) {
1456 assert(index < getNumElements() &&
1457 "index must be less than number of fields in bundle");
1458 return getElements()[index].name;
1461 StringRef BundleType::getElementName(
size_t index) {
1462 return getElementNameAttr(index).getValue();
1465 std::optional<BundleType::BundleElement>
1466 BundleType::getElement(StringAttr name) {
1467 if (
auto maybeIndex = getElementIndex(name))
1468 return getElements()[*maybeIndex];
1469 return std::nullopt;
1472 std::optional<BundleType::BundleElement>
1473 BundleType::getElement(StringRef name) {
1474 if (
auto maybeIndex = getElementIndex(name))
1475 return getElements()[*maybeIndex];
1476 return std::nullopt;
1480 BundleType::BundleElement BundleType::getElement(
size_t index) {
1481 assert(index < getNumElements() &&
1482 "index must be less than number of fields in bundle");
1483 return getElements()[index];
1487 auto element = getElement(name);
1492 auto element = getElement(name);
1497 assert(index < getNumElements() &&
1498 "index must be less than number of fields in bundle");
1499 return getElements()[index].type;
1503 return getImpl()->fieldIDs[index];
1507 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1508 auto fieldIDs = getImpl()->fieldIDs;
1509 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1510 return std::distance(fieldIDs.begin(), it);
1513 std::pair<uint64_t, uint64_t>
1517 return {index, fieldID - elementFieldID};
1520 std::pair<Type, uint64_t>
1525 auto subfieldType = getElementType(subfieldIndex);
1526 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1527 return {subfieldType, subfieldID};
1532 std::pair<uint64_t, bool>
1535 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1537 return std::make_pair(fieldID - childRoot,
1538 fieldID >= childRoot && fieldID <= rangeEnd);
1543 BundleType::ElementType
1544 BundleType::getElementTypePreservingConst(
size_t index) {
1545 auto type = getElementType(index);
1546 return type.getConstType(type.isConst() ||
isConst());
1551 auto *impl = getImpl();
1554 if (impl->anonymousType)
1555 return impl->anonymousType;
1558 if (!impl->props.containsTypeAlias) {
1559 impl->anonymousType = *
this;
1565 SmallVector<BundleType::BundleElement, 16> newElements;
1566 newElements.reserve(impl->elements.size());
1567 for (
auto &elt : impl->elements)
1568 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1571 impl->anonymousType = anonymousType;
1572 return anonymousType;
1580 using KeyTy = std::pair<ArrayRef<OpenBundleType::BundleElement>,
char>;
1588 uint64_t fieldID = 0;
1591 auto type = element.type;
1592 auto eltInfo = type.getRecursiveTypeProperties();
1613 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1625 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1638 ArrayRef<BundleElement> elements,
1643 auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1644 return getImpl()->elements;
1649 return getImpl()->props;
1652 OpenBundleType OpenBundleType::getConstType(
bool isConst) {
1655 return get(getContext(), getElements(),
isConst);
1658 std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1659 for (
const auto &it : llvm::enumerate(getElements())) {
1660 auto element = it.value();
1661 if (element.name == name) {
1662 return unsigned(it.index());
1665 return std::nullopt;
1668 std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1669 for (
const auto &it : llvm::enumerate(getElements())) {
1670 auto element = it.value();
1671 if (element.name.getValue() == name) {
1672 return unsigned(it.index());
1675 return std::nullopt;
1678 StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1679 assert(index < getNumElements() &&
1680 "index must be less than number of fields in bundle");
1681 return getElements()[index].name;
1684 StringRef OpenBundleType::getElementName(
size_t index) {
1685 return getElementNameAttr(index).getValue();
1688 std::optional<OpenBundleType::BundleElement>
1689 OpenBundleType::getElement(StringAttr name) {
1690 if (
auto maybeIndex = getElementIndex(name))
1691 return getElements()[*maybeIndex];
1692 return std::nullopt;
1695 std::optional<OpenBundleType::BundleElement>
1696 OpenBundleType::getElement(StringRef name) {
1697 if (
auto maybeIndex = getElementIndex(name))
1698 return getElements()[*maybeIndex];
1699 return std::nullopt;
1703 OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1704 assert(index < getNumElements() &&
1705 "index must be less than number of fields in bundle");
1706 return getElements()[index];
1709 OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1710 auto element = getElement(name);
1714 OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1715 auto element = getElement(name);
1719 OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1720 assert(index < getNumElements() &&
1721 "index must be less than number of fields in bundle");
1722 return getElements()[index].type;
1726 return getImpl()->fieldIDs[index];
1730 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1731 auto fieldIDs = getImpl()->fieldIDs;
1732 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1733 return std::distance(fieldIDs.begin(), it);
1736 std::pair<uint64_t, uint64_t>
1740 return {index, fieldID - elementFieldID};
1743 std::pair<Type, uint64_t>
1748 auto subfieldType = getElementType(subfieldIndex);
1749 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1750 return {subfieldType, subfieldID};
1755 std::pair<uint64_t, bool>
1758 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1760 return std::make_pair(fieldID - childRoot,
1761 fieldID >= childRoot && fieldID <= rangeEnd);
1766 OpenBundleType::ElementType
1767 OpenBundleType::getElementTypePreservingConst(
size_t index) {
1768 auto type = getElementType(index);
1770 return TypeSwitch<FIRRTLType, ElementType>(type)
1771 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1772 return type.getConstType(type.isConst() ||
isConst());
1779 ArrayRef<BundleElement> elements,
bool isConst) {
1780 for (
auto &element : elements) {
1782 return emitErrorFn()
1783 <<
"'const' bundle cannot have references, but element "
1784 << element.name <<
" has type " << element.type;
1785 if (type_isa<LHSType>(element.type))
1786 return emitErrorFn() <<
"bundle element " << element.name
1787 <<
" cannot have a left-hand side type";
1799 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1817 static_cast<bool>(std::get<2>(key)));
1836 return getImpl()->elementType;
1839 size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
1843 return getImpl()->props;
1848 auto *impl = getImpl();
1851 if (impl->passiveType)
1852 return impl->passiveType;
1855 if (impl->elementType.getRecursiveTypeProperties().isPassive)
1856 return impl->passiveType = *
this;
1861 impl->passiveType = passiveType;
1865 FVectorType FVectorType::getConstType(
bool isConst) {
1868 return get(getElementType(), getNumElements(),
isConst);
1871 FVectorType FVectorType::getAllConstDroppedType() {
1874 return get(getElementType().getAllConstDroppedType(), getNumElements(),
1880 auto *impl = getImpl();
1882 if (impl->anonymousType)
1883 return impl->anonymousType;
1886 if (!impl->props.containsTypeAlias)
1887 return impl->anonymousType = *
this;
1892 impl->anonymousType = anonymousType;
1893 return anonymousType;
1901 assert(fieldID &&
"fieldID must be at least 1");
1906 std::pair<uint64_t, uint64_t>
1910 return {index, fieldID - elementFieldID};
1913 std::pair<Type, uint64_t>
1921 return getNumElements() *
1925 std::pair<uint64_t, bool>
1930 return std::make_pair(fieldID - childRoot,
1931 fieldID >= childRoot && fieldID <= rangeEnd);
1936 FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
1937 auto type = getElementType();
1938 return type.getConstType(type.isConst() ||
isConst());
1946 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
1964 static_cast<bool>(std::get<2>(key)));
1979 FIRRTLType OpenVectorType::getElementType()
const {
1980 return getImpl()->elementType;
1983 size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
1987 return getImpl()->props;
1990 OpenVectorType OpenVectorType::getConstType(
bool isConst) {
1993 return get(getElementType(), getNumElements(),
isConst);
2001 assert(fieldID &&
"fieldID must be at least 1");
2006 std::pair<uint64_t, uint64_t>
2010 return {index, fieldID - elementFieldID};
2013 std::pair<Type, uint64_t>
2022 return getNumElements() *
2026 std::pair<uint64_t, bool>
2031 return std::make_pair(fieldID - childRoot,
2032 fieldID >= childRoot && fieldID <= rangeEnd);
2037 OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2038 auto type = getElementType();
2040 return TypeSwitch<FIRRTLType, ElementType>(type)
2041 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2042 return type.getConstType(type.isConst() ||
isConst());
2052 return emitErrorFn() <<
"vector cannot be const with references";
2054 return emitErrorFn() <<
"vector cannot have a left-hand side type";
2063 using KeyTy = std::pair<ArrayRef<FEnumType::EnumElement>,
char>;
2069 false,
false,
false};
2070 uint64_t fieldID = 0;
2073 auto type = element.type;
2074 auto eltInfo = type.getRecursiveTypeProperties();
2075 props.isPassive &= eltInfo.isPassive;
2076 props.containsAnalog |= eltInfo.containsAnalog;
2077 props.containsConst |= eltInfo.containsConst;
2078 props.containsReference |= eltInfo.containsReference;
2079 props.containsTypeAlias |= eltInfo.containsTypeAlias;
2080 props.hasUninferredReset |= eltInfo.hasUninferredReset;
2081 props.hasUninferredWidth |= eltInfo.hasUninferredWidth;
2097 llvm::hash_combine_range(key.first.begin(), key.first.end()),
2116 ArrayRef<EnumElement> elements,
bool isConst) {
2120 ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2121 return getImpl()->elements;
2124 FEnumType FEnumType::getConstType(
bool isConst) {
2125 return get(getContext(), getElements(),
isConst);
2128 FEnumType FEnumType::getAllConstDroppedType() {
2132 SmallVector<EnumElement> constDroppedElements(
2133 llvm::map_range(getElements(), [](EnumElement element) {
2134 element.type = element.type.getAllConstDroppedType();
2137 return get(getContext(), constDroppedElements,
false);
2142 return getImpl()->recProps;
2145 std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2146 for (
const auto &it : llvm::enumerate(getElements())) {
2147 auto element = it.value();
2148 if (element.name == name) {
2149 return unsigned(it.index());
2152 return std::nullopt;
2155 std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2156 for (
const auto &it : llvm::enumerate(getElements())) {
2157 auto element = it.value();
2158 if (element.name.getValue() == name) {
2159 return unsigned(it.index());
2162 return std::nullopt;
2165 StringAttr FEnumType::getElementNameAttr(
size_t index) {
2166 assert(index < getNumElements() &&
2167 "index must be less than number of fields in enum");
2168 return getElements()[index].name;
2171 StringRef FEnumType::getElementName(
size_t index) {
2172 return getElementNameAttr(index).getValue();
2175 std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2176 if (
auto maybeIndex = getElementIndex(name))
2177 return getElements()[*maybeIndex];
2178 return std::nullopt;
2181 std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2182 if (
auto maybeIndex = getElementIndex(name))
2183 return getElements()[*maybeIndex];
2184 return std::nullopt;
2188 FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2189 assert(index < getNumElements() &&
2190 "index must be less than number of fields in enum");
2191 return getElements()[index];
2195 auto element = getElement(name);
2200 auto element = getElement(name);
2205 assert(index < getNumElements() &&
2206 "index must be less than number of fields in enum");
2207 return getElements()[index].type;
2210 FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2211 auto type = getElementType(index);
2212 return type.getConstType(type.isConst() ||
isConst());
2216 return getImpl()->fieldIDs[index];
2220 assert(!getElements().
empty() &&
"Enum must have >0 fields");
2221 auto fieldIDs = getImpl()->fieldIDs;
2222 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2223 return std::distance(fieldIDs.begin(), it);
2226 std::pair<uint64_t, uint64_t>
2230 return {index, fieldID - elementFieldID};
2233 std::pair<Type, uint64_t>
2238 auto subfieldType = getElementType(subfieldIndex);
2239 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2240 return {subfieldType, subfieldID};
2245 std::pair<uint64_t, bool>
2248 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2250 return std::make_pair(fieldID - childRoot,
2251 fieldID >= childRoot && fieldID <= rangeEnd);
2255 ArrayRef<EnumElement> elements,
bool isConst)
2257 for (
auto &elt : elements) {
2258 auto r = elt.type.getRecursiveTypeProperties();
2260 return emitErrorFn() <<
"enum field '" << elt.name <<
"' not passive";
2261 if (r.containsAnalog)
2262 return emitErrorFn() <<
"enum field '" << elt.name <<
"' contains analog";
2263 if (r.containsConst && !
isConst)
2264 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2272 auto *impl = getImpl();
2274 if (impl->anonymousType)
2275 return impl->anonymousType;
2277 if (!impl->recProps.containsTypeAlias)
2278 return impl->anonymousType = *
this;
2280 SmallVector<FEnumType::EnumElement, 4> elements;
2282 for (
auto element : getElements())
2283 elements.push_back({element.name, element.type.getAnonymousType()});
2284 return impl->anonymousType =
FEnumType::get(getContext(), elements);
2293 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2318 -> BaseTypeAliasType {
2323 return getImpl()->name;
2327 return getImpl()->innerType;
2331 auto *impl = getImpl();
2332 if (impl->anonymousType)
2333 return impl->anonymousType;
2334 return impl->anonymousType = getInnerType().getAnonymousType();
2342 auto rtp = getInnerType().getRecursiveTypeProperties();
2350 if (newInnerType == getInnerType())
2352 return newInnerType;
2357 return getModifiedType(getInnerType().getAllConstDroppedType());
2361 return getModifiedType(getInnerType().getConstType(
isConst));
2364 std::pair<Type, uint64_t>
2373 std::pair<uint64_t, bool>
2375 uint64_t index)
const {
2387 std::pair<uint64_t, uint64_t>
2400 LogicalResult
LHSType::verify(function_ref<InFlightDiagnostic()> emitError,
2402 if (type.containsAnalog())
2403 return emitError() <<
"lhs type cannot contain an AnalogType";
2405 return emitError() <<
"lhs type cannot contain a non-passive type";
2406 if (type.containsReference())
2407 return emitError() <<
"lhs type cannot contain a reference";
2408 if (type_isa<LHSType>(type))
2409 return emitError() <<
"lhs type cannot contain a lhs type";
2420 return Base::get(type.getContext(), type, forceable, layer);
2426 if (!base.isPassive())
2427 return emitErrorFn() <<
"reference base type must be passive";
2428 if (forceable && base.containsConst())
2429 return emitErrorFn()
2430 <<
"forceable reference base type cannot contain const";
2435 auto rtp = getType().getRecursiveTypeProperties();
2438 rtp.isPassive =
false;
2456 int32_t widthOrSentinel,
bool isConst) {
2457 if (widthOrSentinel < -1)
2458 return emitError() <<
"invalid width";
2462 int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2464 AnalogType AnalogType::getConstType(
bool isConst) {
2467 return get(getContext(), getWidthOrSentinel(),
isConst);
2474 ClockType ClockType::getConstType(
bool isConst) {
2484 ResetType ResetType::getConstType(
bool isConst) {
2494 AsyncResetType AsyncResetType::getConstType(
bool isConst) {
2505 using KeyTy = std::pair<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2509 auto name = key.first;
2510 auto elements = allocator.copyInto(key.second);
2513 SmallVector<uint64_t, 4> ids;
2522 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2545 ArrayRef<ClassElement> elements) {
2546 return get(name.getContext(), name, elements);
2550 return getNameAttr().getAttr().getValue();
2553 FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2555 ArrayRef<ClassElement> ClassType::getElements()
const {
2556 return getImpl()->elements;
2559 const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2560 return getElement(index.getValue().getZExtValue());
2563 const ClassElement &ClassType::getElement(
size_t index)
const {
2564 return getElements()[index];
2567 std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2568 for (
const auto [i, e] : llvm::enumerate(getElements()))
2569 if (fieldName == e.name)
2574 void ClassType::printInterface(AsmPrinter &p)
const {
2578 for (
const auto &element : getElements()) {
2582 p.printKeywordOrString(element.name);
2583 p <<
": " << element.type;
2590 return getImpl()->fieldIDs[index];
2594 assert(!getElements().
empty() &&
"Class must have >0 fields");
2595 auto fieldIDs = getImpl()->fieldIDs;
2596 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2597 return std::distance(fieldIDs.begin(), it);
2600 std::pair<uint64_t, uint64_t>
2604 return {index, fieldID - elementFieldID};
2607 std::pair<Type, uint64_t>
2612 auto subfieldType = getElement(subfieldIndex).type;
2613 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2614 return {subfieldType, subfieldID};
2619 std::pair<uint64_t, bool>
2622 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2624 return std::make_pair(fieldID - childRoot,
2625 fieldID >= childRoot && fieldID <= rangeEnd);
2628 ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2629 StringAttr className;
2630 if (parser.parseSymbolName(className))
2633 SmallVector<ClassElement> elements;
2634 if (parser.parseCommaSeparatedList(
2635 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
2637 Direction direction;
2638 if (succeeded(parser.parseOptionalKeyword(
"out")))
2639 direction = Direction::Out;
2640 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2641 direction = Direction::In;
2646 std::string keyword;
2647 if (parser.parseKeywordOrString(&keyword))
2649 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2653 if (parser.parseColonType(type))
2656 elements.emplace_back(name, type, direction);
2669 void FIRRTLDialect::registerTypes() {
2671 #define GET_TYPEDEF_LIST
2672 #include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
2686 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
2687 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
2689 for (
auto &elt : bundle) {
2690 if (elt.isFlip && !ignoreFlip)
2691 return std::nullopt;
2694 return std::nullopt;
2699 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
2701 for (
auto &elt : fenum) {
2704 return std::nullopt;
2707 return width + llvm::Log2_32_Ceil(fenum.getNumElements());
2709 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
2712 return std::nullopt;
2713 return *w * vector.getNumElements();
2716 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
2717 .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.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
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....
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
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.
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.
size_t hash_combine(size_t h1, size_t h2)
C++'s stdlib doesn't have a hash_combine function. This is a simple one.
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