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 .Default([&](
auto) { anyFailed =
true; });
170 return failure(anyFailed);
181 assert(
false &&
"type to print unknown to FIRRTL dialect");
216 const char constPrefix[] =
"const.";
217 if (name.starts_with(constPrefix)) {
219 name = name.drop_front(std::size(constPrefix) - 1);
222 auto *context = parser.getContext();
224 return result = ClockType::get(context,
isConst), success();
226 return result = ResetType::get(context,
isConst), success();
227 if (name ==
"asyncreset")
228 return result = AsyncResetType::get(context,
isConst), success();
230 if (name ==
"sint" || name ==
"uint" || name ==
"analog") {
233 if (!parser.parseOptionalLess()) {
234 if (parser.parseInteger(width) || parser.parseGreater())
238 return parser.emitError(parser.getNameLoc(),
"unknown width"),
243 result = SIntType::get(context, width,
isConst);
244 else if (name ==
"uint")
245 result = UIntType::get(context, width,
isConst);
248 result = AnalogType::get(context, width,
isConst);
253 if (name ==
"bundle") {
254 SmallVector<BundleType::BundleElement, 4> elements;
256 auto parseBundleElement = [&]() -> ParseResult {
261 if (failed(parser.parseKeywordOrString(&nameStr)))
265 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
269 elements.push_back({StringAttr::get(context, name), isFlip, type});
273 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
277 result = parser.getChecked<BundleType>(context, elements,
isConst);
278 return failure(!result);
280 if (name ==
"openbundle") {
281 SmallVector<OpenBundleType::BundleElement, 4> elements;
283 auto parseBundleElement = [&]() -> ParseResult {
288 if (failed(parser.parseKeywordOrString(&nameStr)))
292 bool isFlip = succeeded(parser.parseOptionalKeyword(
"flip"));
296 elements.push_back({StringAttr::get(context, name), isFlip, type});
300 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
304 result = parser.getChecked<OpenBundleType>(context, elements,
isConst);
305 return failure(!result);
308 if (name ==
"enum") {
309 SmallVector<StringAttr> names;
310 SmallVector<APInt> values;
311 SmallVector<FIRRTLBaseType> types;
312 auto parseEnumElement = [&]() -> ParseResult {
315 if (failed(parser.parseKeywordOrString(&nameStr)))
317 names.push_back(StringAttr::get(context, nameStr));
323 if (succeeded(parser.parseOptionalEqual())) {
324 if (parser.parseInteger(value))
326 }
else if (values.empty()) {
332 auto &prev = values.back();
333 if (prev.isMaxValue())
334 value = prev.zext(prev.getBitWidth() + 1);
339 values.push_back(std::move(value));
343 if (succeeded(parser.parseOptionalColon())) {
347 type = UIntType::get(parser.getContext(), 0);
349 types.push_back(type);
354 if (parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::LessGreater,
359 unsigned bitwidth = 0;
360 for (
auto &value : values)
361 bitwidth = std::max(bitwidth, value.getActiveBits());
362 auto tagType = IntegerType::get(context, bitwidth, IntegerType::Unsigned);
364 SmallVector<FEnumType::EnumElement, 4> elements;
365 for (
auto [name, value, type] : llvm::zip(names, values, types)) {
366 auto tagValue = value.zextOrTrunc(bitwidth);
367 elements.push_back({name, IntegerAttr::get(tagType, tagValue), type});
370 if (failed(FEnumType::verify(
371 [&]() {
return parser.emitError(parser.getNameLoc()); }, elements,
375 result = parser.getChecked<FEnumType>(context, elements,
isConst);
376 return failure(!result);
379 if (name ==
"vector") {
384 parser.parseComma() || parser.parseInteger(width) ||
385 parser.parseGreater())
390 if (name ==
"openvector") {
395 parser.parseComma() || parser.parseInteger(width) ||
396 parser.parseGreater())
401 return failure(!result);
405 if (name ==
"ref" || name ==
"probe") {
412 if (parser.parseOptionalComma().succeeded())
413 if (parser.parseOptionalAttribute(layer).value())
414 return parser.emitError(parser.getNameLoc(),
415 "expected symbol reference");
416 if (parser.parseGreater())
419 if (failed(RefType::verify(
420 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
424 return result = RefType::get(type,
false, layer), success();
429 parser.parseGreater())
431 if (!isa<FIRRTLBaseType>(type))
432 return parser.emitError(parser.getNameLoc(),
"expected base type");
433 result = parser.getChecked<LHSType>(context, cast<FIRRTLBaseType>(type));
434 return failure(!result);
436 if (name ==
"rwprobe") {
441 if (parser.parseOptionalComma().succeeded())
442 if (parser.parseOptionalAttribute(layer).value())
443 return parser.emitError(parser.getNameLoc(),
444 "expected symbol reference");
445 if (parser.parseGreater())
448 if (failed(RefType::verify(
449 [&]() {
return parser.emitError(parser.getNameLoc()); }, type,
true,
453 return result = RefType::get(type,
true, layer), success();
455 if (name ==
"class") {
457 return parser.emitError(parser.getNameLoc(),
"classes cannot be const");
459 if (parser.parseLess() || ClassType::parseInterface(parser, classType) ||
460 parser.parseGreater())
465 if (name ==
"anyref") {
467 return parser.emitError(parser.getNameLoc(),
"any refs cannot be const");
469 result = AnyRefType::get(parser.getContext());
472 if (name ==
"string") {
474 parser.emitError(parser.getNameLoc(),
"strings cannot be const");
477 result = StringType::get(parser.getContext());
480 if (name ==
"integer") {
482 parser.emitError(parser.getNameLoc(),
"bigints cannot be const");
485 result = FIntegerType::get(parser.getContext());
488 if (name ==
"bool") {
490 parser.emitError(parser.getNameLoc(),
"bools cannot be const");
493 result = BoolType::get(parser.getContext());
496 if (name ==
"double") {
498 parser.emitError(parser.getNameLoc(),
"doubles cannot be const");
501 result = DoubleType::get(parser.getContext());
504 if (name ==
"list") {
506 parser.emitError(parser.getNameLoc(),
"lists cannot be const");
511 parser.parseGreater())
513 result = parser.getChecked<ListType>(context,
elementType);
518 if (name ==
"path") {
520 parser.emitError(parser.getNameLoc(),
"path cannot be const");
523 result = PathType::get(parser.getContext());
526 if (name ==
"alias") {
529 if (parser.parseLess() || parser.parseKeyword(&name) ||
531 parser.parseGreater())
535 BaseTypeAliasType::get(StringAttr::get(context, name), type),
538 if (name ==
"fstring") {
539 return result = FStringType::get(context), success();
550static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
553 if (parseResult.has_value())
554 return parseResult.value();
557 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL dialect type: \"")
550static ParseResult
parseType(Type &result, StringRef name, AsmParser &parser) {
…}
569 if (failed(
parseType(type, name, parser)))
571 result = type_dyn_cast<FIRRTLType>(type);
574 parser.emitError(parser.getNameLoc(),
"unknown FIRRTL type: \"")
584 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type)) {
588 parser.emitError(parser.getNameLoc(),
"expected base type, found ") << type;
597 if (
auto prop = type_dyn_cast<PropertyType>(type)) {
601 parser.emitError(parser.getNameLoc(),
"expected property type, found ")
614 if (parser.parseKeyword(&name))
624 if (parser.parseKeyword(&name))
634 if (parser.parseKeyword(&name))
645void FIRRTLDialect::printType(Type type, DialectAsmPrinter &os)
const {
650Type FIRRTLDialect::parseType(DialectAsmParser &parser)
const {
653 if (parser.parseKeyword(&name) ||
::parseType(result, name, parser))
696bool FIRRTLType::isGround() {
697 return TypeSwitch<FIRRTLType, bool>(*
this)
698 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
699 AnalogType>([](Type) {
return true; })
700 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType>(
701 [](Type) {
return false; })
702 .Case<BaseTypeAliasType>([](BaseTypeAliasType alias) {
703 return alias.getAnonymousType().isGround();
706 .Case<PropertyType, RefType>([](Type) {
return false; })
708 llvm_unreachable(
"unknown FIRRTL type");
714 return TypeSwitch<FIRRTLType, bool>(*
this)
716 [](
auto type) {
return type.isConst(); })
723 return TypeSwitch<FIRRTLType, RecursiveTypeProperties>(*
this)
724 .Case<ClockType, ResetType, AsyncResetType>([](
FIRRTLBaseType type) {
731 firrtl::type_isa<ResetType>(type)};
733 .Case<SIntType, UIntType>([](
auto type) {
735 true,
false,
false, type.isConst(),
false, !type.hasWidth(),
false};
737 .Case<AnalogType>([](
auto type) {
739 true,
false,
true, type.isConst(),
false, !type.hasWidth(),
false};
741 .Case<BundleType, FVectorType, FEnumType, OpenBundleType, OpenVectorType,
742 RefType, BaseTypeAliasType>(
743 [](
auto type) {
return type.getRecursiveTypeProperties(); })
744 .Case<PropertyType>([](
auto type) {
746 false,
false,
false};
749 [](
auto type) {
return type.getType().getRecursiveTypeProperties(); })
750 .Case<FStringType>([](
auto type) {
752 false,
false,
false};
755 llvm_unreachable(
"unknown FIRRTL type");
762 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
763 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
764 AnalogType>([&](Type) {
return *
this; })
765 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
766 [](
auto type) {
return type.getAnonymousType(); })
768 llvm_unreachable(
"unknown FIRRTL type");
775 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
776 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
777 AnalogType, FEnumType>([&](Type) {
return *
this; })
778 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
779 [](
auto type) {
return type.getPassiveType(); })
781 llvm_unreachable(
"unknown FIRRTL type");
788 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
789 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
790 UIntType, BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
791 [&](
auto type) {
return type.getConstType(
isConst); })
793 llvm_unreachable(
"unknown FIRRTL type");
800 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
801 .Case<ClockType, ResetType, AsyncResetType, AnalogType, SIntType,
802 UIntType>([&](
auto type) {
return type.getConstType(
false); })
803 .Case<BundleType, FVectorType, FEnumType, BaseTypeAliasType>(
804 [&](
auto type) {
return type.getAllConstDroppedType(); })
806 llvm_unreachable(
"unknown FIRRTL type");
814 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
815 .Case<ClockType, ResetType, AsyncResetType, SIntType, UIntType,
816 AnalogType, FEnumType>([&](Type) {
817 return UIntType::get(this->getContext(), 1, this->
isConst());
819 .Case<BundleType>([&](BundleType bundleType) {
820 SmallVector<BundleType::BundleElement, 4> newElements;
821 newElements.reserve(bundleType.getElements().size());
822 for (
auto elt : bundleType)
823 newElements.push_back(
824 {elt.name,
false , elt.type.getMaskType()});
825 return BundleType::get(this->getContext(), newElements,
826 bundleType.isConst());
828 .Case<FVectorType>([](FVectorType vectorType) {
829 return FVectorType::get(vectorType.getElementType().getMaskType(),
830 vectorType.getNumElements(),
831 vectorType.isConst());
833 .Case<BaseTypeAliasType>([](BaseTypeAliasType base) {
834 return base.getModifiedType(base.getInnerType().getMaskType());
837 llvm_unreachable(
"unknown FIRRTL type");
845 return TypeSwitch<FIRRTLBaseType, FIRRTLBaseType>(*
this)
846 .Case<ClockType, ResetType, AsyncResetType>([](
auto a) {
return a; })
847 .Case<UIntType, SIntType, AnalogType>(
848 [&](
auto a) {
return a.get(this->getContext(), -1, a.isConst()); })
849 .Case<BundleType>([&](
auto a) {
850 SmallVector<BundleType::BundleElement, 4> newElements;
851 newElements.reserve(a.getElements().size());
853 newElements.push_back(
854 {elt.name, elt.isFlip, elt.type.getWidthlessType()});
855 return BundleType::get(this->getContext(), newElements, a.isConst());
857 .Case<FVectorType>([](
auto a) {
858 return FVectorType::get(a.getElementType().getWidthlessType(),
859 a.getNumElements(), a.isConst());
861 .Case<FEnumType>([&](FEnumType a) {
862 SmallVector<FEnumType::EnumElement, 4> newElements;
863 newElements.reserve(a.getNumElements());
865 newElements.push_back(
866 {elt.name, elt.value, elt.type.getWidthlessType()});
867 return FEnumType::get(this->getContext(), newElements, a.isConst());
869 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
870 return type.getModifiedType(type.getInnerType().getWidthlessType());
873 llvm_unreachable(
"unknown FIRRTL type");
883 return TypeSwitch<FIRRTLBaseType, int32_t>(*
this)
884 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
885 .Case<SIntType, UIntType>(
888 [](AnalogType analogType) {
return analogType.getWidthOrSentinel(); })
889 .Case<FEnumType>([&](FEnumType fenum) {
return fenum.getBitWidth(); })
890 .Case<BundleType, FVectorType>([](Type) {
return -2; })
891 .Case<BaseTypeAliasType>([](BaseTypeAliasType type) {
893 return type.getAnonymousType().getBitWidthOrSentinel();
896 llvm_unreachable(
"unknown FIRRTL type");
905 return TypeSwitch<FIRRTLType, bool>(*
this)
906 .Case<ResetType, AsyncResetType>([](Type) {
return true; })
908 [](UIntType a) {
return !a.hasWidth() || a.getWidth() == 1; })
909 .Case<BaseTypeAliasType>(
910 [](
auto type) {
return type.getInnerType().isResetType(); })
911 .Default([](Type) {
return false; });
915 return TypeSwitch<Type, bool>(type)
917 [](
auto base) {
return base.isConst(); })
922 return TypeSwitch<Type, bool>(type)
924 [](
auto base) {
return base.containsConst(); })
931 .
Case<BundleType>([&](
auto bundle) {
932 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
933 auto elt = bundle.getElement(i);
937 return bundle.getNumElements() == 0;
939 .Case<FVectorType>([&](
auto vector) {
940 if (vector.getNumElements() == 0)
944 .Case<FIRRTLBaseType>([](
auto groundType) {
947 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
948 .Default([](
auto) {
return false; });
958 BundleType::BundleElement srcElement,
959 bool destOuterTypeIsConst,
960 bool srcOuterTypeIsConst,
961 bool requiresSameWidth) {
962 if (destElement.name != srcElement.name)
964 if (destElement.isFlip != srcElement.isFlip)
967 if (destElement.isFlip) {
968 std::swap(destElement, srcElement);
969 std::swap(destOuterTypeIsConst, srcOuterTypeIsConst);
973 destOuterTypeIsConst, srcOuterTypeIsConst,
982 bool destOuterTypeIsConst,
983 bool srcOuterTypeIsConst,
984 bool requireSameWidths) {
985 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
986 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
989 if (!destType || !srcType)
990 return destFType == srcFType;
992 bool srcIsConst = srcOuterTypeIsConst || srcFType.
isConst();
993 bool destIsConst = destOuterTypeIsConst || destFType.
isConst();
996 auto destVectorType = type_dyn_cast<FVectorType>(destType);
997 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
998 if (destVectorType && srcVectorType)
999 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1001 srcVectorType.getElementType(), destIsConst,
1002 srcIsConst, requireSameWidths);
1006 auto destBundleType = type_dyn_cast<BundleType>(destType);
1007 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1008 if (destBundleType && srcBundleType) {
1009 auto destElements = destBundleType.getElements();
1010 auto srcElements = srcBundleType.getElements();
1011 size_t numDestElements = destElements.size();
1012 if (numDestElements != srcElements.size())
1015 for (
size_t i = 0; i < numDestElements; ++i) {
1016 auto destElement = destElements[i];
1017 auto srcElement = srcElements[i];
1019 srcIsConst, requireSameWidths))
1027 auto dstEnumType = type_dyn_cast<FEnumType>(destType);
1028 auto srcEnumType = type_dyn_cast<FEnumType>(srcType);
1030 if (dstEnumType && srcEnumType) {
1031 if (dstEnumType.getNumElements() != srcEnumType.getNumElements())
1034 for (
const auto &[dst, src] : llvm::zip(dstEnumType, srcEnumType)) {
1036 if (dst.name != src.name)
1048 if (destIsConst && !srcIsConst)
1052 if (firrtl::type_isa<ResetType>(destType))
1053 return srcType.isResetType();
1056 if (firrtl::type_isa<ResetType>(srcType))
1057 return destType.isResetType();
1061 if (!requireSameWidths || destType.getBitWidthOrSentinel() == -1)
1062 srcType = srcType.getWidthlessType();
1063 if (!requireSameWidths || srcType.getBitWidthOrSentinel() == -1)
1064 destType = destType.getWidthlessType();
1067 return destType.getConstType(
false) == srcType.getConstType(
false);
1072 bool srcOuterTypeIsConst) {
1074 if (destFType == srcFType)
1077 auto destType = type_dyn_cast<FIRRTLBaseType>(destFType);
1078 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
1081 if (!destType || !srcType)
1085 if (!destType.isPassive() || !srcType.isPassive())
1088 bool srcIsConst = srcType.isConst() || srcOuterTypeIsConst;
1091 if (destType.isConst() && !srcIsConst)
1096 auto destVectorType = type_dyn_cast<FVectorType>(destType);
1097 auto srcVectorType = type_dyn_cast<FVectorType>(srcType);
1098 if (destVectorType && srcVectorType)
1099 return destVectorType.getNumElements() == srcVectorType.getNumElements() &&
1101 srcVectorType.getElementType(), srcIsConst);
1102 if (destVectorType != srcVectorType)
1107 auto destBundleType = type_dyn_cast<BundleType>(destType);
1108 auto srcBundleType = type_dyn_cast<BundleType>(srcType);
1109 if (destBundleType && srcBundleType) {
1110 auto destElements = destBundleType.getElements();
1111 auto srcElements = srcBundleType.getElements();
1112 size_t numDestElements = destElements.size();
1113 if (numDestElements != srcElements.size())
1116 return llvm::all_of_zip(
1117 destElements, srcElements,
1118 [&](
const auto &destElement,
const auto &srcElement) {
1119 return destElement.name == srcElement.name &&
1124 if (destBundleType != srcBundleType)
1129 return destType == srcType.getConstType(destType.isConst());
1133 auto dstRefType = type_dyn_cast<RefType>(dstType);
1134 auto srcRefType = type_dyn_cast<RefType>(srcType);
1135 if (!dstRefType || !srcRefType)
1137 if (dstRefType == srcRefType)
1139 if (dstRefType.getForceable() && !srcRefType.getForceable())
1151 bool srcOuterTypeIsConst) ->
bool {
1157 assert(dest.isPassive() && src.isPassive());
1159 bool srcIsConst = src.isConst() || srcOuterTypeIsConst;
1162 if (dest.isConst() && !srcIsConst)
1168 if (
auto destVectorType = type_dyn_cast<FVectorType>(dest)) {
1169 auto srcVectorType = type_dyn_cast<FVectorType>(src);
1170 return srcVectorType &&
1171 destVectorType.getNumElements() ==
1172 srcVectorType.getNumElements() &&
1173 f(f, destVectorType.getElementType(),
1174 srcVectorType.getElementType(), srcIsConst);
1177 if (
auto destBundleType = type_dyn_cast<BundleType>(dest)) {
1178 auto srcBundleType = type_dyn_cast<BundleType>(src);
1182 auto destElements = destBundleType.getElements();
1183 auto srcElements = srcBundleType.getElements();
1185 return destElements.size() == srcElements.size() &&
1187 destElements, srcElements,
1188 [&](
const auto &destElement,
const auto &srcElement) {
1189 return destElement.name == srcElement.name &&
1190 f(f, destElement.type, srcElement.type, srcIsConst);
1194 if (
auto destEnumType = type_dyn_cast<FEnumType>(dest)) {
1195 auto srcEnumType = type_dyn_cast<FEnumType>(src);
1198 auto destElements = destEnumType.getElements();
1199 auto srcElements = srcEnumType.getElements();
1201 return destElements.size() == srcElements.size() &&
1203 destElements, srcElements,
1204 [&](
const auto &destElement,
const auto &srcElement) {
1205 return destElement.name == srcElement.name &&
1206 f(f, destElement.type, srcElement.type, srcIsConst);
1211 if (type_isa<ResetType>(dest))
1212 return src.isResetType();
1216 src = src.getConstType(dest.isConst());
1219 if (dest.getBitWidthOrSentinel() == -1)
1220 src = src.getWidthlessType();
1225 return recurse(recurse, dstRefType.getType(), srcRefType.getType(),
false);
1232 return TypeSwitch<FIRRTLBaseType, bool>(dstType)
1233 .Case<BundleType>([&](
auto dstBundle) {
1234 auto srcBundle = type_cast<BundleType>(srcType);
1235 for (
size_t i = 0, n = dstBundle.getNumElements(); i < n; ++i) {
1236 auto srcElem = srcBundle.getElement(i);
1237 auto dstElem = dstBundle.getElement(i);
1238 if (dstElem.isFlip) {
1248 .Case<FVectorType>([&](
auto vector) {
1250 type_cast<FVectorType>(srcType).getElementType());
1252 .Default([&](
auto dstGround) {
1255 return destWidth <= -1 || srcWidth <= -1 || destWidth >= srcWidth;
1266 if (
auto destBaseType = type_dyn_cast<FIRRTLBaseType>(lhs))
1267 if (
auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(rhs))
1270 if (
auto destRefType = type_dyn_cast<RefType>(lhs))
1271 if (
auto srcRefType = type_dyn_cast<RefType>(rhs))
1273 srcRefType.getType());
1281 return type_cast<FIRRTLBaseType>(anyBaseFIRRTLType).getPassiveType();
1285 return llvm::TypeSwitch<Type, bool>(type)
1287 return !type.containsReference() &&
1288 (!type.isPassive() || type.containsAnalog());
1300 int32_t widthOrSentinel,
bool isConst) {
1302 return SIntType::get(context, widthOrSentinel,
isConst);
1303 return UIntType::get(context, widthOrSentinel,
isConst);
1307 if (
auto sintType = type_dyn_cast<SIntType>(*
this))
1308 return sintType.getWidthOrSentinel();
1309 if (
auto uintType = type_dyn_cast<UIntType>(*
this))
1310 return uintType.getWidthOrSentinel();
1338 if (
auto sIntType = type_dyn_cast<SIntType>(*
this))
1347SIntType SIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1349SIntType SIntType::get(MLIRContext *context, std::optional<int32_t> width,
1351 return get(context, width ? *width : -1,
isConst);
1354LogicalResult SIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1355 int32_t widthOrSentinel,
bool isConst) {
1356 if (widthOrSentinel < -1)
1357 return emitError() <<
"invalid width";
1361int32_t SIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1363SIntType SIntType::getConstType(
bool isConst)
const {
1366 return get(getContext(), getWidthOrSentinel(),
isConst);
1373UIntType UIntType::get(MLIRContext *context) {
return get(context, -1,
false); }
1375UIntType UIntType::get(MLIRContext *context, std::optional<int32_t> width,
1377 return get(context, width ? *width : -1,
isConst);
1380LogicalResult UIntType::verify(function_ref<InFlightDiagnostic()> emitError,
1381 int32_t widthOrSentinel,
bool isConst) {
1382 if (widthOrSentinel < -1)
1383 return emitError() <<
"invalid width";
1387int32_t UIntType::getWidthOrSentinel()
const {
return getImpl()->width; }
1389UIntType UIntType::getConstType(
bool isConst)
const {
1392 return get(getContext(), getWidthOrSentinel(),
isConst);
1401 using KeyTy = std::pair<ArrayRef<BundleType::BundleElement>,
char>;
1408 uint64_t fieldID = 0;
1411 auto type = element.type;
1412 auto eltInfo = type.getRecursiveTypeProperties();
1433 return llvm::hash_combine(
1434 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1455BundleType BundleType::get(MLIRContext *context,
1456 ArrayRef<BundleElement> elements,
bool isConst) {
1457 return Base::get(context, elements,
isConst);
1460auto BundleType::getElements() const -> ArrayRef<BundleElement> {
1461 return getImpl()->elements;
1466 return getImpl()->props;
1471 auto *impl = getImpl();
1474 if (impl->passiveType)
1475 return impl->passiveType;
1478 if (impl->props.isPassive) {
1479 impl->passiveType = *
this;
1484 SmallVector<BundleType::BundleElement, 16> newElements;
1485 newElements.reserve(impl->elements.size());
1486 for (
auto &elt : impl->elements) {
1487 newElements.push_back({elt.name,
false, elt.type.getPassiveType()});
1490 auto passiveType = BundleType::get(getContext(), newElements,
isConst());
1491 impl->passiveType = passiveType;
1495BundleType BundleType::getConstType(
bool isConst)
const {
1498 return get(getContext(), getElements(),
isConst);
1501BundleType BundleType::getAllConstDroppedType() {
1505 SmallVector<BundleElement> constDroppedElements(
1506 llvm::map_range(getElements(), [](BundleElement element) {
1507 element.type = element.type.getAllConstDroppedType();
1510 return get(getContext(), constDroppedElements,
false);
1513std::optional<unsigned> BundleType::getElementIndex(StringAttr name) {
1514 for (
const auto &it :
llvm::enumerate(getElements())) {
1515 auto element = it.value();
1516 if (element.name == name) {
1517 return unsigned(it.index());
1520 return std::nullopt;
1523std::optional<unsigned> BundleType::getElementIndex(StringRef name) {
1524 for (
const auto &it :
llvm::enumerate(getElements())) {
1525 auto element = it.value();
1526 if (element.name.getValue() == name) {
1527 return unsigned(it.index());
1530 return std::nullopt;
1533StringAttr BundleType::getElementNameAttr(
size_t index) {
1534 assert(index < getNumElements() &&
1535 "index must be less than number of fields in bundle");
1536 return getElements()[index].name;
1539StringRef BundleType::getElementName(
size_t index) {
1540 return getElementNameAttr(index).getValue();
1543std::optional<BundleType::BundleElement>
1544BundleType::getElement(StringAttr name) {
1545 if (
auto maybeIndex = getElementIndex(name))
1546 return getElements()[*maybeIndex];
1547 return std::nullopt;
1550std::optional<BundleType::BundleElement>
1551BundleType::getElement(StringRef name) {
1552 if (
auto maybeIndex = getElementIndex(name))
1553 return getElements()[*maybeIndex];
1554 return std::nullopt;
1558BundleType::BundleElement BundleType::getElement(
size_t index) {
1559 assert(index < getNumElements() &&
1560 "index must be less than number of fields in bundle");
1561 return getElements()[index];
1565 auto element = getElement(name);
1570 auto element = getElement(name);
1575 assert(index < getNumElements() &&
1576 "index must be less than number of fields in bundle");
1577 return getElements()[index].type;
1580uint64_t BundleType::getFieldID(uint64_t index)
const {
1581 return getImpl()->fieldIDs[index];
1584uint64_t BundleType::getIndexForFieldID(uint64_t fieldID)
const {
1585 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1586 auto fieldIDs = getImpl()->fieldIDs;
1587 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1588 return std::distance(fieldIDs.begin(), it);
1591std::pair<uint64_t, uint64_t>
1592BundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1595 return {index, fieldID - elementFieldID};
1598std::pair<Type, uint64_t>
1599BundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1603 auto subfieldType = getElementType(subfieldIndex);
1604 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1605 return {subfieldType, subfieldID};
1608uint64_t BundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1610std::pair<uint64_t, bool>
1611BundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1613 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1615 return std::make_pair(fieldID - childRoot,
1616 fieldID >= childRoot && fieldID <= rangeEnd);
1619bool BundleType::isConst()
const {
return getImpl()->isConst; }
1621BundleType::ElementType
1622BundleType::getElementTypePreservingConst(
size_t index) {
1623 auto type = getElementType(index);
1624 return type.getConstType(type.isConst() ||
isConst());
1629 auto *impl = getImpl();
1632 if (impl->anonymousType)
1633 return impl->anonymousType;
1636 if (!impl->props.containsTypeAlias) {
1637 impl->anonymousType = *
this;
1643 SmallVector<BundleType::BundleElement, 16> newElements;
1644 newElements.reserve(impl->elements.size());
1645 for (
auto &elt : impl->elements)
1646 newElements.push_back({elt.name, elt.isFlip, elt.type.getAnonymousType()});
1648 auto anonymousType = BundleType::get(getContext(), newElements,
isConst());
1649 impl->anonymousType = anonymousType;
1650 return anonymousType;
1653LogicalResult BundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1654 ArrayRef<BundleElement> elements,
1656 SmallPtrSet<StringAttr, 4> nameSet;
1657 for (
auto &element : elements) {
1658 if (!nameSet.insert(element.name).second)
1659 return emitErrorFn() <<
"duplicate field name " << element.name
1671 using KeyTy = std::pair<ArrayRef<OpenBundleType::BundleElement>,
char>;
1679 uint64_t fieldID = 0;
1682 auto type = element.type;
1683 auto eltInfo = type.getRecursiveTypeProperties();
1703 return llvm::hash_combine(
1704 llvm::hash_combine_range(key.first.begin(), key.first.end()),
1716 SmallVector<OpenBundleType::BundleElement, 4>
elements;
1728OpenBundleType OpenBundleType::get(MLIRContext *context,
1729 ArrayRef<BundleElement> elements,
1731 return Base::get(context, elements,
isConst);
1734auto OpenBundleType::getElements() const -> ArrayRef<BundleElement> {
1735 return getImpl()->elements;
1740 return getImpl()->props;
1743OpenBundleType OpenBundleType::getConstType(
bool isConst)
const {
1746 return get(getContext(), getElements(),
isConst);
1749std::optional<unsigned> OpenBundleType::getElementIndex(StringAttr name) {
1750 for (
const auto &it :
llvm::enumerate(getElements())) {
1751 auto element = it.value();
1752 if (element.name == name) {
1753 return unsigned(it.index());
1756 return std::nullopt;
1759std::optional<unsigned> OpenBundleType::getElementIndex(StringRef name) {
1760 for (
const auto &it :
llvm::enumerate(getElements())) {
1761 auto element = it.value();
1762 if (element.name.getValue() == name) {
1763 return unsigned(it.index());
1766 return std::nullopt;
1769StringAttr OpenBundleType::getElementNameAttr(
size_t index) {
1770 assert(index < getNumElements() &&
1771 "index must be less than number of fields in bundle");
1772 return getElements()[index].name;
1775StringRef OpenBundleType::getElementName(
size_t index) {
1776 return getElementNameAttr(index).getValue();
1779std::optional<OpenBundleType::BundleElement>
1780OpenBundleType::getElement(StringAttr name) {
1781 if (
auto maybeIndex = getElementIndex(name))
1782 return getElements()[*maybeIndex];
1783 return std::nullopt;
1786std::optional<OpenBundleType::BundleElement>
1787OpenBundleType::getElement(StringRef name) {
1788 if (
auto maybeIndex = getElementIndex(name))
1789 return getElements()[*maybeIndex];
1790 return std::nullopt;
1794OpenBundleType::BundleElement OpenBundleType::getElement(
size_t index) {
1795 assert(index < getNumElements() &&
1796 "index must be less than number of fields in bundle");
1797 return getElements()[index];
1800OpenBundleType::ElementType OpenBundleType::getElementType(StringAttr name) {
1801 auto element = getElement(name);
1805OpenBundleType::ElementType OpenBundleType::getElementType(StringRef name) {
1806 auto element = getElement(name);
1810OpenBundleType::ElementType OpenBundleType::getElementType(
size_t index)
const {
1811 assert(index < getNumElements() &&
1812 "index must be less than number of fields in bundle");
1813 return getElements()[index].type;
1816uint64_t OpenBundleType::getFieldID(uint64_t index)
const {
1817 return getImpl()->fieldIDs[index];
1820uint64_t OpenBundleType::getIndexForFieldID(uint64_t fieldID)
const {
1821 assert(!getElements().
empty() &&
"Bundle must have >0 fields");
1822 auto fieldIDs = getImpl()->fieldIDs;
1823 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
1824 return std::distance(fieldIDs.begin(), it);
1827std::pair<uint64_t, uint64_t>
1828OpenBundleType::getIndexAndSubfieldID(uint64_t fieldID)
const {
1831 return {index, fieldID - elementFieldID};
1834std::pair<Type, uint64_t>
1835OpenBundleType::getSubTypeByFieldID(uint64_t fieldID)
const {
1839 auto subfieldType = getElementType(subfieldIndex);
1840 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
1841 return {subfieldType, subfieldID};
1844uint64_t OpenBundleType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
1846std::pair<uint64_t, bool>
1847OpenBundleType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
1849 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
1851 return std::make_pair(fieldID - childRoot,
1852 fieldID >= childRoot && fieldID <= rangeEnd);
1855bool OpenBundleType::isConst()
const {
return getImpl()->isConst; }
1857OpenBundleType::ElementType
1858OpenBundleType::getElementTypePreservingConst(
size_t index) {
1859 auto type = getElementType(index);
1861 return TypeSwitch<FIRRTLType, ElementType>(type)
1862 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
1863 return type.getConstType(type.isConst() ||
isConst());
1869OpenBundleType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
1870 ArrayRef<BundleElement> elements,
bool isConst) {
1871 SmallPtrSet<StringAttr, 4> nameSet;
1872 for (
auto &element : elements) {
1873 if (!nameSet.insert(element.name).second)
1874 return emitErrorFn() <<
"duplicate field name " << element.name
1875 <<
" in openbundle";
1877 return emitErrorFn()
1878 <<
"'const' bundle cannot have references, but element "
1879 << element.name <<
" has type " << element.type;
1880 if (type_isa<LHSType>(element.type))
1881 return emitErrorFn() <<
"bundle element " << element.name
1882 <<
" cannot have a left-hand side type";
1894 using KeyTy = std::tuple<FIRRTLBaseType, size_t, char>;
1912 static_cast<bool>(std::get<2>(key)));
1931 return getImpl()->elementType;
1934size_t FVectorType::getNumElements()
const {
return getImpl()->numElements; }
1938 return getImpl()->props;
1943 auto *impl = getImpl();
1946 if (impl->passiveType)
1947 return impl->passiveType;
1950 if (impl->elementType.getRecursiveTypeProperties().isPassive)
1951 return impl->passiveType = *
this;
1954 auto passiveType = FVectorType::get(getElementType().
getPassiveType(),
1956 impl->passiveType = passiveType;
1960FVectorType FVectorType::getConstType(
bool isConst)
const {
1963 return get(getElementType(), getNumElements(),
isConst);
1966FVectorType FVectorType::getAllConstDroppedType() {
1969 return get(getElementType().getAllConstDroppedType(), getNumElements(),
1975 auto *impl = getImpl();
1977 if (impl->anonymousType)
1978 return impl->anonymousType;
1981 if (!impl->props.containsTypeAlias)
1982 return impl->anonymousType = *
this;
1985 auto anonymousType = FVectorType::get(getElementType().getAnonymousType(),
1987 impl->anonymousType = anonymousType;
1988 return anonymousType;
1991uint64_t FVectorType::getFieldID(uint64_t index)
const {
1995uint64_t FVectorType::getIndexForFieldID(uint64_t fieldID)
const {
1996 assert(fieldID &&
"fieldID must be at least 1");
2001std::pair<uint64_t, uint64_t>
2002FVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2005 return {index, fieldID - elementFieldID};
2008std::pair<Type, uint64_t>
2009FVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2015uint64_t FVectorType::getMaxFieldID()
const {
2016 return getNumElements() *
2020std::pair<uint64_t, bool>
2021FVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2025 return std::make_pair(fieldID - childRoot,
2026 fieldID >= childRoot && fieldID <= rangeEnd);
2029bool FVectorType::isConst()
const {
return getImpl()->isConst; }
2031FVectorType::ElementType FVectorType::getElementTypePreservingConst() {
2032 auto type = getElementType();
2033 return type.getConstType(type.isConst() ||
isConst());
2041 using KeyTy = std::tuple<FIRRTLType, size_t, char>;
2059 static_cast<bool>(std::get<2>(key)));
2074FIRRTLType OpenVectorType::getElementType()
const {
2075 return getImpl()->elementType;
2078size_t OpenVectorType::getNumElements()
const {
return getImpl()->numElements; }
2082 return getImpl()->props;
2085OpenVectorType OpenVectorType::getConstType(
bool isConst)
const {
2088 return get(getElementType(), getNumElements(),
isConst);
2091uint64_t OpenVectorType::getFieldID(uint64_t index)
const {
2095uint64_t OpenVectorType::getIndexForFieldID(uint64_t fieldID)
const {
2096 assert(fieldID &&
"fieldID must be at least 1");
2101std::pair<uint64_t, uint64_t>
2102OpenVectorType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2105 return {index, fieldID - elementFieldID};
2108std::pair<Type, uint64_t>
2109OpenVectorType::getSubTypeByFieldID(uint64_t fieldID)
const {
2115uint64_t OpenVectorType::getMaxFieldID()
const {
2117 return getNumElements() *
2121std::pair<uint64_t, bool>
2122OpenVectorType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2126 return std::make_pair(fieldID - childRoot,
2127 fieldID >= childRoot && fieldID <= rangeEnd);
2130bool OpenVectorType::isConst()
const {
return getImpl()->isConst; }
2132OpenVectorType::ElementType OpenVectorType::getElementTypePreservingConst() {
2133 auto type = getElementType();
2135 return TypeSwitch<FIRRTLType, ElementType>(type)
2136 .Case<
FIRRTLBaseType, OpenBundleType, OpenVectorType>([&](
auto type) {
2137 return type.getConstType(type.isConst() ||
isConst());
2143OpenVectorType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2147 return emitErrorFn() <<
"vector cannot be const with references";
2149 return emitErrorFn() <<
"vector cannot have a left-hand side type";
2158 using KeyTy = std::pair<ArrayRef<FEnumType::EnumElement>,
char>;
2164 false,
false,
false};
2167 auto type = element.type;
2168 auto eltInfo = type.getRecursiveTypeProperties();
2170 props.containsTypeAlias |= eltInfo.containsTypeAlias;
2182 return llvm::hash_combine(
2183 llvm::hash_combine_range(key.first.begin(), key.first.end()),
2199FEnumType FEnumType::get(::mlir::MLIRContext *context,
2200 ArrayRef<EnumElement> elements,
bool isConst) {
2201 return Base::get(context, elements,
isConst);
2204ArrayRef<FEnumType::EnumElement> FEnumType::getElements()
const {
2205 return getImpl()->elements;
2208FEnumType FEnumType::getConstType(
bool isConst)
const {
2209 return get(getContext(), getElements(),
isConst);
2212FEnumType FEnumType::getAllConstDroppedType() {
2216 SmallVector<EnumElement> constDroppedElements(
2217 llvm::map_range(getElements(), [](EnumElement element) {
2218 element.type = element.type.getAllConstDroppedType();
2221 return get(getContext(), constDroppedElements,
false);
2226 return getImpl()->recProps;
2229std::optional<unsigned> FEnumType::getElementIndex(StringAttr name) {
2230 for (
const auto &it :
llvm::enumerate(getElements())) {
2231 auto element = it.value();
2232 if (element.name == name) {
2233 return unsigned(it.index());
2236 return std::nullopt;
2239size_t FEnumType::getBitWidth() {
return getDataWidth() + getTagWidth(); }
2241size_t FEnumType::getDataWidth() {
return getImpl()->dataSize; }
2243size_t FEnumType::getTagWidth() {
2244 if (getElements().size() == 0)
2247 return cast<IntegerType>(getElements()[0].value.getType()).getWidth();
2250std::optional<unsigned> FEnumType::getElementIndex(StringRef name) {
2251 for (
const auto &it :
llvm::enumerate(getElements())) {
2252 auto element = it.value();
2253 if (element.name.getValue() == name) {
2254 return unsigned(it.index());
2257 return std::nullopt;
2260StringAttr FEnumType::getElementNameAttr(
size_t index) {
2261 assert(index < getNumElements() &&
2262 "index must be less than number of fields in enum");
2263 return getElements()[index].name;
2266StringRef FEnumType::getElementName(
size_t index) {
2267 return getElementNameAttr(index).getValue();
2270IntegerAttr FEnumType::getElementValueAttr(
size_t index) {
2271 return getElements()[index].value;
2274APInt FEnumType::getElementValue(
size_t index) {
2275 return getElementValueAttr(index).getValue();
2279 return getElements()[index].type;
2282std::optional<FEnumType::EnumElement> FEnumType::getElement(StringAttr name) {
2283 if (
auto maybeIndex = getElementIndex(name))
2284 return getElements()[*maybeIndex];
2285 return std::nullopt;
2288std::optional<FEnumType::EnumElement> FEnumType::getElement(StringRef name) {
2289 if (
auto maybeIndex = getElementIndex(name))
2290 return getElements()[*maybeIndex];
2291 return std::nullopt;
2295FEnumType::EnumElement FEnumType::getElement(
size_t index) {
2296 assert(index < getNumElements() &&
2297 "index must be less than number of fields in enum");
2298 return getElements()[index];
2302 auto element = getElement(name);
2307 auto element = getElement(name);
2312 assert(index < getNumElements() &&
2313 "index must be less than number of fields in enum");
2314 return getElements()[index].type;
2317FIRRTLBaseType FEnumType::getElementTypePreservingConst(
size_t index) {
2318 auto type = getElementType(index);
2319 return type.getConstType(type.isConst() ||
isConst());
2322LogicalResult FEnumType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2323 ArrayRef<EnumElement> elements,
bool isConst) {
2325 IntegerAttr previous;
2326 SmallPtrSet<Attribute, 4> nameSet;
2328 for (
auto &elt : elements) {
2329 auto r = elt.type.getRecursiveTypeProperties();
2331 return emitErrorFn() <<
"enum field " << elt.name <<
" not passive";
2332 if (r.containsAnalog)
2333 return emitErrorFn() <<
"enum field " << elt.name <<
" contains analog";
2334 if (r.hasUninferredWidth)
2335 return emitErrorFn() <<
"enum field " << elt.name
2336 <<
" has uninferred width";
2337 if (r.hasUninferredReset)
2338 return emitErrorFn() <<
"enum field " << elt.name
2339 <<
" has uninferred reset";
2340 if (r.containsConst && !
isConst)
2341 return emitErrorFn() <<
"enum with 'const' elements must be 'const'";
2343 if (!nameSet.insert(elt.name).second)
2344 return emitErrorFn() <<
"duplicate variant name " << elt.name
2348 previous = elt.value;
2351 auto current = elt.value;
2352 if (previous.getType() != current.getType())
2353 return emitErrorFn() <<
"enum variant " << elt.name <<
" has type"
2354 << current.getType()
2355 <<
" which is different than previous variant "
2356 << previous.getType();
2358 if (previous.getValue().getBitWidth() != current.getValue().getBitWidth())
2359 return emitErrorFn() <<
"enum variant " << elt.name <<
" has bitwidth"
2360 << current.getValue().getBitWidth()
2361 <<
" which is different than previous variant "
2362 << previous.getValue().getBitWidth();
2363 if (previous.getValue().uge(current.getValue()))
2364 return emitErrorFn()
2365 <<
"enum variant " << elt.name <<
" has value " << current
2366 <<
" which is not greater than previous variant " << previous;
2375 auto *impl = getImpl();
2377 if (impl->anonymousType)
2378 return impl->anonymousType;
2380 if (!impl->recProps.containsTypeAlias)
2381 return impl->anonymousType = *
this;
2383 SmallVector<FEnumType::EnumElement, 4> elements;
2385 for (
auto element : getElements())
2387 {element.name, element.value, element.type.getAnonymousType()});
2388 return impl->anonymousType = FEnumType::get(getContext(), elements);
2397 using KeyTy = std::tuple<StringAttr, FIRRTLBaseType>;
2408 return llvm::hash_combine(key);
2421auto BaseTypeAliasType::get(StringAttr name,
FIRRTLBaseType innerType)
2422 -> BaseTypeAliasType {
2423 return Base::get(name.getContext(), name, innerType);
2426auto BaseTypeAliasType::getName() const -> StringAttr {
2427 return getImpl()->name;
2431 return getImpl()->innerType;
2435 auto *impl = getImpl();
2436 if (impl->anonymousType)
2437 return impl->anonymousType;
2438 return impl->anonymousType = getInnerType().getAnonymousType();
2446 auto rtp = getInnerType().getRecursiveTypeProperties();
2454BaseTypeAliasType::getModifiedType(
FIRRTLBaseType newInnerType)
const {
2455 if (newInnerType == getInnerType())
2457 return newInnerType;
2462 return getModifiedType(getInnerType().getAllConstDroppedType());
2466 return getModifiedType(getInnerType().getConstType(
isConst));
2469std::pair<Type, uint64_t>
2470BaseTypeAliasType::getSubTypeByFieldID(uint64_t fieldID)
const {
2474uint64_t BaseTypeAliasType::getMaxFieldID()
const {
2478std::pair<uint64_t, bool>
2479BaseTypeAliasType::projectToChildFieldID(uint64_t fieldID,
2480 uint64_t index)
const {
2484uint64_t BaseTypeAliasType::getIndexForFieldID(uint64_t fieldID)
const {
2488uint64_t BaseTypeAliasType::getFieldID(uint64_t index)
const {
2492std::pair<uint64_t, uint64_t>
2493BaseTypeAliasType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2502 return LHSType::get(type.getContext(), type);
2505LogicalResult LHSType::verify(function_ref<InFlightDiagnostic()> emitError,
2507 if (type.containsAnalog())
2508 return emitError() <<
"lhs type cannot contain an AnalogType";
2510 return emitError() <<
"lhs type cannot contain a non-passive type";
2511 if (type.containsReference())
2512 return emitError() <<
"lhs type cannot contain a reference";
2513 if (type_isa<LHSType>(type))
2514 return emitError() <<
"lhs type cannot contain a lhs type";
2523auto RefType::get(
FIRRTLBaseType type,
bool forceable, SymbolRefAttr layer)
2525 return Base::get(type.getContext(), type, forceable, layer);
2528auto RefType::verify(function_ref<InFlightDiagnostic()> emitErrorFn,
2531 if (!base.isPassive())
2532 return emitErrorFn() <<
"reference base type must be passive";
2533 if (forceable && base.containsConst())
2534 return emitErrorFn()
2535 <<
"forceable reference base type cannot contain const";
2540 auto rtp = getType().getRecursiveTypeProperties();
2543 rtp.isPassive =
false;
2551AnalogType AnalogType::get(mlir::MLIRContext *context) {
2552 return AnalogType::get(context, -1,
false);
2555AnalogType AnalogType::get(mlir::MLIRContext *context,
2556 std::optional<int32_t> width,
bool isConst) {
2557 return AnalogType::get(context, width ? *width : -1,
isConst);
2560LogicalResult AnalogType::verify(function_ref<InFlightDiagnostic()> emitError,
2561 int32_t widthOrSentinel,
bool isConst) {
2562 if (widthOrSentinel < -1)
2563 return emitError() <<
"invalid width";
2567int32_t AnalogType::getWidthOrSentinel()
const {
return getImpl()->width; }
2569AnalogType AnalogType::getConstType(
bool isConst)
const {
2572 return get(getContext(), getWidthOrSentinel(),
isConst);
2579ClockType ClockType::getConstType(
bool isConst)
const {
2589ResetType ResetType::getConstType(
bool isConst)
const {
2599AsyncResetType AsyncResetType::getConstType(
bool isConst)
const {
2610 using KeyTy = std::pair<FlatSymbolRefAttr, ArrayRef<ClassElement>>;
2614 auto name = key.first;
2615 auto elements = allocator.copyInto(key.second);
2618 SmallVector<uint64_t, 4> ids;
2627 auto fieldIDs = allocator.copyInto(ArrayRef(ids));
2649ClassType ClassType::get(FlatSymbolRefAttr name,
2650 ArrayRef<ClassElement> elements) {
2651 return get(name.getContext(), name, elements);
2654StringRef ClassType::getName()
const {
2655 return getNameAttr().getAttr().getValue();
2658FlatSymbolRefAttr ClassType::getNameAttr()
const {
return getImpl()->name; }
2660ArrayRef<ClassElement> ClassType::getElements()
const {
2661 return getImpl()->elements;
2664const ClassElement &ClassType::getElement(IntegerAttr index)
const {
2665 return getElement(index.getValue().getZExtValue());
2668const ClassElement &ClassType::getElement(
size_t index)
const {
2669 return getElements()[index];
2672std::optional<uint64_t> ClassType::getElementIndex(StringRef fieldName)
const {
2673 for (
const auto [i, e] :
llvm::enumerate(getElements()))
2674 if (fieldName == e.name)
2679void ClassType::printInterface(AsmPrinter &p)
const {
2683 for (
const auto &element : getElements()) {
2687 p.printKeywordOrString(element.name);
2688 p <<
": " << element.type;
2694uint64_t ClassType::getFieldID(uint64_t index)
const {
2695 return getImpl()->fieldIDs[index];
2698uint64_t ClassType::getIndexForFieldID(uint64_t fieldID)
const {
2699 assert(!getElements().
empty() &&
"Class must have >0 fields");
2700 auto fieldIDs = getImpl()->fieldIDs;
2701 auto *it = std::prev(llvm::upper_bound(fieldIDs, fieldID));
2702 return std::distance(fieldIDs.begin(), it);
2705std::pair<uint64_t, uint64_t>
2706ClassType::getIndexAndSubfieldID(uint64_t fieldID)
const {
2709 return {index, fieldID - elementFieldID};
2712std::pair<Type, uint64_t>
2713ClassType::getSubTypeByFieldID(uint64_t fieldID)
const {
2717 auto subfieldType = getElement(subfieldIndex).type;
2718 auto subfieldID = fieldID -
getFieldID(subfieldIndex);
2719 return {subfieldType, subfieldID};
2722uint64_t ClassType::getMaxFieldID()
const {
return getImpl()->maxFieldID; }
2724std::pair<uint64_t, bool>
2725ClassType::projectToChildFieldID(uint64_t fieldID, uint64_t index)
const {
2727 auto rangeEnd = index + 1 >= getNumElements() ?
getMaxFieldID()
2729 return std::make_pair(fieldID - childRoot,
2730 fieldID >= childRoot && fieldID <= rangeEnd);
2733ParseResult ClassType::parseInterface(AsmParser &parser, ClassType &result) {
2734 StringAttr className;
2735 if (parser.parseSymbolName(className))
2738 SmallVector<ClassElement> elements;
2739 if (parser.parseCommaSeparatedList(
2740 OpAsmParser::Delimiter::Paren, [&]() -> ParseResult {
2742 Direction direction;
2743 if (succeeded(parser.parseOptionalKeyword(
"out")))
2744 direction = Direction::Out;
2745 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
2746 direction = Direction::In;
2751 std::string keyword;
2752 if (parser.parseKeywordOrString(&keyword))
2754 StringAttr name = StringAttr::get(parser.getContext(), keyword);
2758 if (parser.parseColonType(type))
2761 elements.emplace_back(name, type, direction);
2766 result = ClassType::get(FlatSymbolRefAttr::get(className), elements);
2774void FIRRTLDialect::registerTypes() {
2776#define GET_TYPEDEF_LIST
2777#include "circt/Dialect/FIRRTL/FIRRTLTypes.cpp.inc"
2791 return TypeSwitch<FIRRTLBaseType, std::optional<int64_t>>(type)
2792 .Case<BundleType>([&](BundleType bundle) -> std::optional<int64_t> {
2794 for (
auto &elt : bundle) {
2795 if (elt.isFlip && !ignoreFlip)
2796 return std::nullopt;
2799 return std::nullopt;
2804 .Case<FEnumType>([&](FEnumType fenum) -> std::optional<int64_t> {
2806 for (
auto &elt : fenum) {
2809 return std::nullopt;
2810 width = std::max(width, *w);
2812 return width + fenum.getTagWidth();
2814 .Case<FVectorType>([&](
auto vector) -> std::optional<int64_t> {
2817 return std::nullopt;
2818 return *w * vector.getNumElements();
2821 .Case<ClockType, ResetType, AsyncResetType>([](Type) {
return 1; })
2822 .Default([&](
auto t) {
return std::nullopt; });
2824 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)