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();
1329 using KeyTy = std::tuple<int32_t, char>;
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::tuple<ArrayRef<BundleType::BundleElement>,
char>;
1414 props{true, false, false,
isConst, false, false, false} {
1415 uint64_t fieldID = 0;
1418 auto type = element.type;
1419 auto eltInfo = type.getRecursiveTypeProperties();
1440 return llvm::hash_value(key);
1446 std::get<0>(key),
static_cast<bool>(std::get<1>(key)));
1460BundleType BundleType::get(MLIRContext *context,
1461 ArrayRef<BundleElement> elements,
bool isConst) {
1462 return Base::get(context, elements,
isConst);
1465auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1466 return getImpl()->elements;
1471 return getImpl()->props;
1476 auto *impl = getImpl();
1479 if (impl->passiveType)
1480 return impl->passiveType;
1483 if (impl->props.isPassive) {
1484 impl->passiveType = *
this;
1489 SmallVector<BundleType::BundleElement, 16> newElements;
1490 newElements.reserve(impl->elements.size());
1491 for (
auto &elt : impl->elements) {
1492 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1495 auto passiveType = BundleType::get(getContext(), newElements,
isConst());
1496 impl->passiveType = passiveType;
1500BundleType BundleType::getConstType(
bool isConst)
const {
1503 return get(getContext(), getElements(),
isConst);
1506BundleType BundleType::getAllConstDroppedType() {
1510 SmallVector<BundleElement> constDroppedElements(
1511 llvm::map_range(getElements(), [](BundleElement element) {
1512 element.type = element.type.getAllConstDroppedType();
1515 return get(getContext(), constDroppedElements,
false);
1518std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1519 for (
const auto &it :
llvm::enumerate(getElements())) {
1520 auto element = it.value();
1521 if (element.name == name) {
1522 return unsigned(it.index());
1525 return std::nullopt;
1528std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1529 for (
const auto &it :
llvm::enumerate(getElements())) {
1530 auto element = it.value();
1531 if (element.name.getValue() == name) {
1532 return unsigned(it.index());
1535 return std::nullopt;
1538StringAttr BundleType::getElementNameAttr(
size_t index) {
1539 assert(index < getNumElements() &&
1540 "index must be less than number of fields in bundle");
1541 return getElements()[index].name;
1544StringRef BundleType::getElementName(
size_t index) {
1545 return getElementNameAttr(index).getValue();
1548std::optional<BundleType::BundleElement>
1549BundleType::getElement(StringAttr name) {
1550 if (
auto maybeIndex = getElementIndex(name))
1551 return getElements()[*maybeIndex];
1552 return std::nullopt;
1555std::optional<BundleType::BundleElement>
1556BundleType::getElement(StringRef name) {
1557 if (
auto maybeIndex = getElementIndex(name))
1558 return getElements()[*maybeIndex];
1559 return std::nullopt;
1563BundleType::BundleElement BundleType::getElement(
size_t index) {
1564 assert(index < getNumElements() &&
1565 "index must be less than number of fields in bundle");
1566 return getElements()[index];
1570 auto element = getElement(name);
1575 auto element = getElement(name);
1580 assert(index < getNumElements() &&
1581 "index must be less than number of fields in bundle");
1582 return getElements()[index].type;
1585uint64_t BundleType::getFieldID(uint64_t index)
const {
1586 return getImpl()->fieldIDs[index];
1589uint64_t BundleType::getIndexForFieldID(uint64_t fieldID)
const {
1590 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1591 auto fieldIDs = getImpl()->fieldIDs;
1592 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1593 return std::distance(fieldIDs.begin(), it);
1596std::pair<uint64_t, uint64_t>
1597BundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1600 return {index, fieldID - elementFieldID};
1603std::pair<Type, uint64_t>
1604BundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1608 auto subfieldType = getElementType(subfieldIndex);
1609 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1610 return {subfieldType, subfieldID};
1613uint64_t BundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1615std::pair<uint64_t, bool>
1616BundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1618 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1620 return std::make_pair(fieldID - childRoot,
1621 fieldID >= childRoot && fieldID <= rangeEnd);
1624bool BundleType::isConst()
const {
return getImpl()->isConst; }
1626BundleType::ElementType
1627BundleType::getElementTypePreservingConst(
size_t index) {
1628 auto type = getElementType(index);
1629 return type.getConstType(type.isConst() ||
isConst());
1634 auto *impl = getImpl();
1637 if (impl->anonymousType)
1638 return impl->anonymousType;
1641 if (!impl->props.containsTypeAlias) {
1642 impl->anonymousType = *
this;
1648 SmallVector<BundleType::BundleElement, 16> newElements;
1649 newElements.reserve(impl->elements.size());
1650 for (
auto &elt : impl->elements)
1651 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1653 auto anonymousType = BundleType::get(getContext(), newElements,
isConst());
1654 impl->anonymousType = anonymousType;
1655 return anonymousType;
1658LogicalResult BundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1659 ArrayRef<BundleElement> elements,
1661 SmallPtrSet<StringAttr, 4> nameSet;
1662 for (
auto &element : elements) {
1663 if (!nameSet.insert(element.name).second)
1664 return emitErrorFn() <<
"duplicate field name " << element.name
1676 using KeyTy = std::tuple<ArrayRef<OpenBundleType::BundleElement>,
char>;
1681 props{true, false, false,
isConst, false, false, false},
1683 uint64_t fieldID = 0;
1686 auto type = element.type;
1687 auto eltInfo = type.getRecursiveTypeProperties();
1707 return llvm::hash_value(key);
1716 static_cast<bool>(std::get<1>(key)));
1719 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1731OpenBundleType OpenBundleType::get(MLIRContext *context,
1732 ArrayRef<BundleElement> elements,
1734 return Base::get(context, elements,
isConst);
1737auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1738 return getImpl()->elements;
1743 return getImpl()->props;
1746OpenBundleType OpenBundleType::getConstType(
bool isConst)
const {
1749 return get(getContext(), getElements(),
isConst);
1752std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1753 for (
const auto &it :
llvm::enumerate(getElements())) {
1754 auto element = it.value();
1755 if (element.name == name) {
1756 return unsigned(it.index());
1759 return std::nullopt;
1762std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1763 for (
const auto &it :
llvm::enumerate(getElements())) {
1764 auto element = it.value();
1765 if (element.name.getValue() == name) {
1766 return unsigned(it.index());
1769 return std::nullopt;
1772StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1773 assert(index < getNumElements() &&
1774 "index must be less than number of fields in bundle");
1775 return getElements()[index].name;
1778StringRef OpenBundleType::getElementName(
size_t index) {
1779 return getElementNameAttr(index).getValue();
1782std::optional<OpenBundleType::BundleElement>
1783OpenBundleType::getElement(StringAttr name) {
1784 if (
auto maybeIndex = getElementIndex(name))
1785 return getElements()[*maybeIndex];
1786 return std::nullopt;
1789std::optional<OpenBundleType::BundleElement>
1790OpenBundleType::getElement(StringRef name) {
1791 if (
auto maybeIndex = getElementIndex(name))
1792 return getElements()[*maybeIndex];
1793 return std::nullopt;
1797OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1798 assert(index < getNumElements() &&
1799 "index must be less than number of fields in bundle");
1800 return getElements()[index];
1803OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1804 auto element = getElement(name);
1808OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1809 auto element = getElement(name);
1813OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1814 assert(index < getNumElements() &&
1815 "index must be less than number of fields in bundle");
1816 return getElements()[index].type;
1819uint64_t OpenBundleType::getFieldID(uint64_t index)
const {
1820 return getImpl()->fieldIDs[index];
1823uint64_t OpenBundleType::getIndexForFieldID(uint64_t fieldID)
const {
1824 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1825 auto fieldIDs = getImpl()->fieldIDs;
1826 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1827 return std::distance(fieldIDs.begin(), it);
1830std::pair<uint64_t, uint64_t>
1831OpenBundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1834 return {index, fieldID - elementFieldID};
1837std::pair<Type, uint64_t>
1838OpenBundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1842 auto subfieldType = getElementType(subfieldIndex);
1843 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1844 return {subfieldType, subfieldID};
1847uint64_t OpenBundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1849std::pair<uint64_t, bool>
1850OpenBundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1852 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1854 return std::make_pair(fieldID - childRoot,
1855 fieldID >= childRoot && fieldID <= rangeEnd);
1858bool OpenBundleType::isConst()
const {
return getImpl()->isConst; }
1860OpenBundleType::ElementType
1861OpenBundleType::getElementTypePreservingConst(
size_t index) {
1862 auto type = getElementType(index);
1864 return TypeSwitch<FIRRTLType, ElementType>(type)
1865 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1866 return type.getConstType(type.isConst() ||
isConst());
1872OpenBundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1873 ArrayRef<BundleElement> elements,
bool isConst) {
1874 SmallPtrSet<StringAttr, 4> nameSet;
1875 for (
auto &element : elements) {
1876 if (!nameSet.insert(element.name).second)
1877 return emitErrorFn() <<
"duplicate field name " << element.name
1878 <<
" in openbundle";
1880 return emitErrorFn()
1881 <<
"'const' bundle cannot have references, but element "
1882 << element.name <<
" has type " << element.type;
1883 if (type_isa<LHSType>(element.type))
1884 return emitErrorFn() <<
"bundle element " << element.name
1885 <<
" cannot have a left-hand side type";
1897 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1915 static_cast<bool>(std::get<2>(key)));
1934 return getImpl()->elementType;
1937size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
1941 return getImpl()->props;
1946 auto *impl = getImpl();
1949 if (impl->passiveType)
1950 return impl->passiveType;
1953 if (impl->elementType.getRecursiveTypeProperties().isPassive)
1954 return impl->passiveType = *
this;
1957 auto passiveType = FVectorType::get(getElementType().
getPassiveType(),
1959 impl->passiveType = passiveType;
1963FVectorType FVectorType::getConstType(
bool isConst)
const {
1966 return get(getElementType(), getNumElements(),
isConst);
1969FVectorType FVectorType::getAllConstDroppedType() {
1972 return get(getElementType().getAllConstDroppedType(), getNumElements(),
1978 auto *impl = getImpl();
1980 if (impl->anonymousType)
1981 return impl->anonymousType;
1984 if (!impl->props.containsTypeAlias)
1985 return impl->anonymousType = *
this;
1988 auto anonymousType = FVectorType::get(getElementType().getAnonymousType(),
1990 impl->anonymousType = anonymousType;
1991 return anonymousType;
1994uint64_t FVectorType::getFieldID(uint64_t index)
const {
1998uint64_t FVectorType::getIndexForFieldID(uint64_t fieldID)
const {
1999 assert(fieldID &&
"fieldID must be at least 1");
2004std::pair<uint64_t, uint64_t>
2005FVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2008 return {index, fieldID - elementFieldID};
2011std::pair<Type, uint64_t>
2012FVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2018uint64_t FVectorType::getMaxFieldID()
const {
2019 return getNumElements() *
2023std::pair<uint64_t, bool>
2024FVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2028 return std::make_pair(fieldID - childRoot,
2029 fieldID >= childRoot && fieldID <= rangeEnd);
2032bool FVectorType::isConst()
const {
return getImpl()->isConst; }
2034FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
2035 auto type = getElementType();
2036 return type.getConstType(type.isConst() ||
isConst());
2044 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
2062 static_cast<bool>(std::get<2>(key)));
2077FIRRTLType OpenVectorType::getElementType()
const {
2078 return getImpl()->elementType;
2081size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
2085 return getImpl()->props;
2088OpenVectorType OpenVectorType::getConstType(
bool isConst)
const {
2091 return get(getElementType(), getNumElements(),
isConst);
2094uint64_t OpenVectorType::getFieldID(uint64_t index)
const {
2098uint64_t OpenVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2099 assert(fieldID &&
"fieldID must be at least 1");
2104std::pair<uint64_t, uint64_t>
2105OpenVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2108 return {index, fieldID - elementFieldID};
2111std::pair<Type, uint64_t>
2112OpenVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2118uint64_t OpenVectorType::getMaxFieldID()
const {
2120 return getNumElements() *
2124std::pair<uint64_t, bool>
2125OpenVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2129 return std::make_pair(fieldID - childRoot,
2130 fieldID >= childRoot && fieldID <= rangeEnd);
2133bool OpenVectorType::isConst()
const {
return getImpl()->isConst; }
2135OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2136 auto type = getElementType();
2138 return TypeSwitch<FIRRTLType, ElementType>(type)
2139 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2140 return type.getConstType(type.isConst() ||
isConst());
2146OpenVectorType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2150 return emitErrorFn() <<
"vector cannot be const with references";
2152 return emitErrorFn() <<
"vector cannot have a left-hand side type";
2161 using KeyTy = std::tuple<ArrayRef<FEnumType::EnumElement>,
char>;
2167 false,
false,
false};
2170 auto type = element.type;
2171 auto eltInfo = type.getRecursiveTypeProperties();
2173 props.containsTypeAlias |= eltInfo.containsTypeAlias;
2185 return llvm::hash_value(key);
2200FEnumType FEnumType::get(::mlir::MLIRContext *context,
2201 ArrayRef<EnumElement> elements,
bool isConst) {
2202 return Base::get(context, elements,
isConst);
2205ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2206 return getImpl()->elements;
2209FEnumType FEnumType::getConstType(
bool isConst)
const {
2210 return get(getContext(), getElements(),
isConst);
2213FEnumType FEnumType::getAllConstDroppedType() {
2217 SmallVector<EnumElement> constDroppedElements(
2218 llvm::map_range(getElements(), [](EnumElement element) {
2219 element.type = element.type.getAllConstDroppedType();
2222 return get(getContext(), constDroppedElements,
false);
2227 return getImpl()->recProps;
2230std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2231 for (
const auto &it :
llvm::enumerate(getElements())) {
2232 auto element = it.value();
2233 if (element.name == name) {
2234 return unsigned(it.index());
2237 return std::nullopt;
2240size_t FEnumType::getBitWidth() {
return getDataWidth() + getTagWidth(); }
2242size_t FEnumType::getDataWidth() {
return getImpl()->dataSize; }
2244size_t FEnumType::getTagWidth() {
2245 if (getElements().size() == 0)
2248 return cast<IntegerType>(getElements()[0].value.getType()).getWidth();
2251std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2252 for (
const auto &it :
llvm::enumerate(getElements())) {
2253 auto element = it.value();
2254 if (element.name.getValue() == name) {
2255 return unsigned(it.index());
2258 return std::nullopt;
2261StringAttr FEnumType::getElementNameAttr(
size_t index) {
2262 assert(index < getNumElements() &&
2263 "index must be less than number of fields in enum");
2264 return getElements()[index].name;
2267StringRef FEnumType::getElementName(
size_t index) {
2268 return getElementNameAttr(index).getValue();
2271IntegerAttr FEnumType::getElementValueAttr(
size_t index) {
2272 return getElements()[index].value;
2275APInt FEnumType::getElementValue(
size_t index) {
2276 return getElementValueAttr(index).getValue();
2280 return getElements()[index].type;
2283std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2284 if (
auto maybeIndex = getElementIndex(name))
2285 return getElements()[*maybeIndex];
2286 return std::nullopt;
2289std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2290 if (
auto maybeIndex = getElementIndex(name))
2291 return getElements()[*maybeIndex];
2292 return std::nullopt;
2296FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2297 assert(index < getNumElements() &&
2298 "index must be less than number of fields in enum");
2299 return getElements()[index];
2303 auto element = getElement(name);
2308 auto element = getElement(name);
2313 assert(index < getNumElements() &&
2314 "index must be less than number of fields in enum");
2315 return getElements()[index].type;
2318FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2319 auto type = getElementType(index);
2320 return type.getConstType(type.isConst() ||
isConst());
2323LogicalResult FEnumType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2324 ArrayRef<EnumElement> elements,
bool isConst) {
2326 IntegerAttr previous;
2327 SmallPtrSet<Attribute, 4> nameSet;
2329 for (
auto &elt : elements) {
2330 auto r = elt.type.getRecursiveTypeProperties();
2332 return emitErrorFn() <<
"enum field " << elt.name <<
" not passive";
2333 if (r.containsAnalog)
2334 return emitErrorFn() <<
"enum field " << elt.name <<
" contains analog";
2335 if (r.hasUninferredWidth)
2336 return emitErrorFn() <<
"enum field " << elt.name
2337 <<
" has uninferred width";
2338 if (r.hasUninferredReset)
2339 return emitErrorFn() <<
"enum field " << elt.name
2340 <<
" has uninferred reset";
2341 if (r.containsConst && !
isConst)
2342 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2344 if (!nameSet.insert(elt.name).second)
2345 return emitErrorFn() <<
"duplicate variant name " << elt.name
2349 previous = elt.value;
2352 auto current = elt.value;
2353 if (previous.getType() != current.getType())
2354 return emitErrorFn() <<
"enum variant " << elt.name <<
" has type"
2355 << current.getType()
2356 <<
" which is different than previous variant "
2357 << previous.getType();
2359 if (previous.getValue().getBitWidth() != current.getValue().getBitWidth())
2360 return emitErrorFn() <<
"enum variant " << elt.name <<
" has bitwidth"
2361 << current.getValue().getBitWidth()
2362 <<
" which is different than previous variant "
2363 << previous.getValue().getBitWidth();
2364 if (previous.getValue().uge(current.getValue()))
2365 return emitErrorFn()
2366 <<
"enum variant " << elt.name <<
" has value " << current
2367 <<
" which is not greater than previous variant " << previous;
2376 auto *impl = getImpl();
2378 if (impl->anonymousType)
2379 return impl->anonymousType;
2381 if (!impl->recProps.containsTypeAlias)
2382 return impl->anonymousType = *
this;
2384 SmallVector<FEnumType::EnumElement, 4> elements;
2386 for (
auto element : getElements())
2388 {element.name, element.value, element.type.getAnonymousType()});
2389 return impl->anonymousType = FEnumType::get(getContext(), elements);
2398 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2409 return llvm::hash_value(key);
2422auto BaseTypeAliasType::get(StringAttr name,
FIRRTLBaseType innerType)
2423 -> BaseTypeAliasType {
2424 return Base::get(name.getContext(), name, innerType);
2427auto BaseTypeAliasType::getName() const -> StringAttr {
2428 return getImpl()->name;
2432 return getImpl()->innerType;
2436 auto *impl = getImpl();
2437 if (impl->anonymousType)
2438 return impl->anonymousType;
2439 return impl->anonymousType = getInnerType().getAnonymousType();
2447 auto rtp = getInnerType().getRecursiveTypeProperties();
2455BaseTypeAliasType::getModifiedType(
FIRRTLBaseType newInnerType)
const {
2456 if (newInnerType == getInnerType())
2458 return newInnerType;
2463 return getModifiedType(getInnerType().getAllConstDroppedType());
2467 return getModifiedType(getInnerType().getConstType(
isConst));
2470std::pair<Type, uint64_t>
2471BaseTypeAliasType::getSubTypeByFieldID(uint64_t fieldID)
const {
2475uint64_t BaseTypeAliasType::getMaxFieldID()
const {
2479std::pair<uint64_t, bool>
2480BaseTypeAliasType::projectToChildFieldID(uint64_t fieldID,
2481 uint64_t index)
const {
2485uint64_t BaseTypeAliasType::getIndexForFieldID(uint64_t fieldID)
const {
2489uint64_t BaseTypeAliasType::getFieldID(uint64_t index)
const {
2493std::pair<uint64_t, uint64_t>
2494BaseTypeAliasType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2503 return LHSType::get(type.getContext(), type);
2506LogicalResult LHSType::verify(function_ref<InFlightDiagnostic()> emitError,
2508 if (type.containsAnalog())
2509 return emitError() <<
"lhs type cannot contain an AnalogType";
2511 return emitError() <<
"lhs type cannot contain a non-passive type";
2512 if (type.containsReference())
2513 return emitError() <<
"lhs type cannot contain a reference";
2514 if (type_isa<LHSType>(type))
2515 return emitError() <<
"lhs type cannot contain a lhs type";
2524auto RefType::get(
FIRRTLBaseType type,
bool forceable, SymbolRefAttr layer)
2526 return Base::get(type.getContext(), type, forceable, layer);
2529auto RefType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2532 if (!base.isPassive())
2533 return emitErrorFn() <<
"reference base type must be passive";
2534 if (forceable && base.containsConst())
2535 return emitErrorFn()
2536 <<
"forceable reference base type cannot contain const";
2541 auto rtp = getType().getRecursiveTypeProperties();
2544 rtp.isPassive =
false;
2552AnalogType AnalogType::get(mlir::MLIRContext *context) {
2553 return AnalogType::get(context, -1,
false);
2556AnalogType AnalogType::get(mlir::MLIRContext *context,
2557 std::optional<int32_t> width,
bool isConst) {
2558 return AnalogType::get(context, width ? *width : -1,
isConst);
2561LogicalResult AnalogType::verify(function_ref<InFlightDiagnostic()> emitError,
2562 int32_t widthOrSentinel,
bool isConst) {
2563 if (widthOrSentinel < -1)
2564 return emitError() <<
"invalid width";
2568int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2570AnalogType AnalogType::getConstType(
bool isConst)
const {
2573 return get(getContext(), getWidthOrSentinel(),
isConst);
2580ClockType ClockType::getConstType(
bool isConst)
const {
2590ResetType ResetType::getConstType(
bool isConst)
const {
2600AsyncResetType AsyncResetType::getConstType(
bool isConst)
const {
2611 using KeyTy = std::tuple<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2615 auto name = std::get<0>(key);
2616 auto elements = allocator.copyInto(std::get<1>(key));
2619 SmallVector<uint64_t, 4> ids;
2628 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2650ClassType ClassType::get(FlatSymbolRefAttr name,
2651 ArrayRef<ClassElement> elements) {
2652 return get(name.getContext(), name, elements);
2655StringRef ClassType::getName()
const {
2656 return getNameAttr().getAttr().getValue();
2659FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2661ArrayRef<ClassElement> ClassType::getElements()
const {
2662 return getImpl()->elements;
2665const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2666 return getElement(index.getValue().getZExtValue());
2669const ClassElement &ClassType::getElement(
size_t index)
const {
2670 return getElements()[index];
2673std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2674 for (
const auto [i, e] :
llvm::enumerate(getElements()))
2675 if (fieldName == e.name)
2680void ClassType::printInterface(AsmPrinter &p)
const {
2684 for (
const auto &element : getElements()) {
2688 p.printKeywordOrString(element.name);
2689 p <<
": " << element.type;
2695uint64_t ClassType::getFieldID(uint64_t index)
const {
2696 return getImpl()->fieldIDs[index];
2699uint64_t ClassType::getIndexForFieldID(uint64_t fieldID)
const {
2700 assert(!getElements().
empty() &&
"Class must have >0 fields");
2701 auto fieldIDs = getImpl()->fieldIDs;
2702 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2703 return std::distance(fieldIDs.begin(), it);
2706std::pair<uint64_t, uint64_t>
2707ClassType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2710 return {index, fieldID - elementFieldID};
2713std::pair<Type, uint64_t>
2714ClassType::getSubTypeByFieldID(uint64_t fieldID)
const {
2718 auto subfieldType = getElement(subfieldIndex).type;
2719 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2720 return {subfieldType, subfieldID};
2723uint64_t ClassType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
2725std::pair<uint64_t, bool>
2726ClassType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2728 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2730 return std::make_pair(fieldID - childRoot,
2731 fieldID >= childRoot && fieldID <= rangeEnd);
2734ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2735 StringAttr className;
2736 if (parser.parseSymbolName(className))
2739 SmallVector<ClassElement> elements;
2740 if (parser.parseCommaSeparatedList(
2741 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
2743 Direction direction;
2744 if (succeeded(parser.parseOptionalKeyword(
"out")))
2745 direction = Direction::Out;
2746 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2747 direction = Direction::In;
2752 std::string keyword;
2753 if (parser.parseKeywordOrString(&keyword))
2755 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2759 if (parser.parseColonType(type))
2762 elements.emplace_back(name, type, direction);
2767 result = ClassType::get(FlatSymbolRefAttr::get(className), elements);
2775void FIRRTLDialect::registerTypes() {
2777#define GET_TYPEDEF_LIST
2778#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
2792 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
2793 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
2795 for (
auto &elt : bundle) {
2796 if (elt.isFlip && !ignoreFlip)
2797 return std::nullopt;
2800 return std::nullopt;
2805 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
2807 for (
auto &elt : fenum) {
2810 return std::nullopt;
2811 width = std::max(width, *w);
2813 return width + fenum.getTagWidth();
2815 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
2818 return std::nullopt;
2819 return *w * vector.getNumElements();
2822 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
2823 .Default([&](
auto t) {
return std::nullopt; });
2825 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)
std::tuple< ArrayRef< BundleType::BundleElement >, char > KeyTy
SmallVector< BundleType::BundleElement, 4 > elements
static llvm::hash_code hashKey(const KeyTy &key)
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
BundleTypeStorage(ArrayRef< BundleType::BundleElement > elements, bool isConst)
bool operator==(const KeyTy &key) const
SmallVector< uint64_t, 4 > fieldIDs
bool operator==(const KeyTy &key) const
ArrayRef< uint64_t > fieldIDs
static ClassTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
std::tuple< FlatSymbolRefAttr, ArrayRef< ClassElement > > KeyTy
ArrayRef< ClassElement > elements
ClassTypeStorage(FlatSymbolRefAttr name, ArrayRef< ClassElement > elements, ArrayRef< uint64_t > fieldIDs, uint64_t maxFieldID)
SmallVector< FEnumType::EnumElement, 4 > elements
static llvm::hash_code hashKey(const KeyTy &key)
bool operator==(const KeyTy &key) const
static FEnumTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FEnumTypeStorage(ArrayRef< FEnumType::EnumElement > elements, bool isConst)
RecursiveTypeProperties recProps
FIRRTLBaseType anonymousType
std::tuple< ArrayRef< FEnumType::EnumElement >, char > KeyTy
bool operator==(const KeyTy &key) const
FIRRTLBaseTypeStorage(bool isConst)
static FIRRTLBaseTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
bool operator==(const KeyTy &key) const
FIRRTLBaseType elementType
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
FIRRTLBaseType passiveType
static FVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
FIRRTLBaseType anonymousType
std::tuple< FIRRTLBaseType, size_t, char > KeyTy
FVectorTypeStorage(FIRRTLBaseType elementType, size_t numElements, bool isConst)
SmallVector< OpenBundleType::BundleElement, 4 > elements
bool operator==(const KeyTy &key) const
static OpenBundleTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
static llvm::hash_code hashKey(const KeyTy &key)
RecursiveTypeProperties props
This holds the bits for the type's recursive properties, and can hold a pointer to a passive version ...
OpenBundleTypeStorage(ArrayRef< OpenBundleType::BundleElement > elements, bool isConst)
SmallVector< uint64_t, 4 > fieldIDs
std::tuple< ArrayRef< OpenBundleType::BundleElement >, char > KeyTy
std::tuple< FIRRTLType, size_t, char > KeyTy
bool operator==(const KeyTy &key) const
RecursiveTypeProperties props
static OpenVectorTypeStorage * construct(TypeStorageAllocator &allocator, KeyTy key)
OpenVectorTypeStorage(FIRRTLType elementType, size_t numElements, bool isConst)
WidthTypeStorage(int32_t width, bool isConst)
std::tuple< int32_t, char > KeyTy
bool operator==(const KeyTy &key) const
static WidthTypeStorage * construct(TypeStorageAllocator &allocator, const KeyTy &key)