17#include "mlir/IR/DialectImplementation.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/ADT/TypeSwitch.h"
23using namespace firrtl;
25using mlir::OptionalParseResult;
26using mlir::TypeStorageAllocator;
33#define GET_TYPEDEF_CLASSES
34#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
49 auto printWidthQualifier = [&](std::optional<int32_t> width) {
51 os <<
'<' << *width <<
'>';
53 bool anyFailed =
false;
54 TypeSwitch<Type>(type)
55 .Case<ClockType>([&](
auto) { os <<
"clock"; })
56 .Case<ResetType>([&](
auto) { os <<
"reset"; })
57 .Case<AsyncResetType>([&](
auto) { os <<
"asyncreset"; })
58 .Case<SIntType>([&](
auto sIntType) {
60 printWidthQualifier(sIntType.getWidth());
62 .Case<UIntType>([&](
auto uIntType) {
64 printWidthQualifier(uIntType.getWidth());
66 .Case<AnalogType>([&](
auto analogType) {
68 printWidthQualifier(analogType.getWidth());
70 .Case<BundleType, OpenBundleType>([&](
auto bundleType) {
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)
90 .Case<FEnumType>([&](
auto fenumType) {
92 std::optional<APInt> previous;
93 llvm::interleaveComma(
94 fenumType, os, [&](FEnumType::EnumElement element) {
96 os << element.name.getValue();
99 auto value = element.value.getValue();
104 if (value != previous) {
106 os.printAttributeWithoutType(element.value);
108 }
else if (!element.value.getValue().isZero()) {
110 os.printAttributeWithoutType(element.value);
115 bool skipType =
false;
116 if (
auto type = dyn_cast<UIntType>(element.type))
117 if (type.getWidth() == 0)
126 .Case<FVectorType, OpenVectorType>([&](
auto vectorType) {
127 if (firrtl::type_isa<OpenVectorType>(vectorType))
131 os <<
", " << vectorType.getNumElements() <<
'>';
133 .Case<RefType>([&](RefType refType) {
134 if (refType.getForceable())
138 if (
auto layer = refType.getLayer())
142 .Case<LHSType>([&](LHSType lhstype) {
147 .Case<StringType>([&](
auto stringType) { os <<
"string"; })
148 .Case<FIntegerType>([&](
auto integerType) { os <<
"integer"; })
149 .Case<BoolType>([&](
auto boolType) { os <<
"bool"; })
150 .Case<DoubleType>([&](
auto doubleType) { os <<
"double"; })
151 .Case<ListType>([&](
auto listType) {
156 .Case<PathType>([&](
auto pathType) { os <<
"path"; })
157 .Case<BaseTypeAliasType>([&](BaseTypeAliasType alias) {
158 os <<
"alias<" << alias.getName().getValue() <<
", ";
162 .Case<ClassType>([&](ClassType type) {
164 type.printInterface(os);
167 .Case<AnyRefType>([&](AnyRefType type) { os <<
"anyref"; })
168 .Case<FStringType>([&](
auto) { os <<
"fstring"; })
169 .Case<DomainType>([&](
auto) { os <<
"domain"; })
170 .Default([&](
auto) { anyFailed =
true; });
171 return failure(anyFailed);
182 assert(
false &&
"type to print unknown to FIRRTL dialect");
217 const char constPrefix[] =
"const.";
218 if (name.starts_with(constPrefix)) {
220 name = name.drop_front(std::size(constPrefix) - 1);
223 auto *context = parser.getContext();
225 return result = ClockType::get(context,
isConst), success();
227 return result = ResetType::get(context,
isConst), success();
228 if (name ==
"asyncreset")
229 return result = AsyncResetType::get(context,
isConst), success();
231 if (name ==
"sint" || name ==
"uint" || name ==
"analog") {
234 if (!parser.parseOptionalLess()) {
235 if (parser.parseInteger(width) || parser.parseGreater())
239 return parser.emitError(parser.getNameLoc(),
"unknown width"),
244 result = SIntType::get(context, width,
isConst);
245 else if (name ==
"uint")
246 result = UIntType::get(context, width,
isConst);
249 result = AnalogType::get(context, width,
isConst);
254 if (name ==
"bundle") {
255 SmallVector<BundleType::BundleElement, 4> elements;
257 auto parseBundleElement = [&]() -> ParseResult {
262 if (failed(parser.parseKeywordOrString(&nameStr)))
266 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
270 elements.push_back({StringAttr::get(context, name), isFlip, type});
274 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
278 result = parser.getChecked<BundleType>(context, elements,
isConst);
279 return failure(!result);
281 if (name ==
"openbundle") {
282 SmallVector<OpenBundleType::BundleElement, 4> elements;
284 auto parseBundleElement = [&]() -> ParseResult {
289 if (failed(parser.parseKeywordOrString(&nameStr)))
293 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
297 elements.push_back({StringAttr::get(context, name), isFlip, type});
301 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
305 result = parser.getChecked<OpenBundleType>(context, elements,
isConst);
306 return failure(!result);
309 if (name ==
"enum") {
310 SmallVector<StringAttr> names;
311 SmallVector<APInt> values;
312 SmallVector<FIRRTLBaseType> types;
313 auto parseEnumElement = [&]() -> ParseResult {
316 if (failed(parser.parseKeywordOrString(&nameStr)))
318 names.push_back(StringAttr::get(context, nameStr));
324 if (succeeded(parser.parseOptionalEqual())) {
325 if (parser.parseInteger(value))
327 }
else if (values.empty()) {
333 auto &prev = values.back();
334 if (prev.isMaxValue())
335 value = prev.zext(prev.getBitWidth() + 1);
340 values.push_back(std::move(value));
344 if (succeeded(parser.parseOptionalColon())) {
348 type = UIntType::get(parser.getContext(), 0);
350 types.push_back(type);
355 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
360 unsigned bitwidth = 0;
361 for (
auto &value : values)
362 bitwidth = std::max(bitwidth, value.getActiveBits());
363 auto tagType = IntegerType::get(context, bitwidth, IntegerType::Unsigned);
365 SmallVector<FEnumType::EnumElement, 4> elements;
366 for (
auto [name, value, type] : llvm::zip(names, values, types)) {
367 auto tagValue = value.zextOrTrunc(bitwidth);
368 elements.push_back({name, IntegerAttr::get(tagType, tagValue), type});
371 if (failed(FEnumType::verify(
372 [&]() {
return parser.emitError(parser.getNameLoc()); }, elements,
376 result = parser.getChecked<FEnumType>(context, elements,
isConst);
377 return failure(!result);
380 if (name ==
"vector") {
385 parser.parseComma() || parser.parseInteger(width) ||
386 parser.parseGreater())
391 if (name ==
"openvector") {
396 parser.parseComma() || parser.parseInteger(width) ||
397 parser.parseGreater())
402 return failure(!result);
406 if (name ==
"ref" || name ==
"probe") {
413 if (parser.parseOptionalComma().succeeded())
414 if (parser.parseOptionalAttribute(layer).value())
415 return parser.emitError(parser.getNameLoc(),
416 "expected symbol reference");
417 if (parser.parseGreater())
420 if (failed(RefType::verify(
421 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
425 return result = RefType::get(type,
false, layer), success();
430 parser.parseGreater())
432 if (!isa<FIRRTLBaseType>(type))
433 return parser.emitError(parser.getNameLoc(),
"expected base type");
434 result = parser.getChecked<LHSType>(context, cast<FIRRTLBaseType>(type));
435 return failure(!result);
437 if (name ==
"rwprobe") {
442 if (parser.parseOptionalComma().succeeded())
443 if (parser.parseOptionalAttribute(layer).value())
444 return parser.emitError(parser.getNameLoc(),
445 "expected symbol reference");
446 if (parser.parseGreater())
449 if (failed(RefType::verify(
450 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
true,
454 return result = RefType::get(type,
true, layer), success();
456 if (name ==
"class") {
458 return parser.emitError(parser.getNameLoc(),
"classes cannot be const");
460 if (parser.parseLess() || ClassType::parseInterface(parser, classType) ||
461 parser.parseGreater())
466 if (name ==
"anyref") {
468 return parser.emitError(parser.getNameLoc(),
"any refs cannot be const");
470 result = AnyRefType::get(parser.getContext());
473 if (name ==
"string") {
475 parser.emitError(parser.getNameLoc(),
"strings cannot be const");
478 result = StringType::get(parser.getContext());
481 if (name ==
"integer") {
483 parser.emitError(parser.getNameLoc(),
"bigints cannot be const");
486 result = FIntegerType::get(parser.getContext());
489 if (name ==
"bool") {
491 parser.emitError(parser.getNameLoc(),
"bools cannot be const");
494 result = BoolType::get(parser.getContext());
497 if (name ==
"double") {
499 parser.emitError(parser.getNameLoc(),
"doubles cannot be const");
502 result = DoubleType::get(parser.getContext());
505 if (name ==
"list") {
507 parser.emitError(parser.getNameLoc(),
"lists cannot be const");
512 parser.parseGreater())
514 result = parser.getChecked<ListType>(context,
elementType);
519 if (name ==
"path") {
521 parser.emitError(parser.getNameLoc(),
"path cannot be const");
524 result = PathType::get(parser.getContext());
527 if (name ==
"alias") {
530 if (parser.parseLess() || parser.parseKeyword(&name) ||
532 parser.parseGreater())
536 BaseTypeAliasType::get(StringAttr::get(context, name), type),
539 if (name ==
"fstring") {
540 return result = FStringType::get(context), success();
542 if (name ==
"domain") {
543 return result = DomainType::get(context), success();
554static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
557 if (parseResult.has_value())
558 return parseResult.value();
561 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL dialect type: \"")
573 if (failed(
parseType(type, name, parser)))
575 result = type_dyn_cast<FIRRTLType>(type);
578 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL type: \"")
588 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type)) {
592 parser.emitError(parser.getNameLoc(),
"expected base type, found ") << type;
601 if (
auto prop = type_dyn_cast<PropertyType>(type)) {
605 parser.emitError(parser.getNameLoc(),
"expected property type, found ")
618 if (parser.parseKeyword(&name))
628 if (parser.parseKeyword(&name))
638 if (parser.parseKeyword(&name))
649void FIRRTLDialect::printType(Type type, DialectAsmPrinter &os)
const {
654Type FIRRTLDialect::parseType(DialectAsmParser &parser)
const {
657 if (parser.parseKeyword(&name) ||
::parseType(result, name, parser))
700bool FIRRTLType::isGround() {
701 return TypeSwitch<FIRRTLType, bool>(*
this)
702 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
703 AnalogType>([](Type) {
return true; })
704 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType>(
705 [](Type) {
return false; })
706 .Case<BaseTypeAliasType>([](BaseTypeAliasType alias) {
707 return alias.getAnonymousType().isGround();
710 .Case<PropertyType, RefType>([](Type) {
return false; })
712 llvm_unreachable(
"unknown FIRRTL type");
718 return TypeSwitch<FIRRTLType, bool>(*
this)
720 [](
auto type) {
return type.isConst(); })
727 return TypeSwitch<FIRRTLType, RecursiveTypeProperties>(*
this)
728 .Case<ClockType, ResetType, AsyncResetType>([](
FIRRTLBaseType type) {
735 firrtl::type_isa<ResetType>(type)};
737 .Case<SIntType, UIntType>([](
auto type) {
739 true,
false,
false, type.isConst(),
false, !type.hasWidth(),
false};
741 .Case<AnalogType>([](
auto type) {
743 true,
false,
true, type.isConst(),
false, !type.hasWidth(),
false};
745 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType,
746 RefType, BaseTypeAliasType>(
747 [](
auto type) {
return type.getRecursiveTypeProperties(); })
748 .Case<PropertyType>([](
auto type) {
750 false,
false,
false};
753 [](
auto type) {
return type.getType().getRecursiveTypeProperties(); })
754 .Case<FStringType>([](
auto type) {
756 false,
false,
false};
758 .Case<DomainType>([](
auto type) {
760 false,
false,
false};
763 llvm_unreachable(
"unknown FIRRTL type");
770 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
771 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
772 AnalogType>([&](Type) {
return *
this; })
773 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
774 [](
auto type) {
return type.getAnonymousType(); })
776 llvm_unreachable(
"unknown FIRRTL type");
783 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
784 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
785 AnalogType, FEnumType>([&](Type) {
return *
this; })
786 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
787 [](
auto type) {
return type.getPassiveType(); })
789 llvm_unreachable(
"unknown FIRRTL type");
796 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
797 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
798 UIntType, BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
799 [&](
auto type) {
return type.getConstType(
isConst); })
801 llvm_unreachable(
"unknown FIRRTL type");
808 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
809 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
810 UIntType>([&](
auto type) {
return type.getConstType(
false); })
811 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
812 [&](
auto type) {
return type.getAllConstDroppedType(); })
814 llvm_unreachable(
"unknown FIRRTL type");
822 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
823 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
824 AnalogType, FEnumType>([&](Type) {
825 return UIntType::get(this->getContext(), 1, this->
isConst());
827 .Case<BundleType>([&](BundleType bundleType) {
828 SmallVector<BundleType::BundleElement, 4> newElements;
829 newElements.reserve(bundleType.getElements().size());
830 for (
auto elt : bundleType)
831 newElements.push_back(
832 {elt.name,
false , elt.type.getMaskType()});
833 return BundleType::get(this->getContext(), newElements,
834 bundleType.isConst());
836 .Case<FVectorType>([](FVectorType vectorType) {
837 return FVectorType::get(vectorType.getElementType().getMaskType(),
838 vectorType.getNumElements(),
839 vectorType.isConst());
841 .Case<BaseTypeAliasType>([](BaseTypeAliasType base) {
842 return base.getModifiedType(base.getInnerType().getMaskType());
845 llvm_unreachable(
"unknown FIRRTL type");
853 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
854 .Case<ClockType, ResetType, AsyncResetType>([](
auto a) {
return a; })
855 .Case<UIntType, SIntType, AnalogType>(
856 [&](
auto a) {
return a.get(this->getContext(), -1, a.isConst()); })
857 .Case<BundleType>([&](
auto a) {
858 SmallVector<BundleType::BundleElement, 4> newElements;
859 newElements.reserve(a.getElements().size());
861 newElements.push_back(
862 {elt.name, elt.isFlip, elt.type.getWidthlessType()});
863 return BundleType::get(this->getContext(), newElements, a.isConst());
865 .Case<FVectorType>([](
auto a) {
866 return FVectorType::get(a.getElementType().getWidthlessType(),
867 a.getNumElements(), a.isConst());
869 .Case<FEnumType>([&](FEnumType a) {
870 SmallVector<FEnumType::EnumElement, 4> newElements;
871 newElements.reserve(a.getNumElements());
873 newElements.push_back(
874 {elt.name, elt.value, elt.type.getWidthlessType()});
875 return FEnumType::get(this->getContext(), newElements, a.isConst());
877 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
878 return type.getModifiedType(type.getInnerType().getWidthlessType());
881 llvm_unreachable(
"unknown FIRRTL type");
891 return TypeSwitch<FIRRTLBaseType, int32_t>(*
this)
892 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
893 .Case<SIntType, UIntType>(
896 [](AnalogType analogType) {
return analogType.getWidthOrSentinel(); })
897 .Case<FEnumType>([&](FEnumType fenum) {
return fenum.getBitWidth(); })
898 .Case<BundleType, FVectorType>([](Type) {
return -2; })
899 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
901 return type.getAnonymousType().getBitWidthOrSentinel();
904 llvm_unreachable(
"unknown FIRRTL type");
913 return TypeSwitch<FIRRTLType, bool>(*
this)
914 .Case<ResetType, AsyncResetType>([](Type) {
return true; })
916 [](UIntType a) {
return !a.hasWidth() || a.getWidth() == 1; })
917 .Case<BaseTypeAliasType>(
918 [](
auto type) {
return type.getInnerType().isResetType(); })
919 .Default([](Type) {
return false; });
923 return TypeSwitch<Type, bool>(type)
925 [](
auto base) {
return base.isConst(); })
930 return TypeSwitch<Type, bool>(type)
932 [](
auto base) {
return base.containsConst(); })
939 .
Case<BundleType>([&](
auto bundle) {
940 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
941 auto elt = bundle.getElement(i);
945 return bundle.getNumElements() == 0;
947 .Case<FVectorType>([&](
auto vector) {
948 if (vector.getNumElements() == 0)
952 .Case<FIRRTLBaseType>([](
auto groundType) {
955 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
956 .Default([](
auto) {
return false; });
966 BundleType::BundleElement srcElement,
967 bool destOuterTypeIsConst,
968 bool srcOuterTypeIsConst,
969 bool requiresSameWidth) {
970 if (destElement.name != srcElement.name)
972 if (destElement.isFlip != srcElement.isFlip)
975 if (destElement.isFlip) {
976 std::swap(destElement, srcElement);
977 std::swap(destOuterTypeIsConst, srcOuterTypeIsConst);
981 destOuterTypeIsConst, srcOuterTypeIsConst,
990 bool destOuterTypeIsConst,
991 bool srcOuterTypeIsConst,
992 bool requireSameWidths) {
993 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
994 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
997 if (!destType || !srcType)
998 return destFType == srcFType;
1000 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
1001 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
1004 auto destVectorType = type_dyn_cast<FVectorType>(destType);
1005 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
1006 if (destVectorType && srcVectorType)
1007 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1009 srcVectorType.getElementType(), destIsConst,
1010 srcIsConst, requireSameWidths);
1014 auto destBundleType = type_dyn_cast<BundleType>(destType);
1015 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1016 if (destBundleType && srcBundleType) {
1017 auto destElements = destBundleType.getElements();
1018 auto srcElements = srcBundleType.getElements();
1019 size_t numDestElements = destElements.size();
1020 if (numDestElements != srcElements.size())
1023 for (
size_t i = 0; i < numDestElements; ++i) {
1024 auto destElement = destElements[i];
1025 auto srcElement = srcElements[i];
1027 srcIsConst, requireSameWidths))
1035 auto dstEnumType = type_dyn_cast<FEnumType>(destType);
1036 auto srcEnumType = type_dyn_cast<FEnumType>(srcType);
1038 if (dstEnumType && srcEnumType) {
1039 if (dstEnumType.getNumElements() != srcEnumType.getNumElements())
1042 for (
const auto &[dst, src] : llvm::zip(dstEnumType, srcEnumType)) {
1044 if (dst.name != src.name)
1056 if (destIsConst && !srcIsConst)
1060 if (firrtl::type_isa<ResetType>(destType))
1061 return srcType.isResetType();
1064 if (firrtl::type_isa<ResetType>(srcType))
1065 return destType.isResetType();
1069 if (!requireSameWidths || destType.getBitWidthOrSentinel() == -1)
1070 srcType = srcType.getWidthlessType();
1071 if (!requireSameWidths || srcType.getBitWidthOrSentinel() == -1)
1072 destType = destType.getWidthlessType();
1075 return destType.getConstType(
false) == srcType.getConstType(
false);
1080 bool srcOuterTypeIsConst) {
1082 if (destFType == srcFType)
1085 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
1086 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
1089 if (!destType || !srcType)
1093 if (!destType.isPassive() || !srcType.isPassive())
1096 bool srcIsConst = srcType.isConst() || srcOuterTypeIsConst;
1099 if (destType.isConst() && !srcIsConst)
1104 auto destVectorType = type_dyn_cast<FVectorType>(destType);
1105 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
1106 if (destVectorType && srcVectorType)
1107 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1109 srcVectorType.getElementType(), srcIsConst);
1110 if (destVectorType != srcVectorType)
1115 auto destBundleType = type_dyn_cast<BundleType>(destType);
1116 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1117 if (destBundleType && srcBundleType) {
1118 auto destElements = destBundleType.getElements();
1119 auto srcElements = srcBundleType.getElements();
1120 size_t numDestElements = destElements.size();
1121 if (numDestElements != srcElements.size())
1124 return llvm::all_of_zip(
1125 destElements, srcElements,
1126 [&](
const auto &destElement,
const auto &srcElement) {
1127 return destElement.name == srcElement.name &&
1132 if (destBundleType != srcBundleType)
1137 return destType == srcType.getConstType(destType.isConst());
1141 auto dstRefType = type_dyn_cast<RefType>(dstType);
1142 auto srcRefType = type_dyn_cast<RefType>(srcType);
1143 if (!dstRefType || !srcRefType)
1145 if (dstRefType == srcRefType)
1147 if (dstRefType.getForceable() && !srcRefType.getForceable())
1159 bool srcOuterTypeIsConst) ->
bool {
1165 assert(dest.isPassive() && src.isPassive());
1167 bool srcIsConst = src.isConst() || srcOuterTypeIsConst;
1170 if (dest.isConst() && !srcIsConst)
1176 if (
auto destVectorType = type_dyn_cast<FVectorType>(dest)) {
1177 auto srcVectorType = type_dyn_cast<FVectorType>(src);
1178 return srcVectorType &&
1179 destVectorType.getNumElements() ==
1180 srcVectorType.getNumElements() &&
1181 f(f, destVectorType.getElementType(),
1182 srcVectorType.getElementType(), srcIsConst);
1185 if (
auto destBundleType = type_dyn_cast<BundleType>(dest)) {
1186 auto srcBundleType = type_dyn_cast<BundleType>(src);
1190 auto destElements = destBundleType.getElements();
1191 auto srcElements = srcBundleType.getElements();
1193 return destElements.size() == srcElements.size() &&
1195 destElements, srcElements,
1196 [&](
const auto &destElement,
const auto &srcElement) {
1197 return destElement.name == srcElement.name &&
1198 f(f, destElement.type, srcElement.type, srcIsConst);
1202 if (
auto destEnumType = type_dyn_cast<FEnumType>(dest)) {
1203 auto srcEnumType = type_dyn_cast<FEnumType>(src);
1206 auto destElements = destEnumType.getElements();
1207 auto srcElements = srcEnumType.getElements();
1209 return destElements.size() == srcElements.size() &&
1211 destElements, srcElements,
1212 [&](
const auto &destElement,
const auto &srcElement) {
1213 return destElement.name == srcElement.name &&
1214 f(f, destElement.type, srcElement.type, srcIsConst);
1219 if (type_isa<ResetType>(dest))
1220 return src.isResetType();
1224 src = src.getConstType(dest.isConst());
1227 if (dest.getBitWidthOrSentinel() == -1)
1228 src = src.getWidthlessType();
1233 return recurse(recurse, dstRefType.getType(), srcRefType.getType(),
false);
1240 return TypeSwitch<FIRRTLBaseType, bool>(dstType)
1241 .Case<BundleType>([&](
auto dstBundle) {
1242 auto srcBundle = type_cast<BundleType>(srcType);
1243 for (
size_t i = 0, n = dstBundle.getNumElements(); i < n; ++i) {
1244 auto srcElem = srcBundle.getElement(i);
1245 auto dstElem = dstBundle.getElement(i);
1246 if (dstElem.isFlip) {
1256 .Case<FVectorType>([&](
auto vector) {
1258 type_cast<FVectorType>(srcType).getElementType());
1260 .Default([&](
auto dstGround) {
1263 return destWidth <= -1 || srcWidth <= -1 || destWidth >= srcWidth;
1274 if (
auto destBaseType = type_dyn_cast<FIRRTLBaseType>(lhs))
1275 if (
auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(rhs))
1278 if (
auto destRefType = type_dyn_cast<RefType>(lhs))
1279 if (
auto srcRefType = type_dyn_cast<RefType>(rhs))
1281 srcRefType.getType());
1289 return type_cast<FIRRTLBaseType>(anyBaseFIRRTLType).getPassiveType();
1293 return llvm::TypeSwitch<Type, bool>(type)
1295 return !type.containsReference() &&
1296 (!type.isPassive() || type.containsAnalog());
1308 int32_t widthOrSentinel,
bool isConst) {
1310 return SIntType::get(context, widthOrSentinel,
isConst);
1311 return UIntType::get(context, widthOrSentinel,
isConst);
1315 if (
auto sintType = type_dyn_cast<SIntType>(*
this))
1316 return sintType.getWidthOrSentinel();
1317 if (
auto uintType = type_dyn_cast<UIntType>(*
this))
1318 return uintType.getWidthOrSentinel();
1346 if (
auto sIntType = type_dyn_cast<SIntType>(*
this))
1355SIntType SIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1357SIntType SIntType::get(MLIRContext *context, std::optional<int32_t> width,
1359 return get(context, width ? *width : -1,
isConst);
1362LogicalResult SIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1363 int32_t widthOrSentinel,
bool isConst) {
1364 if (widthOrSentinel < -1)
1365 return emitError() <<
"invalid width";
1369int32_t SIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1371SIntType SIntType::getConstType(
bool isConst)
const {
1374 return get(getContext(), getWidthOrSentinel(),
isConst);
1381UIntType UIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1383UIntType UIntType::get(MLIRContext *context, std::optional<int32_t> width,
1385 return get(context, width ? *width : -1,
isConst);
1388LogicalResult UIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1389 int32_t widthOrSentinel,
bool isConst) {
1390 if (widthOrSentinel < -1)
1391 return emitError() <<
"invalid width";
1395int32_t UIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1397UIntType UIntType::getConstType(
bool isConst)
const {
1400 return get(getContext(), getWidthOrSentinel(),
isConst);
1409 using KeyTy = std::pair<ArrayRef<BundleType::BundleElement>,
char>;
1416 uint64_t fieldID = 0;
1419 auto type = element.type;
1420 auto eltInfo = type.getRecursiveTypeProperties();
1441 return llvm::hash_combine(
1442 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1463BundleType BundleType::get(MLIRContext *context,
1464 ArrayRef<BundleElement> elements,
bool isConst) {
1465 return Base::get(context, elements,
isConst);
1468auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1469 return getImpl()->elements;
1474 return getImpl()->props;
1479 auto *impl = getImpl();
1482 if (impl->passiveType)
1483 return impl->passiveType;
1486 if (impl->props.isPassive) {
1487 impl->passiveType = *
this;
1492 SmallVector<BundleType::BundleElement, 16> newElements;
1493 newElements.reserve(impl->elements.size());
1494 for (
auto &elt : impl->elements) {
1495 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1498 auto passiveType = BundleType::get(getContext(), newElements,
isConst());
1499 impl->passiveType = passiveType;
1503BundleType BundleType::getConstType(
bool isConst)
const {
1506 return get(getContext(), getElements(),
isConst);
1509BundleType BundleType::getAllConstDroppedType() {
1513 SmallVector<BundleElement> constDroppedElements(
1514 llvm::map_range(getElements(), [](BundleElement element) {
1515 element.type = element.type.getAllConstDroppedType();
1518 return get(getContext(), constDroppedElements,
false);
1521std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1522 for (
const auto &it :
llvm::enumerate(getElements())) {
1523 auto element = it.value();
1524 if (element.name == name) {
1525 return unsigned(it.index());
1528 return std::nullopt;
1531std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1532 for (
const auto &it :
llvm::enumerate(getElements())) {
1533 auto element = it.value();
1534 if (element.name.getValue() == name) {
1535 return unsigned(it.index());
1538 return std::nullopt;
1541StringAttr BundleType::getElementNameAttr(
size_t index) {
1542 assert(index < getNumElements() &&
1543 "index must be less than number of fields in bundle");
1544 return getElements()[index].name;
1547StringRef BundleType::getElementName(
size_t index) {
1548 return getElementNameAttr(index).getValue();
1551std::optional<BundleType::BundleElement>
1552BundleType::getElement(StringAttr name) {
1553 if (
auto maybeIndex = getElementIndex(name))
1554 return getElements()[*maybeIndex];
1555 return std::nullopt;
1558std::optional<BundleType::BundleElement>
1559BundleType::getElement(StringRef name) {
1560 if (
auto maybeIndex = getElementIndex(name))
1561 return getElements()[*maybeIndex];
1562 return std::nullopt;
1566BundleType::BundleElement BundleType::getElement(
size_t index) {
1567 assert(index < getNumElements() &&
1568 "index must be less than number of fields in bundle");
1569 return getElements()[index];
1573 auto element = getElement(name);
1578 auto element = getElement(name);
1583 assert(index < getNumElements() &&
1584 "index must be less than number of fields in bundle");
1585 return getElements()[index].type;
1588uint64_t BundleType::getFieldID(uint64_t index)
const {
1589 return getImpl()->fieldIDs[index];
1592uint64_t BundleType::getIndexForFieldID(uint64_t fieldID)
const {
1593 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1594 auto fieldIDs = getImpl()->fieldIDs;
1595 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1596 return std::distance(fieldIDs.begin(), it);
1599std::pair<uint64_t, uint64_t>
1600BundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1603 return {index, fieldID - elementFieldID};
1606std::pair<Type, uint64_t>
1607BundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1611 auto subfieldType = getElementType(subfieldIndex);
1612 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1613 return {subfieldType, subfieldID};
1616uint64_t BundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1618std::pair<uint64_t, bool>
1619BundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1621 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1623 return std::make_pair(fieldID - childRoot,
1624 fieldID >= childRoot && fieldID <= rangeEnd);
1627bool BundleType::isConst()
const {
return getImpl()->isConst; }
1629BundleType::ElementType
1630BundleType::getElementTypePreservingConst(
size_t index) {
1631 auto type = getElementType(index);
1632 return type.getConstType(type.isConst() ||
isConst());
1637 auto *impl = getImpl();
1640 if (impl->anonymousType)
1641 return impl->anonymousType;
1644 if (!impl->props.containsTypeAlias) {
1645 impl->anonymousType = *
this;
1651 SmallVector<BundleType::BundleElement, 16> newElements;
1652 newElements.reserve(impl->elements.size());
1653 for (
auto &elt : impl->elements)
1654 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1656 auto anonymousType = BundleType::get(getContext(), newElements,
isConst());
1657 impl->anonymousType = anonymousType;
1658 return anonymousType;
1661LogicalResult BundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1662 ArrayRef<BundleElement> elements,
1664 SmallPtrSet<StringAttr, 4> nameSet;
1665 for (
auto &element : elements) {
1666 if (!nameSet.insert(element.name).second)
1667 return emitErrorFn() <<
"duplicate field name " << element.name
1679 using KeyTy = std::pair<ArrayRef<OpenBundleType::BundleElement>,
char>;
1687 uint64_t fieldID = 0;
1690 auto type = element.type;
1691 auto eltInfo = type.getRecursiveTypeProperties();
1711 return llvm::hash_combine(
1712 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1724 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1736OpenBundleType OpenBundleType::get(MLIRContext *context,
1737 ArrayRef<BundleElement> elements,
1739 return Base::get(context, elements,
isConst);
1742auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1743 return getImpl()->elements;
1748 return getImpl()->props;
1751OpenBundleType OpenBundleType::getConstType(
bool isConst)
const {
1754 return get(getContext(), getElements(),
isConst);
1757std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1758 for (
const auto &it :
llvm::enumerate(getElements())) {
1759 auto element = it.value();
1760 if (element.name == name) {
1761 return unsigned(it.index());
1764 return std::nullopt;
1767std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1768 for (
const auto &it :
llvm::enumerate(getElements())) {
1769 auto element = it.value();
1770 if (element.name.getValue() == name) {
1771 return unsigned(it.index());
1774 return std::nullopt;
1777StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1778 assert(index < getNumElements() &&
1779 "index must be less than number of fields in bundle");
1780 return getElements()[index].name;
1783StringRef OpenBundleType::getElementName(
size_t index) {
1784 return getElementNameAttr(index).getValue();
1787std::optional<OpenBundleType::BundleElement>
1788OpenBundleType::getElement(StringAttr name) {
1789 if (
auto maybeIndex = getElementIndex(name))
1790 return getElements()[*maybeIndex];
1791 return std::nullopt;
1794std::optional<OpenBundleType::BundleElement>
1795OpenBundleType::getElement(StringRef name) {
1796 if (
auto maybeIndex = getElementIndex(name))
1797 return getElements()[*maybeIndex];
1798 return std::nullopt;
1802OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1803 assert(index < getNumElements() &&
1804 "index must be less than number of fields in bundle");
1805 return getElements()[index];
1808OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1809 auto element = getElement(name);
1813OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1814 auto element = getElement(name);
1818OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1819 assert(index < getNumElements() &&
1820 "index must be less than number of fields in bundle");
1821 return getElements()[index].type;
1824uint64_t OpenBundleType::getFieldID(uint64_t index)
const {
1825 return getImpl()->fieldIDs[index];
1828uint64_t OpenBundleType::getIndexForFieldID(uint64_t fieldID)
const {
1829 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1830 auto fieldIDs = getImpl()->fieldIDs;
1831 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1832 return std::distance(fieldIDs.begin(), it);
1835std::pair<uint64_t, uint64_t>
1836OpenBundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1839 return {index, fieldID - elementFieldID};
1842std::pair<Type, uint64_t>
1843OpenBundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1847 auto subfieldType = getElementType(subfieldIndex);
1848 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1849 return {subfieldType, subfieldID};
1852uint64_t OpenBundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1854std::pair<uint64_t, bool>
1855OpenBundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1857 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1859 return std::make_pair(fieldID - childRoot,
1860 fieldID >= childRoot && fieldID <= rangeEnd);
1863bool OpenBundleType::isConst()
const {
return getImpl()->isConst; }
1865OpenBundleType::ElementType
1866OpenBundleType::getElementTypePreservingConst(
size_t index) {
1867 auto type = getElementType(index);
1869 return TypeSwitch<FIRRTLType, ElementType>(type)
1870 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1871 return type.getConstType(type.isConst() ||
isConst());
1877OpenBundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1878 ArrayRef<BundleElement> elements,
bool isConst) {
1879 SmallPtrSet<StringAttr, 4> nameSet;
1880 for (
auto &element : elements) {
1881 if (!nameSet.insert(element.name).second)
1882 return emitErrorFn() <<
"duplicate field name " << element.name
1883 <<
" in openbundle";
1885 return emitErrorFn()
1886 <<
"'const' bundle cannot have references, but element "
1887 << element.name <<
" has type " << element.type;
1888 if (type_isa<LHSType>(element.type))
1889 return emitErrorFn() <<
"bundle element " << element.name
1890 <<
" cannot have a left-hand side type";
1902 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1920 static_cast<bool>(std::get<2>(key)));
1939 return getImpl()->elementType;
1942size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
1946 return getImpl()->props;
1951 auto *impl = getImpl();
1954 if (impl->passiveType)
1955 return impl->passiveType;
1958 if (impl->elementType.getRecursiveTypeProperties().isPassive)
1959 return impl->passiveType = *
this;
1962 auto passiveType = FVectorType::get(getElementType().
getPassiveType(),
1964 impl->passiveType = passiveType;
1968FVectorType FVectorType::getConstType(
bool isConst)
const {
1971 return get(getElementType(), getNumElements(),
isConst);
1974FVectorType FVectorType::getAllConstDroppedType() {
1977 return get(getElementType().getAllConstDroppedType(), getNumElements(),
1983 auto *impl = getImpl();
1985 if (impl->anonymousType)
1986 return impl->anonymousType;
1989 if (!impl->props.containsTypeAlias)
1990 return impl->anonymousType = *
this;
1993 auto anonymousType = FVectorType::get(getElementType().getAnonymousType(),
1995 impl->anonymousType = anonymousType;
1996 return anonymousType;
1999uint64_t FVectorType::getFieldID(uint64_t index)
const {
2003uint64_t FVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2004 assert(fieldID &&
"fieldID must be at least 1");
2009std::pair<uint64_t, uint64_t>
2010FVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2013 return {index, fieldID - elementFieldID};
2016std::pair<Type, uint64_t>
2017FVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2023uint64_t FVectorType::getMaxFieldID()
const {
2024 return getNumElements() *
2028std::pair<uint64_t, bool>
2029FVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2033 return std::make_pair(fieldID - childRoot,
2034 fieldID >= childRoot && fieldID <= rangeEnd);
2037bool FVectorType::isConst()
const {
return getImpl()->isConst; }
2039FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
2040 auto type = getElementType();
2041 return type.getConstType(type.isConst() ||
isConst());
2049 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
2067 static_cast<bool>(std::get<2>(key)));
2082FIRRTLType OpenVectorType::getElementType()
const {
2083 return getImpl()->elementType;
2086size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
2090 return getImpl()->props;
2093OpenVectorType OpenVectorType::getConstType(
bool isConst)
const {
2096 return get(getElementType(), getNumElements(),
isConst);
2099uint64_t OpenVectorType::getFieldID(uint64_t index)
const {
2103uint64_t OpenVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2104 assert(fieldID &&
"fieldID must be at least 1");
2109std::pair<uint64_t, uint64_t>
2110OpenVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2113 return {index, fieldID - elementFieldID};
2116std::pair<Type, uint64_t>
2117OpenVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2123uint64_t OpenVectorType::getMaxFieldID()
const {
2125 return getNumElements() *
2129std::pair<uint64_t, bool>
2130OpenVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2134 return std::make_pair(fieldID - childRoot,
2135 fieldID >= childRoot && fieldID <= rangeEnd);
2138bool OpenVectorType::isConst()
const {
return getImpl()->isConst; }
2140OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2141 auto type = getElementType();
2143 return TypeSwitch<FIRRTLType, ElementType>(type)
2144 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2145 return type.getConstType(type.isConst() ||
isConst());
2151OpenVectorType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2155 return emitErrorFn() <<
"vector cannot be const with references";
2157 return emitErrorFn() <<
"vector cannot have a left-hand side type";
2166 using KeyTy = std::pair<ArrayRef<FEnumType::EnumElement>,
char>;
2172 false,
false,
false};
2175 auto type = element.type;
2176 auto eltInfo = type.getRecursiveTypeProperties();
2178 props.containsTypeAlias |= eltInfo.containsTypeAlias;
2190 return llvm::hash_combine(
2191 llvm::hash_combine_range(key.first.begin(), key.first.end()),
2207FEnumType FEnumType::get(::mlir::MLIRContext *context,
2208 ArrayRef<EnumElement> elements,
bool isConst) {
2209 return Base::get(context, elements,
isConst);
2212ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2213 return getImpl()->elements;
2216FEnumType FEnumType::getConstType(
bool isConst)
const {
2217 return get(getContext(), getElements(),
isConst);
2220FEnumType FEnumType::getAllConstDroppedType() {
2224 SmallVector<EnumElement> constDroppedElements(
2225 llvm::map_range(getElements(), [](EnumElement element) {
2226 element.type = element.type.getAllConstDroppedType();
2229 return get(getContext(), constDroppedElements,
false);
2234 return getImpl()->recProps;
2237std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2238 for (
const auto &it :
llvm::enumerate(getElements())) {
2239 auto element = it.value();
2240 if (element.name == name) {
2241 return unsigned(it.index());
2244 return std::nullopt;
2247size_t FEnumType::getBitWidth() {
return getDataWidth() + getTagWidth(); }
2249size_t FEnumType::getDataWidth() {
return getImpl()->dataSize; }
2251size_t FEnumType::getTagWidth() {
2252 if (getElements().size() == 0)
2255 return cast<IntegerType>(getElements()[0].value.getType()).getWidth();
2258std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2259 for (
const auto &it :
llvm::enumerate(getElements())) {
2260 auto element = it.value();
2261 if (element.name.getValue() == name) {
2262 return unsigned(it.index());
2265 return std::nullopt;
2268StringAttr FEnumType::getElementNameAttr(
size_t index) {
2269 assert(index < getNumElements() &&
2270 "index must be less than number of fields in enum");
2271 return getElements()[index].name;
2274StringRef FEnumType::getElementName(
size_t index) {
2275 return getElementNameAttr(index).getValue();
2278IntegerAttr FEnumType::getElementValueAttr(
size_t index) {
2279 return getElements()[index].value;
2282APInt FEnumType::getElementValue(
size_t index) {
2283 return getElementValueAttr(index).getValue();
2287 return getElements()[index].type;
2290std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2291 if (
auto maybeIndex = getElementIndex(name))
2292 return getElements()[*maybeIndex];
2293 return std::nullopt;
2296std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2297 if (
auto maybeIndex = getElementIndex(name))
2298 return getElements()[*maybeIndex];
2299 return std::nullopt;
2303FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2304 assert(index < getNumElements() &&
2305 "index must be less than number of fields in enum");
2306 return getElements()[index];
2310 auto element = getElement(name);
2315 auto element = getElement(name);
2320 assert(index < getNumElements() &&
2321 "index must be less than number of fields in enum");
2322 return getElements()[index].type;
2325FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2326 auto type = getElementType(index);
2327 return type.getConstType(type.isConst() ||
isConst());
2330LogicalResult FEnumType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2331 ArrayRef<EnumElement> elements,
bool isConst) {
2333 IntegerAttr previous;
2334 SmallPtrSet<Attribute, 4> nameSet;
2336 for (
auto &elt : elements) {
2337 auto r = elt.type.getRecursiveTypeProperties();
2339 return emitErrorFn() <<
"enum field " << elt.name <<
" not passive";
2340 if (r.containsAnalog)
2341 return emitErrorFn() <<
"enum field " << elt.name <<
" contains analog";
2342 if (r.hasUninferredWidth)
2343 return emitErrorFn() <<
"enum field " << elt.name
2344 <<
" has uninferred width";
2345 if (r.hasUninferredReset)
2346 return emitErrorFn() <<
"enum field " << elt.name
2347 <<
" has uninferred reset";
2348 if (r.containsConst && !
isConst)
2349 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2351 if (!nameSet.insert(elt.name).second)
2352 return emitErrorFn() <<
"duplicate variant name " << elt.name
2356 previous = elt.value;
2359 auto current = elt.value;
2360 if (previous.getType() != current.getType())
2361 return emitErrorFn() <<
"enum variant " << elt.name <<
" has type"
2362 << current.getType()
2363 <<
" which is different than previous variant "
2364 << previous.getType();
2366 if (previous.getValue().getBitWidth() != current.getValue().getBitWidth())
2367 return emitErrorFn() <<
"enum variant " << elt.name <<
" has bitwidth"
2368 << current.getValue().getBitWidth()
2369 <<
" which is different than previous variant "
2370 << previous.getValue().getBitWidth();
2371 if (previous.getValue().uge(current.getValue()))
2372 return emitErrorFn()
2373 <<
"enum variant " << elt.name <<
" has value " << current
2374 <<
" which is not greater than previous variant " << previous;
2383 auto *impl = getImpl();
2385 if (impl->anonymousType)
2386 return impl->anonymousType;
2388 if (!impl->recProps.containsTypeAlias)
2389 return impl->anonymousType = *
this;
2391 SmallVector<FEnumType::EnumElement, 4> elements;
2393 for (
auto element : getElements())
2395 {element.name, element.value, element.type.getAnonymousType()});
2396 return impl->anonymousType = FEnumType::get(getContext(), elements);
2405 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2416 return llvm::hash_combine(key);
2429auto BaseTypeAliasType::get(StringAttr name,
FIRRTLBaseType innerType)
2430 -> BaseTypeAliasType {
2431 return Base::get(name.getContext(), name, innerType);
2434auto BaseTypeAliasType::getName() const -> StringAttr {
2435 return getImpl()->name;
2439 return getImpl()->innerType;
2443 auto *impl = getImpl();
2444 if (impl->anonymousType)
2445 return impl->anonymousType;
2446 return impl->anonymousType = getInnerType().getAnonymousType();
2454 auto rtp = getInnerType().getRecursiveTypeProperties();
2462BaseTypeAliasType::getModifiedType(
FIRRTLBaseType newInnerType)
const {
2463 if (newInnerType == getInnerType())
2465 return newInnerType;
2470 return getModifiedType(getInnerType().getAllConstDroppedType());
2474 return getModifiedType(getInnerType().getConstType(
isConst));
2477std::pair<Type, uint64_t>
2478BaseTypeAliasType::getSubTypeByFieldID(uint64_t fieldID)
const {
2482uint64_t BaseTypeAliasType::getMaxFieldID()
const {
2486std::pair<uint64_t, bool>
2487BaseTypeAliasType::projectToChildFieldID(uint64_t fieldID,
2488 uint64_t index)
const {
2492uint64_t BaseTypeAliasType::getIndexForFieldID(uint64_t fieldID)
const {
2496uint64_t BaseTypeAliasType::getFieldID(uint64_t index)
const {
2500std::pair<uint64_t, uint64_t>
2501BaseTypeAliasType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2510 return LHSType::get(type.getContext(), type);
2513LogicalResult LHSType::verify(function_ref<InFlightDiagnostic()> emitError,
2515 if (type.containsAnalog())
2516 return emitError() <<
"lhs type cannot contain an AnalogType";
2518 return emitError() <<
"lhs type cannot contain a non-passive type";
2519 if (type.containsReference())
2520 return emitError() <<
"lhs type cannot contain a reference";
2521 if (type_isa<LHSType>(type))
2522 return emitError() <<
"lhs type cannot contain a lhs type";
2531auto RefType::get(
FIRRTLBaseType type,
bool forceable, SymbolRefAttr layer)
2533 return Base::get(type.getContext(), type, forceable, layer);
2536auto RefType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2539 if (!base.isPassive())
2540 return emitErrorFn() <<
"reference base type must be passive";
2541 if (forceable && base.containsConst())
2542 return emitErrorFn()
2543 <<
"forceable reference base type cannot contain const";
2548 auto rtp = getType().getRecursiveTypeProperties();
2551 rtp.isPassive =
false;
2559AnalogType AnalogType::get(mlir::MLIRContext *context) {
2560 return AnalogType::get(context, -1,
false);
2563AnalogType AnalogType::get(mlir::MLIRContext *context,
2564 std::optional<int32_t> width,
bool isConst) {
2565 return AnalogType::get(context, width ? *width : -1,
isConst);
2568LogicalResult AnalogType::verify(function_ref<InFlightDiagnostic()> emitError,
2569 int32_t widthOrSentinel,
bool isConst) {
2570 if (widthOrSentinel < -1)
2571 return emitError() <<
"invalid width";
2575int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2577AnalogType AnalogType::getConstType(
bool isConst)
const {
2580 return get(getContext(), getWidthOrSentinel(),
isConst);
2587ClockType ClockType::getConstType(
bool isConst)
const {
2597ResetType ResetType::getConstType(
bool isConst)
const {
2607AsyncResetType AsyncResetType::getConstType(
bool isConst)
const {
2618 using KeyTy = std::pair<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2622 auto name = key.first;
2623 auto elements = allocator.copyInto(key.second);
2626 SmallVector<uint64_t, 4> ids;
2635 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2657ClassType ClassType::get(FlatSymbolRefAttr name,
2658 ArrayRef<ClassElement> elements) {
2659 return get(name.getContext(), name, elements);
2662StringRef ClassType::getName()
const {
2663 return getNameAttr().getAttr().getValue();
2666FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2668ArrayRef<ClassElement> ClassType::getElements()
const {
2669 return getImpl()->elements;
2672const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2673 return getElement(index.getValue().getZExtValue());
2676const ClassElement &ClassType::getElement(
size_t index)
const {
2677 return getElements()[index];
2680std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2681 for (
const auto [i, e] :
llvm::enumerate(getElements()))
2682 if (fieldName == e.name)
2687void ClassType::printInterface(AsmPrinter &p)
const {
2691 for (
const auto &element : getElements()) {
2695 p.printKeywordOrString(element.name);
2696 p <<
": " << element.type;
2702uint64_t ClassType::getFieldID(uint64_t index)
const {
2703 return getImpl()->fieldIDs[index];
2706uint64_t ClassType::getIndexForFieldID(uint64_t fieldID)
const {
2707 assert(!getElements().
empty() &&
"Class must have >0 fields");
2708 auto fieldIDs = getImpl()->fieldIDs;
2709 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2710 return std::distance(fieldIDs.begin(), it);
2713std::pair<uint64_t, uint64_t>
2714ClassType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2717 return {index, fieldID - elementFieldID};
2720std::pair<Type, uint64_t>
2721ClassType::getSubTypeByFieldID(uint64_t fieldID)
const {
2725 auto subfieldType = getElement(subfieldIndex).type;
2726 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2727 return {subfieldType, subfieldID};
2730uint64_t ClassType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
2732std::pair<uint64_t, bool>
2733ClassType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2735 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2737 return std::make_pair(fieldID - childRoot,
2738 fieldID >= childRoot && fieldID <= rangeEnd);
2741ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2742 StringAttr className;
2743 if (parser.parseSymbolName(className))
2746 SmallVector<ClassElement> elements;
2747 if (parser.parseCommaSeparatedList(
2748 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
2750 Direction direction;
2751 if (succeeded(parser.parseOptionalKeyword(
"out")))
2752 direction = Direction::Out;
2753 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2754 direction = Direction::In;
2759 std::string keyword;
2760 if (parser.parseKeywordOrString(&keyword))
2762 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2766 if (parser.parseColonType(type))
2769 elements.emplace_back(name, type, direction);
2774 result = ClassType::get(FlatSymbolRefAttr::get(className), elements);
2782void FIRRTLDialect::registerTypes() {
2784#define GET_TYPEDEF_LIST
2785#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
2799 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
2800 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
2802 for (
auto &elt : bundle) {
2803 if (elt.isFlip && !ignoreFlip)
2804 return std::nullopt;
2807 return std::nullopt;
2812 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
2814 for (
auto &elt : fenum) {
2817 return std::nullopt;
2818 width = std::max(width, *w);
2820 return width + fenum.getTagWidth();
2822 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
2825 return std::nullopt;
2826 return *w * vector.getNumElements();
2829 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
2830 .Default([&](
auto t) {
return std::nullopt; });
2832 return getWidth(type);
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 getFieldID(BundleType type, unsigned index)
static unsigned getIndexForFieldID(BundleType type, unsigned fieldID)
static unsigned getMaxFieldID(FIRRTLBaseType type)
static InstancePath empty
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
FIRRTLBaseType getAnonymousType()
Return this type with any type alias types recursively removed from itself.
bool isResetType()
Return true if this is a valid "reset" type.
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
FIRRTLBaseType getPassiveType()
Return this type with any flip types recursively removed from itself.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
FIRRTLBaseType getWidthlessType()
Return this type with widths of all ground types removed.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
bool containsReference()
Return true if this is or contains a Reference type.
RecursiveTypeProperties getRecursiveTypeProperties() const
Return the recursive properties of the type, containing the isPassive, containsAnalog,...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
This is the common base class between SIntType and UIntType.
IntType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
Represents a limited word-length unsigned integer in SystemC as described in IEEE 1666-2011 ยง7....
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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.
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
static BundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
SmallVector< BundleType::BundleElement, 4 > elements
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
ArrayRef< uint64_t > fieldIDs
static ClassTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
ArrayRef< ClassElement > elements
ClassTypeStorage(FlatSymbolRefAttr name, ArrayRef< ClassElement > elements, ArrayRef< uint64_t > fieldIDs, uint64_t maxFieldID)
SmallVector< FEnumType::EnumElement, 4 > elements
static llvm::hash_code hashKey(const KeyTy &key)
bool operator==(const KeyTy &key) const
static FEnumTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FEnumTypeStorage(ArrayRef< FEnumType::EnumElement > elements, bool isConst)
std::pair< ArrayRef< FEnumType::EnumElement >, char > KeyTy
RecursiveTypeProperties recProps
FIRRTLBaseType anonymousType
bool operator==(const KeyTy &key) const
FIRRTLBaseTypeStorage(bool isConst)
static FIRRTLBaseTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
bool operator==(const KeyTy &key) const
FIRRTLBaseType elementType
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
FIRRTLBaseType passiveType
static FVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FIRRTLBaseType anonymousType
std::tuple< FIRRTLBaseType, size_t, char > KeyTy
FVectorTypeStorage(FIRRTLBaseType elementType, size_t numElements, bool isConst)
SmallVector< OpenBundleType::BundleElement, 4 > elements
bool operator==(const KeyTy &key) const
static OpenBundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
static llvm::hash_code hashKey(const KeyTy &key)
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
OpenBundleTypeStorage(ArrayRef< OpenBundleType::BundleElement > elements, bool isConst)
SmallVector< uint64_t, 4 > fieldIDs
std::pair< ArrayRef< OpenBundleType::BundleElement >, char > KeyTy
std::tuple< FIRRTLType, size_t, char > KeyTy
bool operator==(const KeyTy &key) const
RecursiveTypeProperties props
static OpenVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
OpenVectorTypeStorage(FIRRTLType elementType, size_t numElements, bool isConst)
WidthTypeStorage(int32_t width, bool isConst)
bool operator==(const KeyTy &key) const
std::pair< int32_t, char > KeyTy
static WidthTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)