25#include "mlir/IR/BuiltinOps.h"
26#include "mlir/IR/BuiltinTypes.h"
27#include "mlir/IR/Diagnostics.h"
28#include "mlir/IR/ImplicitLocOpBuilder.h"
29#include "mlir/IR/PatternMatch.h"
30#include "mlir/IR/Threading.h"
31#include "mlir/IR/Verifier.h"
32#include "mlir/Support/Timing.h"
33#include "mlir/Tools/mlir-translate/Translation.h"
34#include "llvm/ADT/PointerEmbeddedInt.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/SmallPtrSet.h"
37#include "llvm/ADT/StringExtras.h"
38#include "llvm/ADT/StringSet.h"
39#include "llvm/ADT/StringSwitch.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/JSON.h"
42#include "llvm/Support/LogicalResult.h"
43#include "llvm/Support/SourceMgr.h"
44#include "llvm/Support/raw_ostream.h"
49using namespace firrtl;
50using namespace chirrtl;
54using mlir::LocationAttr;
67struct SharedParserConstants {
71 loIdentifier(StringAttr::get(
context,
"lo")),
72 hiIdentifier(StringAttr::get(
context,
"hi")),
73 amountIdentifier(StringAttr::get(
context,
"amount")),
75 hw::InnerRefAttr::get(StringAttr::get(
context,
"module"),
76 StringAttr::get(
context,
"placeholder"))) {}
85 llvm::StringMap<FIRRTLType> aliasMap;
88 llvm::DenseMap<StringRef, ClassLike> classMap;
91 llvm::DenseMap<StringRef, DomainOp> domainMap;
94 const ArrayAttr emptyArrayAttr;
97 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
100 const hw::InnerRefAttr placeholderInnerRef;
103 SharedParserConstants(
const SharedParserConstants &) =
delete;
104 void operator=(
const SharedParserConstants &) =
delete;
117 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
119 : version(version), constants(constants), lexer(lexer),
120 locatorFilenameCache(constants.loIdentifier ) {
124 SharedParserConstants &getConstants()
const {
return constants; }
125 MLIRContext *getContext()
const {
return constants.context; }
127 FIRLexer &getLexer() {
return lexer; }
130 std::optional<unsigned> getIndentation()
const {
135 const FIRToken &getToken()
const {
return lexer.getToken(); }
136 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
143 InFlightDiagnostic emitError(
const Twine &message = {}) {
144 return emitError(getToken().
getLoc(), message);
146 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
149 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
150 return emitWarning(getToken().
getLoc(), message);
153 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
163 Location translateLocation(llvm::SMLoc loc) {
164 return lexer.translateLocation(loc);
169 ParseResult parseOptionalInfoLocator(LocationAttr &result);
173 ParseResult parseOptionalName(StringAttr &name);
179 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
180 return requireFeature(minimum, feature, getToken().
getLoc());
183 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
184 if (version < minimum)
185 return emitError(loc)
186 << feature <<
" are a FIRRTL " << minimum
187 <<
"+ feature, but the specified FIRRTL version was " << version;
191 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
192 return removedFeature(removedVersion, feature, getToken().
getLoc());
195 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
197 if (version >= removedVersion)
198 return emitError(loc)
199 << feature <<
" were removed in FIRRTL " << removedVersion
200 <<
", but the specified FIRRTL version was " << version;
210 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
219 if (getToken().isNot(kind))
229 FIRToken consumedToken = getToken();
230 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
231 "shouldn't advance past EOF or errors");
233 return consumedToken;
242 FIRToken consumedToken = getToken();
243 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
245 return consumedToken;
250 ParseResult parseGetSpelling(StringRef &spelling) {
251 spelling = getTokenSpelling();
257 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
262 const std::function<ParseResult()> &parseElement);
269 ParseResult parseIntLit(APInt &result,
const Twine &message);
270 ParseResult parseIntLit(int64_t &result,
const Twine &message);
271 ParseResult parseIntLit(int32_t &result,
const Twine &message);
274 ParseResult parseVersionLit(
const Twine &message);
277 ParseResult parseWidth(int32_t &result);
280 ParseResult parseId(StringRef &result,
const Twine &message);
281 ParseResult parseId(StringAttr &result,
const Twine &message);
282 ParseResult parseFieldId(StringRef &result,
const Twine &message);
283 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
284 const Twine &message);
285 ParseResult parseEnumType(
FIRRTLType &result);
286 ParseResult parseListType(
FIRRTLType &result);
289 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
291 ParseResult parseRUW(RUWBehavior &result);
292 ParseResult parseOptionalRUW(RUWBehavior &result);
294 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
295 SMLoc &resultLoc,
bool allowAggregates =
false);
296 ParseResult parseParameterValue(Attribute &resultValue,
297 bool allowAggregates =
false);
303 FIRParser(
const FIRParser &) =
delete;
304 void operator=(
const FIRParser &) =
delete;
308 SharedParserConstants &constants;
312 StringAttr locatorFilenameCache;
314 FileLineColLoc fileLineColLocCache;
323InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
324 auto diag = mlir::emitError(translateLocation(loc), message);
328 if (getToken().is(FIRToken::error))
333InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
334 return mlir::emitWarning(translateLocation(loc), message);
344 const Twine &message) {
345 if (consumeIf(expectedToken))
347 return emitError(message);
354 const std::function<ParseResult()> &parseElement) {
355 if (consumeIf(rightToken))
361 while (consumeIf(FIRToken::comma)) {
366 if (parseToken(rightToken,
"expected ','"))
398 if (failed(
parser->parseOptionalInfoLocator(loc)))
402 switch (
parser->constants.options.infoLocatorHandling) {
403 case ILH::IgnoreInfo:
404 assert(0 &&
"Should not return info locations if ignoring");
406 case ILH::PreferInfo:
410 infoLoc = FusedLoc::get(loc.getContext(),
411 {loc, parser->translateLocation(firLoc)});
438ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
439 if (getToken().isNot(FIRToken::fileinfo))
442 auto loc = getToken().getLoc();
444 auto spelling = getTokenSpelling();
445 consumeToken(FIRToken::fileinfo);
449 constants.options.infoLocatorHandling ==
450 FIRParserOptions::InfoLocHandling::IgnoreInfo,
451 locatorFilenameCache, fileLineColLocCache, getContext());
454 if (!locationPair.first) {
455 mlir::emitWarning(translateLocation(loc),
456 "ignoring unknown @ info record format");
462 if (locationPair.first && constants.options.infoLocatorHandling ==
463 FIRParserOptions::InfoLocHandling::IgnoreInfo)
467 result = *locationPair.second;
475ParseResult FIRParser::parseOptionalName(StringAttr &name) {
477 if (getToken().isNot(FIRToken::colon)) {
478 name = StringAttr::get(getContext(),
"");
482 consumeToken(FIRToken::colon);
484 if (parseId(nameRef,
"expected result name"))
487 name = StringAttr::get(getContext(), nameRef);
498ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
500 if (getToken().isNot(FIRToken::inlineannotation))
503 loc = getToken().getLoc();
505 result = getTokenSpelling().drop_front(2).drop_back(1);
506 consumeToken(FIRToken::inlineannotation);
524ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
525 auto spelling = getTokenSpelling();
526 bool isNegative =
false;
527 switch (getToken().getKind()) {
528 case FIRToken::signed_integer:
529 isNegative = spelling[0] ==
'-';
530 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
531 spelling = spelling.drop_front();
533 case FIRToken::integer:
534 if (spelling.getAsInteger(10, result))
535 return emitError(message), failure();
539 if (result.isNegative())
540 result = result.zext(result.getBitWidth() + 1);
549 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
550 result = result.trunc(32);
554 case FIRToken::radix_specified_integer: {
555 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
557 if (spelling[0] ==
'-') {
559 spelling = spelling.drop_front();
561 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
566 spelling = spelling.drop_front(2);
567 if (spelling.getAsInteger(base, result))
568 return emitError(
"invalid character in integer literal"), failure();
569 if (result.isNegative())
570 result = result.zext(result.getBitWidth() + 1);
576 case FIRToken::string: {
579 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
582 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
583 spelling = spelling.drop_back().drop_front();
587 switch (spelling.empty() ?
' ' : spelling.front()) {
598 return emitError(
"expected base specifier (h/o/b) in integer literal"),
601 spelling = spelling.drop_front();
604 bool isNegative =
false;
605 if (!spelling.empty() && spelling.front() ==
'+')
606 spelling = spelling.drop_front();
607 else if (!spelling.empty() && spelling.front() ==
'-') {
609 spelling = spelling.drop_front();
613 if (spelling.empty())
614 return emitError(
"expected digits in integer literal"), failure();
616 if (spelling.getAsInteger(base, result))
617 return emitError(
"invalid character in integer literal"), failure();
622 if (result.isNegative())
623 result = result.zext(result.getBitWidth() + 1);
628 consumeToken(FIRToken::string);
633 return emitError(
"expected integer literal"), failure();
637ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
639 auto loc = getToken().getLoc();
640 if (parseIntLit(value, message))
643 result = (int64_t)value.getLimitedValue(INT64_MAX);
645 return emitError(loc,
"value is too big to handle"), failure();
649ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
651 auto loc = getToken().getLoc();
652 if (parseIntLit(value, message))
655 result = (int32_t)value.getLimitedValue(INT32_MAX);
657 return emitError(loc,
"value is too big to handle"), failure();
663ParseResult FIRParser::parseVersionLit(
const Twine &message) {
664 auto spelling = getTokenSpelling();
665 if (getToken().getKind() != FIRToken::version)
666 return emitError(message), failure();
669 return emitError(
"failed to parse version string"), failure();
674 consumeToken(FIRToken::version);
680ParseResult FIRParser::parseWidth(int32_t &result) {
681 auto widthLoc = getToken().getLoc();
682 if (parseIntLit(result,
"expected width") ||
683 parseToken(FIRToken::greater,
"expected '>'"))
686 return emitError(widthLoc,
"invalid width specifier"), failure();
694ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
695 switch (getToken().getKind()) {
697 case FIRToken::identifier:
698 case FIRToken::literal_identifier:
700#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
701#include "FIRTokenKinds.def"
706 if (getToken().getKind() == FIRToken::literal_identifier)
707 result = getTokenSpelling().drop_front().drop_back();
709 result = getTokenSpelling();
719ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
721 if (parseId(name, message))
724 result = StringAttr::get(getContext(), name);
733ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
735 result = getTokenSpelling();
736 if (consumeIf(FIRToken::integer))
742 if (parseId(result, message))
754ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
755 const Twine &message) {
757 StringRef tmp = getTokenSpelling();
759 if (consumeIf(FIRToken::integer)) {
760 result.push_back(tmp);
764 if (consumeIf(FIRToken::floatingpoint)) {
768 auto [a, b] = tmp.split(
".");
774 if (consumeIf(FIRToken::version)) {
776 auto [a,
d] = tmp.split(
".");
777 auto [b, c] =
d.split(
".");
785 if (parseId(tmp, message))
787 result.push_back(tmp);
793ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
794 if (parseToken(FIRToken::l_brace_bar,
795 "expected leading '{|' in enumeration type"))
797 SmallVector<StringAttr> names;
798 SmallVector<APInt> values;
799 SmallVector<FIRRTLBaseType> types;
800 SmallVector<SMLoc> locs;
801 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
802 auto fieldLoc = getToken().getLoc();
803 locs.push_back(fieldLoc);
807 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
809 auto name = StringAttr::get(getContext(), nameStr);
810 names.push_back(name);
816 if (consumeIf(FIRToken::equal)) {
817 if (parseIntLit(value,
"expected integer value for enumeration tag"))
819 if (value.isNegative())
820 return emitError(fieldLoc,
"enum tag value must be non-negative");
821 }
else if (values.empty()) {
827 auto &prev = values.back();
828 if (prev.isMaxValue())
829 value = prev.zext(prev.getBitWidth() + 1);
834 values.push_back(std::move(value));
838 if (consumeIf(FIRToken::colon)) {
840 if (
parseType(parsedType,
"expected enumeration type"))
842 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
844 return emitError(fieldLoc,
"field must be a base type");
847 type = UIntType::get(getContext(), 0);
849 types.push_back(type);
851 auto r = type.getRecursiveTypeProperties();
853 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
854 if (r.containsAnalog)
855 return emitError(fieldLoc)
856 <<
"enum field " << name <<
" contains analog";
857 if (r.hasUninferredWidth)
858 return emitError(fieldLoc)
859 <<
"enum field " << name <<
" has uninferred width";
860 if (r.hasUninferredReset)
861 return emitError(fieldLoc)
862 <<
"enum field " << name <<
" has uninferred reset";
868 SmallPtrSet<StringAttr, 4> nameSet;
869 for (
auto [name, loc] :
llvm::zip(names, locs))
870 if (!nameSet.insert(name).second)
871 return emitError(loc,
872 "duplicate variant name in enum: " + name.getValue());
875 unsigned bitwidth = 0;
876 for (
auto &value : values)
877 bitwidth = std::max(bitwidth, value.getActiveBits());
879 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
883 SmallPtrSet<IntegerAttr, 4> valueSet;
884 SmallVector<FEnumType::EnumElement, 4> elements;
885 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
886 auto tagValue = value.zextOrTrunc(bitwidth);
887 auto attr = IntegerAttr::get(tagType, tagValue);
889 if (!valueSet.insert(attr).second)
890 return emitError(loc,
"duplicate variant value in enum: ") << attr;
891 elements.push_back({name, attr, type});
894 llvm::sort(elements);
895 result = FEnumType::get(getContext(), elements);
899ParseResult FIRParser::parsePropertyType(
PropertyType &result,
900 const Twine &message) {
901 auto loc = getToken().getLoc();
906 auto prop = type_dyn_cast<PropertyType>(type);
908 return emitError(loc,
"expected property type");
914ParseResult FIRParser::parseListType(
FIRRTLType &result) {
915 consumeToken(FIRToken::kw_List);
918 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
919 parsePropertyType(
elementType,
"expected List element type") ||
920 parseToken(FIRToken::greater,
"expected '>' in List type"))
946ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
947 switch (getToken().getKind()) {
949 return emitError(message), failure();
951 case FIRToken::kw_Clock:
952 consumeToken(FIRToken::kw_Clock);
953 result = ClockType::get(getContext());
956 case FIRToken::kw_Inst: {
957 if (requireFeature({6, 0, 0},
"Inst types"))
960 consumeToken(FIRToken::kw_Inst);
961 if (parseToken(FIRToken::less,
"expected < in Inst type"))
964 auto loc = getToken().getLoc();
966 if (parseId(
id,
"expected class name in Inst type"))
970 const auto &classMap = getConstants().classMap;
971 auto lookup = classMap.find(
id);
972 if (lookup == classMap.end())
973 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
975 auto classOp = lookup->second;
977 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
980 result = classOp.getInstanceType();
984 case FIRToken::kw_AnyRef: {
985 if (requireFeature({6, 0, 0},
"AnyRef types"))
988 consumeToken(FIRToken::kw_AnyRef);
989 result = AnyRefType::get(getContext());
993 case FIRToken::kw_Reset:
994 consumeToken(FIRToken::kw_Reset);
995 result = ResetType::get(getContext());
998 case FIRToken::kw_AsyncReset:
999 consumeToken(FIRToken::kw_AsyncReset);
1000 result = AsyncResetType::get(getContext());
1003 case FIRToken::kw_UInt:
1004 consumeToken(FIRToken::kw_UInt);
1006 result = UIntType::get(getContext(), -1);
1009 case FIRToken::kw_SInt:
1010 consumeToken(FIRToken::kw_SInt);
1012 result = SIntType::get(getContext(), -1);
1015 case FIRToken::kw_Analog:
1016 consumeToken(FIRToken::kw_Analog);
1018 result = AnalogType::get(getContext(), -1);
1021 case FIRToken::langle_UInt:
1022 case FIRToken::langle_SInt:
1023 case FIRToken::langle_Analog: {
1026 auto kind = getToken().getKind();
1030 if (parseWidth(width))
1033 if (kind == FIRToken::langle_SInt)
1034 result = SIntType::get(getContext(), width);
1035 else if (kind == FIRToken::langle_UInt)
1036 result = UIntType::get(getContext(), width);
1038 assert(kind == FIRToken::langle_Analog);
1039 result = AnalogType::get(getContext(), width);
1044 case FIRToken::kw_Domain: {
1050 auto loc = getToken().getLoc();
1051 StringRef domainKindStr;
1052 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type") ||
1053 parseId(domainKindStr,
"expected domain kind"))
1057 const auto &domainMap = getConstants().domainMap;
1058 auto lookup = domainMap.find(domainKindStr);
1059 if (lookup == domainMap.end())
1060 return emitError(loc) <<
"unknown domain '" << domainKindStr <<
"'";
1062 result = DomainType::getFromDomainOp(lookup->second);
1066 case FIRToken::kw_Probe:
1067 case FIRToken::kw_RWProbe: {
1068 auto kind = getToken().getKind();
1069 auto loc = getToken().getLoc();
1074 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1075 parseType(type,
"expected probe data type"))
1078 SmallVector<StringRef> layers;
1079 if (consumeIf(FIRToken::comma)) {
1080 if (requireFeature({4, 0, 0},
"colored probes"))
1085 loc = getToken().getLoc();
1086 if (parseId(layer,
"expected layer name"))
1088 layers.push_back(layer);
1089 }
while (consumeIf(FIRToken::period));
1092 if (!consumeIf(FIRToken::greater))
1093 return emitError(loc,
"expected '>' to end reference type");
1095 bool forceable = kind == FIRToken::kw_RWProbe;
1097 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1099 return emitError(loc,
"invalid probe inner type, must be base-type");
1102 return emitError(loc,
"probe inner type must be passive");
1104 if (forceable &&
innerType.containsConst())
1105 return emitError(loc,
"rwprobe cannot contain const");
1107 SymbolRefAttr layer;
1108 if (!layers.empty()) {
1110 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1111 return FlatSymbolRefAttr::get(getContext(), a);
1113 layer = SymbolRefAttr::get(getContext(), layers.front(),
1114 llvm::to_vector(nestedLayers));
1117 result = RefType::get(innerType, forceable, layer);
1121 case FIRToken::l_brace: {
1122 consumeToken(FIRToken::l_brace);
1124 SmallVector<OpenBundleType::BundleElement, 4> elements;
1125 SmallPtrSet<StringAttr, 4> nameSet;
1126 bool bundleCompatible =
true;
1127 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1128 bool isFlipped = consumeIf(FIRToken::kw_flip);
1130 auto loc = getToken().getLoc();
1131 StringRef fieldNameStr;
1132 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1133 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1135 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1138 if (!nameSet.insert(fieldName).second)
1139 return emitError(loc,
"duplicate field name in bundle: " +
1140 fieldName.getValue());
1143 if (
parseType(type,
"expected bundle field type"))
1146 elements.push_back({fieldName, isFlipped, type});
1147 bundleCompatible &= isa<BundleType::ElementType>(type);
1154 if (bundleCompatible) {
1155 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1156 return BundleType::BundleElement{
1157 element.name, element.isFlip,
1158 cast<BundleType::ElementType>(element.type)};
1160 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1162 result = OpenBundleType::get(getContext(), elements);
1166 case FIRToken::l_brace_bar: {
1167 if (parseEnumType(result))
1172 case FIRToken::identifier: {
1174 auto loc = getToken().getLoc();
1175 if (parseId(
id,
"expected a type alias name"))
1177 auto it = constants.aliasMap.find(
id);
1178 if (it == constants.aliasMap.end()) {
1179 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1182 result = it->second;
1186 case FIRToken::kw_const: {
1187 consumeToken(FIRToken::kw_const);
1188 auto nextToken = getToken();
1189 auto loc = nextToken.getLoc();
1192 if (nextToken.is(FIRToken::kw_const))
1193 return emitError(loc,
"'const' can only be specified once on a type");
1198 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1200 return emitError(loc,
"only hardware types can be 'const'");
1202 result = baseType.getConstType(
true);
1206 case FIRToken::kw_String:
1207 if (requireFeature({3, 1, 0},
"Strings"))
1209 consumeToken(FIRToken::kw_String);
1210 result = StringType::get(getContext());
1212 case FIRToken::kw_Integer:
1213 if (requireFeature({3, 1, 0},
"Integers"))
1215 consumeToken(FIRToken::kw_Integer);
1216 result = FIntegerType::get(getContext());
1218 case FIRToken::kw_Bool:
1219 if (requireFeature({6, 0, 0},
"Bools"))
1221 consumeToken(FIRToken::kw_Bool);
1222 result = BoolType::get(getContext());
1224 case FIRToken::kw_Double:
1225 if (requireFeature({6, 0, 0},
"Doubles"))
1227 consumeToken(FIRToken::kw_Double);
1228 result = DoubleType::get(getContext());
1230 case FIRToken::kw_Path:
1231 if (requireFeature({6, 0, 0},
"Paths"))
1233 consumeToken(FIRToken::kw_Path);
1234 result = PathType::get(getContext());
1236 case FIRToken::kw_List:
1237 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1241 case FIRToken::langle_List: {
1244 if (requireFeature({4, 0, 0},
"Lists"))
1249 if (parsePropertyType(
elementType,
"expected List element type") ||
1250 parseToken(FIRToken::greater,
"expected '>' in List type"))
1253 result = ListType::get(getContext(),
elementType);
1259 while (consumeIf(FIRToken::l_square)) {
1260 auto sizeLoc = getToken().getLoc();
1262 if (parseIntLit(size,
"expected width") ||
1263 parseToken(FIRToken::r_square,
"expected ]"))
1267 return emitError(sizeLoc,
"invalid size specifier"), failure();
1269 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1271 result = FVectorType::get(baseType, size);
1273 result = OpenVectorType::get(result, size);
1280ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1281 switch (getToken().getKind()) {
1283 case FIRToken::kw_old:
1284 result = RUWBehavior::Old;
1285 consumeToken(FIRToken::kw_old);
1287 case FIRToken::kw_new:
1288 result = RUWBehavior::New;
1289 consumeToken(FIRToken::kw_new);
1291 case FIRToken::kw_undefined:
1292 result = RUWBehavior::Undefined;
1293 consumeToken(FIRToken::kw_undefined);
1303ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1304 switch (getToken().getKind()) {
1308 case FIRToken::kw_old:
1309 result = RUWBehavior::Old;
1310 consumeToken(FIRToken::kw_old);
1312 case FIRToken::kw_new:
1313 result = RUWBehavior::New;
1314 consumeToken(FIRToken::kw_new);
1316 case FIRToken::kw_undefined:
1317 result = RUWBehavior::Undefined;
1318 consumeToken(FIRToken::kw_undefined);
1326ParseResult FIRParser::parseParameter(StringAttr &resultName,
1327 Attribute &resultValue, SMLoc &resultLoc,
1328 bool allowAggregates) {
1329 auto loc = getToken().getLoc();
1333 if (parseId(name,
"expected parameter name") ||
1334 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1339 if (parseParameterValue(value, allowAggregates))
1342 resultName = StringAttr::get(getContext(), name);
1343 resultValue = value;
1354ParseResult FIRParser::parseParameterValue(Attribute &value,
1355 bool allowAggregates) {
1356 mlir::Builder builder(getContext());
1357 switch (getToken().getKind()) {
1360 case FIRToken::integer:
1361 case FIRToken::signed_integer: {
1363 if (parseIntLit(result,
"invalid integer parameter"))
1369 if (result.getBitWidth() < 32)
1370 result = result.sext(32);
1372 value = builder.getIntegerAttr(
1373 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1379 case FIRToken::string: {
1381 value = builder.getStringAttr(getToken().getStringValue());
1382 consumeToken(FIRToken::string);
1387 case FIRToken::verbatim_string: {
1389 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1390 value = hw::ParamVerbatimAttr::get(text);
1391 consumeToken(FIRToken::verbatim_string);
1396 case FIRToken::floatingpoint: {
1398 if (!llvm::to_float(getTokenSpelling(), v))
1399 return emitError(
"invalid float parameter syntax"), failure();
1401 value = builder.getF64FloatAttr(v);
1402 consumeToken(FIRToken::floatingpoint);
1407 case FIRToken::l_square: {
1408 if (!allowAggregates)
1409 return emitError(
"expected non-aggregate parameter value");
1412 SmallVector<Attribute> elements;
1413 auto parseElement = [&] {
1414 return parseParameterValue(elements.emplace_back(),
1417 if (parseListUntil(FIRToken::r_square, parseElement))
1420 value = builder.getArrayAttr(elements);
1425 case FIRToken::l_brace: {
1426 if (!allowAggregates)
1427 return emitError(
"expected non-aggregate parameter value");
1430 NamedAttrList fields;
1431 auto parseField = [&]() -> ParseResult {
1432 StringAttr fieldName;
1433 Attribute fieldValue;
1435 if (parseParameter(fieldName, fieldValue, fieldLoc,
1438 if (fields.set(fieldName, fieldValue))
1439 return emitError(fieldLoc)
1440 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1443 if (parseListUntil(FIRToken::r_brace, parseField))
1446 value = fields.getDictionary(getContext());
1451 return emitError(
"expected parameter value");
1466 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1474struct UnbundledValueRestorer {
1476 size_t startingSize;
1478 startingSize = list.size();
1480 ~UnbundledValueRestorer() { list.resize(startingSize); }
1489struct FIRModuleContext :
public FIRParser {
1490 explicit FIRModuleContext(Block *topLevelBlock,
1491 SharedParserConstants &constants,
FIRLexer &lexer,
1493 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1496 template <
typename OpTy = ConstantOp,
typename... Args>
1497 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1498 Type type, Args &&...args) {
1499 auto &result = constantCache[{attr, type}];
1505 OpBuilder::InsertPoint savedIP;
1508 if (builder.getInsertionBlock() != topLevelBlock) {
1509 savedIP = builder.saveInsertionPoint();
1510 auto *block = builder.getInsertionBlock();
1512 auto *op = block->getParentOp();
1513 if (!op || !op->getBlock()) {
1515 builder.setInsertionPointToEnd(topLevelBlock);
1518 if (op->getBlock() == topLevelBlock) {
1519 builder.setInsertionPoint(op);
1522 block = op->getBlock();
1526 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1528 if (savedIP.isSet())
1529 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1540 Value &getCachedSubaccess(Value value,
unsigned index) {
1541 auto &result = subaccessCache[{value, index}];
1544 auto it = scopeMap.find(value.getParentBlock());
1545 if (it != scopeMap.end())
1546 it->second->scopedSubaccesses.push_back({result, index});
1556 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1557 bool insertNameIntoGlobalScope =
false);
1558 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1559 bool insertNameIntoGlobalScope =
false) {
1561 insertNameIntoGlobalScope);
1565 void removeSymbolEntry(StringRef name);
1569 SMLoc loc,
bool fatal =
true);
1574 StringRef field, SMLoc loc);
1582 assert(index < unbundledValues.size());
1583 return unbundledValues[index];
1593 struct ContextScope {
1594 friend struct FIRModuleContext;
1595 ContextScope(FIRModuleContext &moduleContext, Block *block)
1596 : moduleContext(moduleContext), block(block),
1597 previousScope(moduleContext.currentScope) {
1598 moduleContext.currentScope =
this;
1599 moduleContext.scopeMap[block] =
this;
1604 for (
auto *entryPtr : scopedDecls)
1605 entryPtr->second.first = SMLoc();
1608 for (
auto subaccess : scopedSubaccesses)
1609 moduleContext.subaccessCache.erase(subaccess);
1611 moduleContext.scopeMap.erase(block);
1613 moduleContext.currentScope = previousScope;
1617 void operator=(
const ContextScope &) =
delete;
1618 ContextScope(
const ContextScope &) =
delete;
1620 FIRModuleContext &moduleContext;
1622 ContextScope *previousScope;
1623 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1624 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1629 Block *topLevelBlock;
1635 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1647 DenseMap<Block *, ContextScope *> scopeMap;
1652 ContextScope *currentScope =
nullptr;
1658void FIRModuleContext::removeSymbolEntry(StringRef name) {
1659 symbolTable.erase(name);
1668ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1670 bool insertNameIntoGlobalScope) {
1673 auto [entryIt, inserted] =
1678 if (entryIt->second.first.isValid()) {
1680 emitError(loc,
"redefinition of name '" + name +
"' ")
1681 .attachNote(translateLocation(entryIt->second.first))
1682 <<
"previous definition here.";
1685 emitError(loc,
"redefinition of name '" + name +
"' ")
1686 <<
"- FIRRTL has flat namespace and requires all "
1687 <<
"declarations in a module to have unique names.";
1694 entryIt->second = {loc, entry};
1695 if (currentScope && !insertNameIntoGlobalScope)
1696 currentScope->scopedDecls.push_back(&*entryIt);
1703 StringRef name, SMLoc loc) {
1704 auto &entry = symbolTable[name];
1705 if (!entry.first.isValid())
1706 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1707 result = entry.second;
1708 assert(result &&
"name in symbol table without definition");
1712ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1714 SMLoc loc,
bool fatal) {
1715 if (!isa<Value>(entry)) {
1717 emitError(loc,
"bundle value should only be used from subfield");
1720 result = cast<Value>(entry);
1724ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1726 StringRef fieldName,
1728 if (!isa<UnbundledID>(entry)) {
1729 emitError(loc,
"value should not be used from subfield");
1733 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1735 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1736 assert(unbundledId < unbundledValues.size());
1738 for (
auto elt : ubEntry) {
1739 if (elt.first == fieldAttr) {
1740 result = elt.second;
1745 emitError(loc,
"use of invalid field name '")
1746 << fieldName <<
"' on bundle value";
1772struct LazyLocationListener :
public OpBuilder::Listener {
1773 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1774 assert(builder.getListener() ==
nullptr);
1775 builder.setListener(
this);
1778 ~LazyLocationListener() {
1779 assert(subOps.empty() &&
"didn't process parsed operations");
1780 assert(builder.getListener() ==
this);
1781 builder.setListener(
nullptr);
1784 void startStatement() {
1785 assert(!isActive &&
"Already processing a statement");
1794 Location
getLoc(FIRParser &parser, SMLoc loc) {
1796 switch (parser.getConstants().options.infoLocatorHandling) {
1797 case ILH::IgnoreInfo:
1800 case ILH::PreferInfo:
1804 case ILH::FusedInfo:
1806 return FusedLoc::get(infoLoc.getContext(),
1807 {infoLoc, parser.translateLocation(loc)});
1810 return parser.translateLocation(loc);
1815 void endStatement(FIRParser &parser) {
1816 assert(isActive &&
"Not parsing a statement");
1820 for (
auto opAndSMLoc : subOps)
1821 opAndSMLoc.first->setLoc(
getLoc(parser, opAndSMLoc.second));
1825 infoLoc = LocationAttr();
1826 currentSMLoc = SMLoc();
1831 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1834 void setInfoLoc(LocationAttr loc) {
1835 assert(!infoLoc &&
"Info location multiply specified");
1841 void notifyOperationInserted(Operation *op,
1842 mlir::IRRewriter::InsertPoint)
override {
1843 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1844 assert(isActive &&
"Not parsing a statement");
1845 subOps.push_back({op, currentSMLoc});
1850 bool isActive =
false;
1858 LocationAttr infoLoc;
1865 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1867 void operator=(
const LazyLocationListener &) =
delete;
1868 LazyLocationListener(
const LazyLocationListener &) =
delete;
1876struct InnerSymFixups {
1879 fixups.push_back({user, target});
1888 hw::InnerRefUserOpInterface innerRefUser;
1891 SmallVector<Fixup, 0> fixups;
1897 for (
auto &f : fixups) {
1900 return isnc.get(module);
1902 assert(ref &&
"unable to resolve inner symbol target");
1906 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1907 .Case<RWProbeOp>([ref](RWProbeOp op) {
1908 op.setTargetAttr(ref);
1911 .Default([](
auto *op) {
1912 return op->emitError(
"unknown inner-ref user requiring fixup");
1923struct FIRStmtParser :
public FIRParser {
1924 explicit FIRStmtParser(Block &blockToInsertInto,
1925 FIRModuleContext &moduleContext,
1926 InnerSymFixups &innerSymFixups,
1927 const SymbolTable &circuitSymTbl,
FIRVersion version,
1928 SymbolRefAttr layerSym = {})
1929 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1931 builder(UnknownLoc::
get(getContext()), getContext()),
1932 locationProcessor(this->builder), moduleContext(moduleContext),
1933 innerSymFixups(innerSymFixups), layerSym(layerSym),
1934 circuitSymTbl(circuitSymTbl) {
1935 builder.setInsertionPointToEnd(&blockToInsertInto);
1938 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1939 ParseResult parseSimpleStmtBlock(
unsigned indent);
1942 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1945 void emitInvalidate(Value val,
Flow flow);
1951 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1954 ParseResult parseOptionalInfo() {
1956 if (failed(parseOptionalInfoLocator(loc)))
1958 locationProcessor.setInfoLoc(loc);
1963 ParseResult parseExpImpl(Value &result,
const Twine &message,
1964 bool isLeadingStmt);
1965 ParseResult parseExp(Value &result,
const Twine &message) {
1966 return parseExpImpl(result, message,
false);
1968 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1969 return parseExpImpl(result, message,
true);
1971 ParseResult parseEnumExp(Value &result);
1972 ParseResult parsePathExp(Value &result);
1973 ParseResult parseDomainExp(Value &result);
1974 ParseResult parseRefExp(Value &result,
const Twine &message);
1975 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1976 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1977 const Twine &message);
1980 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1981 ParseResult parseIntrinsicStmt() {
1983 return parseIntrinsic(unused,
true);
1985 ParseResult parseIntrinsicExp(Value &result) {
1986 return parseIntrinsic(result,
false);
1988 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1990 template <
typename subop>
1991 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1992 ParseResult parseOptionalExpPostscript(Value &result,
1993 bool allowDynamic =
true);
1994 ParseResult parsePostFixFieldId(Value &result);
1995 ParseResult parsePostFixIntSubscript(Value &result);
1996 ParseResult parsePostFixDynamicSubscript(Value &result);
1998 parseIntegerLiteralExp(Value &result,
bool isSigned,
1999 std::optional<int32_t> allocatedWidth = {});
2000 ParseResult parseListExp(Value &result);
2001 ParseResult parseListConcatExp(Value &result);
2002 ParseResult parseCatExp(Value &result);
2003 ParseResult parseStringConcatExp(Value &result);
2004 ParseResult parsePropEqExp(Value &result);
2005 ParseResult parseUnsafeDomainCast(Value &result);
2006 ParseResult parseUnknownProperty(Value &result);
2008 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
2009 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2011 auto loc = getToken().getLoc();
2012 locationProcessor.setLoc(loc);
2015 auto vals = std::array<Value, M>();
2016 auto ints = std::array<int64_t, N>();
2020 for (
size_t i = 0; i < M; ++i) {
2022 if (parseToken(FIRToken::comma,
"expected ','"))
2024 if (parseExp(vals[i],
"expected expression in primitive operand"))
2030 for (
size_t i = 0; i < N; ++i) {
2032 if (parseToken(FIRToken::comma,
"expected ','"))
2034 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2039 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2043 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2047 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2048 translateLocation(loc));
2053 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2054 result = op.getResult();
2058 template <
typename T,
unsigned M,
unsigned N>
2059 ParseResult parsePrimExp(Value &result) {
2060 auto ms = std::make_index_sequence<M>();
2061 auto ns = std::make_index_sequence<N>();
2062 return parsePrim<T, M, N>(ms, ns, result);
2065 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2068 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2069 SymbolRefAttr layerSym);
2070 ParseResult parseAttach();
2071 ParseResult parseMemPort(MemDirAttr direction);
2077 ArrayRef<Value> specOperands,
2078 StringAttr &formatStringResult,
2079 SmallVectorImpl<Value> &operands);
2080 ParseResult parsePrintf();
2081 ParseResult parseFPrintf();
2082 ParseResult parseFFlush();
2083 ParseResult parseSkip();
2084 ParseResult parseStop();
2085 ParseResult parseAssert();
2086 ParseResult parseAssume();
2087 ParseResult parseCover();
2088 ParseResult parseWhen(
unsigned whenIndent);
2089 ParseResult parseMatch(
unsigned matchIndent);
2090 ParseResult parseDomainInstantiation();
2091 ParseResult parseDomainDefine();
2092 ParseResult parseRefDefine();
2093 ParseResult parseRefForce();
2094 ParseResult parseRefForceInitial();
2095 ParseResult parseRefRelease();
2096 ParseResult parseRefReleaseInitial();
2097 ParseResult parseRefRead(Value &result);
2098 ParseResult parseProbe(Value &result);
2099 ParseResult parsePropAssert();
2100 ParseResult parsePropAssign();
2101 ParseResult parseRWProbe(Value &result);
2102 ParseResult parseLeadingExpStmt(Value lhs);
2103 ParseResult parseConnect();
2104 ParseResult parseInvalidate();
2105 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2108 ParseResult parseInstance();
2109 ParseResult parseInstanceChoice();
2110 ParseResult parseObject();
2111 ParseResult parseCombMem();
2112 ParseResult parseSeqMem();
2113 ParseResult parseMem(
unsigned memIndent);
2114 ParseResult parseNode();
2115 ParseResult parseWire();
2116 ParseResult parseRegister(
unsigned regIndent);
2117 ParseResult parseRegisterWithReset();
2118 ParseResult parseContract(
unsigned blockIndent);
2121 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2124 ImplicitLocOpBuilder builder;
2125 LazyLocationListener locationProcessor;
2128 FIRModuleContext &moduleContext;
2131 InnerSymFixups &innerSymFixups;
2135 SymbolRefAttr layerSym;
2137 const SymbolTable &circuitSymTbl;
2144void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2145 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2152 auto props = tpe.getRecursiveTypeProperties();
2153 if (props.isPassive && !props.containsAnalog) {
2154 if (flow == Flow::Source)
2156 emitConnect(builder, val, InvalidValueOp::create(builder, tpe),
2157 getConstants().options.warnOnTruncation);
2168 TypeSwitch<FIRRTLType>(tpe)
2169 .Case<BundleType>([&](
auto tpe) {
2170 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2171 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2173 OpBuilder::InsertionGuard guard(builder);
2174 builder.setInsertionPointAfterValue(val);
2175 subfield = SubfieldOp::create(builder, val, i);
2177 emitInvalidate(subfield,
2178 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2181 .Case<FVectorType>([&](
auto tpe) {
2182 auto tpex = tpe.getElementType();
2183 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2184 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2186 OpBuilder::InsertionGuard guard(builder);
2187 builder.setInsertionPointAfterValue(val);
2188 subindex = SubindexOp::create(builder, tpex, val, i);
2190 emitInvalidate(subindex, flow);
2218ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2219 bool isLeadingStmt) {
2220 auto token = getToken();
2221 auto kind = token.getKind();
2223 case FIRToken::lp_integer_add:
2224 case FIRToken::lp_integer_mul:
2225 case FIRToken::lp_integer_shr:
2226 case FIRToken::lp_integer_shl:
2227 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2236#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2238 case FIRToken::lp_##SPELLING: \
2239 if (requireFeature(VERSION, FEATURE)) \
2241 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2244#include "FIRTokenKinds.def"
2246 case FIRToken::l_brace_bar:
2248 return emitError(
"unexpected enumeration as start of statement");
2249 if (parseEnumExp(result))
2252 case FIRToken::lp_read:
2254 return emitError(
"unexpected read() as start of statement");
2255 if (parseRefRead(result))
2258 case FIRToken::lp_probe:
2260 return emitError(
"unexpected probe() as start of statement");
2261 if (parseProbe(result))
2264 case FIRToken::lp_rwprobe:
2266 return emitError(
"unexpected rwprobe() as start of statement");
2267 if (parseRWProbe(result))
2271 case FIRToken::langle_UInt:
2272 case FIRToken::langle_SInt: {
2275 bool isSigned = getToken().is(FIRToken::langle_SInt);
2278 if (parseWidth(width))
2282 if (parseIntegerLiteralExp(result, isSigned, width))
2287 case FIRToken::lp_UInt:
2288 if (parseIntegerLiteralExp(result,
false))
2291 case FIRToken::lp_SInt:
2292 if (parseIntegerLiteralExp(result,
true))
2295 case FIRToken::lp_String: {
2296 if (requireFeature({3, 1, 0},
"Strings"))
2298 locationProcessor.setLoc(getToken().
getLoc());
2299 consumeToken(FIRToken::lp_String);
2301 if (parseGetSpelling(spelling) ||
2302 parseToken(FIRToken::string,
2303 "expected string literal in String expression") ||
2304 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2307 result = moduleContext.getCachedConstant<StringConstantOp>(
2308 builder, attr, builder.getType<StringType>(), attr);
2311 case FIRToken::lp_Integer: {
2312 if (requireFeature({3, 1, 0},
"Integers"))
2314 locationProcessor.setLoc(getToken().
getLoc());
2315 consumeToken(FIRToken::lp_Integer);
2317 if (parseIntLit(value,
"expected integer literal in Integer expression") ||
2318 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2320 APSInt apint(value,
false);
2321 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2322 builder, IntegerAttr::get(getContext(), apint),
2323 builder.getType<FIntegerType>(), apint);
2326 case FIRToken::lp_Bool: {
2327 if (requireFeature({6, 0, 0},
"Bools"))
2329 locationProcessor.setLoc(getToken().
getLoc());
2330 consumeToken(FIRToken::lp_Bool);
2332 if (consumeIf(FIRToken::kw_true))
2334 else if (consumeIf(FIRToken::kw_false))
2337 return emitError(
"expected true or false in Bool expression");
2338 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2340 auto attr = builder.getBoolAttr(value);
2341 result = moduleContext.getCachedConstant<BoolConstantOp>(
2342 builder, attr, builder.getType<BoolType>(), value);
2345 case FIRToken::lp_Double: {
2346 if (requireFeature({6, 0, 0},
"Doubles"))
2348 locationProcessor.setLoc(getToken().
getLoc());
2349 consumeToken(FIRToken::lp_Double);
2350 auto spelling = getTokenSpelling();
2351 if (parseToken(FIRToken::floatingpoint,
2352 "expected floating point in Double expression") ||
2353 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2358 if (!llvm::to_float(spelling, d))
2359 return emitError(
"invalid double");
2360 auto attr = builder.getF64FloatAttr(d);
2361 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2362 builder, attr, builder.getType<DoubleType>(), attr);
2365 case FIRToken::lp_List:
2366 case FIRToken::langle_List: {
2367 if (requireFeature({4, 0, 0},
"Lists"))
2370 return emitError(
"unexpected List<>() as start of statement");
2371 if (parseListExp(result))
2376 case FIRToken::lp_list_concat: {
2378 return emitError(
"unexpected list_create() as start of statement");
2379 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2384 case FIRToken::lp_path:
2386 return emitError(
"unexpected path() as start of statement");
2387 if (requireFeature({6, 0, 0},
"Paths") || parsePathExp(result))
2391 case FIRToken::lp_intrinsic:
2392 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2393 parseIntrinsicExp(result))
2397 case FIRToken::lp_cat:
2398 if (parseCatExp(result))
2402 case FIRToken::lp_string_concat:
2403 if (parseStringConcatExp(result))
2407 case FIRToken::lp_prop_eq:
2408 if (requireFeature({6, 0, 0},
"property equality") ||
2409 parsePropEqExp(result))
2413 case FIRToken::lp_unsafe_domain_cast:
2415 parseUnsafeDomainCast(result))
2418 case FIRToken::lp_Unknown:
2419 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2420 parseUnknownProperty(result))
2426 case FIRToken::identifier:
2427 case FIRToken::literal_identifier:
2428 case FIRToken::kw_UInt:
2429 case FIRToken::kw_SInt:
2430 case FIRToken::kw_String:
2431 case FIRToken::kw_Integer:
2432 case FIRToken::kw_Bool:
2433 case FIRToken::kw_Double:
2434 case FIRToken::kw_List:
2437 auto loc = getToken().getLoc();
2439 if (parseId(name, message) ||
2440 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2444 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2447 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2452 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2453 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2454 parseOptionalInfo())
2457 locationProcessor.setLoc(loc);
2459 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2461 moduleContext.getUnbundledEntry(unbundledId);
2462 for (
auto elt : ubEntry)
2463 emitInvalidate(elt.second);
2471 StringRef fieldName;
2472 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2473 parseFieldId(fieldName,
"expected field name") ||
2474 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2482 case FIRToken::lp_shr:
2485 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2486 result = PadPrimOp::create(builder, result, 1);
2492 return parseOptionalExpPostscript(result);
2502ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2503 bool allowDynamic) {
2508 if (consumeIf(FIRToken::period)) {
2509 if (parsePostFixFieldId(result))
2516 if (consumeIf(FIRToken::l_square)) {
2517 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2518 if (parsePostFixIntSubscript(result))
2523 return emitError(
"subaccess not allowed here");
2524 if (parsePostFixDynamicSubscript(result))
2534template <
typename subop>
2536FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2538 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2544 auto baseType = cast<FIRRTLType>(base.getType());
2545 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2548 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2554 locationProcessor.setLoc(loc);
2555 OpBuilder::InsertionGuard guard(builder);
2556 builder.setInsertionPointAfterValue(base);
2557 auto op = subop::create(builder, resultType, base, indexNo);
2560 return value = op.getResult();
2567ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2568 auto loc = getToken().getLoc();
2569 SmallVector<StringRef, 3> fields;
2570 if (parseFieldIdSeq(fields,
"expected field name"))
2572 for (
auto fieldName : fields) {
2573 std::optional<unsigned> indexV;
2574 auto type = result.getType();
2575 if (
auto refTy = type_dyn_cast<RefType>(type))
2576 type = refTy.getType();
2577 if (
auto bundle = type_dyn_cast<BundleType>(type))
2578 indexV = bundle.getElementIndex(fieldName);
2579 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2580 indexV = bundle.getElementIndex(fieldName);
2581 else if (
auto klass = type_dyn_cast<ClassType>(type))
2582 indexV = klass.getElementIndex(fieldName);
2583 else if (
auto domain = type_dyn_cast<DomainType>(type))
2584 indexV = domain.getFieldIndex(fieldName);
2586 return emitError(loc,
2587 "subfield requires bundle, object, or domain operand ");
2589 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2590 << result.getType();
2591 auto indexNo = *indexV;
2593 FailureOr<Value> subResult;
2594 if (type_isa<RefType>(result.getType()))
2595 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2596 else if (type_isa<ClassType>(type))
2597 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2598 else if (type_isa<DomainType>(type))
2599 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2600 else if (type_isa<BundleType>(type))
2601 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2603 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2605 if (failed(subResult))
2607 result = *subResult;
2616ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2617 auto loc = getToken().getLoc();
2619 if (parseIntLit(indexNo,
"expected index") ||
2620 parseToken(FIRToken::r_square,
"expected ']'"))
2624 return emitError(loc,
"invalid index specifier"), failure();
2626 FailureOr<Value> subResult;
2627 if (type_isa<RefType>(result.getType()))
2628 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2629 else if (type_isa<FVectorType>(result.getType()))
2630 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2632 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2634 if (failed(subResult))
2636 result = *subResult;
2644ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2645 auto loc = getToken().getLoc();
2647 if (parseExp(index,
"expected subscript index expression") ||
2648 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2652 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2654 return emitError(
"expected base type for index expression");
2655 indexType = indexType.getPassiveType();
2656 locationProcessor.setLoc(loc);
2661 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2664 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2665 translateLocation(loc));
2670 auto op = SubaccessOp::create(builder, resultType, result, index);
2671 result = op.getResult();
2682FIRStmtParser::parseIntegerLiteralExp(Value &result,
bool isSigned,
2683 std::optional<int32_t> allocatedWidth) {
2684 auto loc = getToken().getLoc();
2687 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2692 int32_t width = allocatedWidth.value_or(-1);
2698 parseToken(FIRToken::l_paren,
"expected '(' in integer expression"))
2701 if (parseIntLit(value,
"expected integer value") ||
2702 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2707 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2709 IntegerType::SignednessSemantics signedness =
2710 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2712 if (!value.isZero())
2713 return emitError(loc,
"zero bit constant must be zero");
2714 value = value.trunc(0);
2715 }
else if (width != -1) {
2717 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2719 return emitError(loc,
"initializer too wide for declared width");
2720 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2724 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2725 auto attr = builder.getIntegerAttr(attrType, value);
2727 locationProcessor.setLoc(loc);
2728 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2733ParseResult FIRStmtParser::parseListExp(Value &result) {
2734 auto loc = getToken().getLoc();
2735 bool hasLAngle = getToken().is(FIRToken::langle_List);
2736 bool hasLParen = getToken().is(FIRToken::lp_List);
2741 if (!hasLAngle && parseToken(FIRToken::less,
"expected '<' in List type"))
2744 if (parsePropertyType(
elementType,
"expected List element type") ||
2745 parseToken(FIRToken::greater,
"expected '>' in List type"))
2748 auto listType = ListType::get(getContext(),
elementType);
2752 parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2755 SmallVector<Value, 3> operands;
2756 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2758 locationProcessor.setLoc(loc);
2759 if (parseExp(operand,
"expected expression in List expression"))
2763 if (!isa<AnyRefType>(elementType) ||
2764 !isa<ClassType>(operand.getType()))
2765 return emitError(loc,
"unexpected expression of type ")
2766 << operand.getType() <<
" in List expression of type "
2768 operand = ObjectAnyRefCastOp::create(builder, operand);
2771 operands.push_back(operand);
2776 locationProcessor.setLoc(loc);
2777 result = ListCreateOp::create(builder, listType, operands);
2782ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2783 consumeToken(FIRToken::lp_list_concat);
2785 auto loc = getToken().getLoc();
2787 SmallVector<Value, 3> operands;
2788 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2790 locationProcessor.setLoc(loc);
2791 if (parseExp(operand,
"expected expression in List concat expression"))
2794 if (!type_isa<ListType>(operand.getType()))
2795 return emitError(loc,
"unexpected expression of type ")
2796 << operand.getType() <<
" in List concat expression";
2799 type = type_cast<ListType>(operand.getType());
2801 if (operand.getType() != type)
2802 return emitError(loc,
"unexpected expression of type ")
2803 << operand.getType() <<
" in List concat expression of type "
2806 operands.push_back(operand);
2811 if (operands.empty())
2812 return emitError(loc,
"need at least one List to concatenate");
2814 locationProcessor.setLoc(loc);
2815 result = ListConcatOp::create(builder, type, operands);
2820ParseResult FIRStmtParser::parseCatExp(Value &result) {
2821 consumeToken(FIRToken::lp_cat);
2823 auto loc = getToken().getLoc();
2824 SmallVector<Value, 3> operands;
2825 std::optional<bool> isSigned;
2826 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2828 locationProcessor.setLoc(loc);
2829 auto operandLoc = getToken().getLoc();
2830 if (parseExp(operand,
"expected expression in cat expression"))
2832 if (!type_isa<IntType>(operand.getType())) {
2833 auto diag = emitError(loc,
"all operands must be Int type");
2834 diag.attachNote(translateLocation(operandLoc))
2835 <<
"non-integer operand is here";
2839 isSigned = type_isa<SIntType>(operand.getType());
2840 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2841 auto diag = emitError(loc,
"all operands must have same signedness");
2842 diag.attachNote(translateLocation(operandLoc))
2843 <<
"operand with different signedness is here";
2847 operands.push_back(operand);
2852 if (operands.size() != 2) {
2853 if (requireFeature({6, 0, 0},
"variadic cat", loc))
2857 locationProcessor.setLoc(loc);
2858 result = CatPrimOp::create(builder, operands);
2863ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2864 consumeToken(FIRToken::lp_string_concat);
2866 auto loc = getToken().getLoc();
2867 SmallVector<Value, 3> operands;
2868 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2870 locationProcessor.setLoc(loc);
2871 if (parseExp(operand,
2872 "expected expression in string_concat expression"))
2874 if (!type_isa<StringType>(operand.getType()))
2875 return emitError(loc,
"all operands must be String type");
2876 operands.push_back(operand);
2881 if (operands.empty())
2882 return emitError(loc,
"need at least one String to concatenate");
2884 locationProcessor.setLoc(loc);
2885 auto type = StringType::get(builder.getContext());
2886 result = builder.create<StringConcatOp>(type, operands);
2891ParseResult FIRStmtParser::parsePropEqExp(Value &result) {
2892 consumeToken(FIRToken::lp_prop_eq);
2894 auto loc = getToken().getLoc();
2896 locationProcessor.setLoc(loc);
2897 if (parseExp(lhs,
"expected lhs expression in prop_eq expression") ||
2898 parseToken(FIRToken::comma,
"expected ','") ||
2899 parseExp(rhs,
"expected rhs expression in prop_eq expression") ||
2900 parseToken(FIRToken::r_paren,
"expected ')'"))
2903 auto isValidType = [](Type t) {
2904 return type_isa<StringType>(t) || type_isa<BoolType>(t) ||
2905 type_isa<FIntegerType>(t);
2907 if (!isValidType(lhs.getType()))
2908 return emitError(loc,
2909 "lhs of prop_eq must be String, Bool, or Integer type");
2910 if (!isValidType(rhs.getType()))
2911 return emitError(loc,
2912 "rhs of prop_eq must be String, Bool, or Integer type");
2913 if (lhs.getType() != rhs.getType())
2914 return emitError(loc,
"prop_eq operands must have the same type");
2916 locationProcessor.setLoc(loc);
2917 result = PropEqOp::create(builder, lhs, rhs);
2921ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2922 consumeToken(FIRToken::lp_unsafe_domain_cast);
2924 auto loc = getToken().getLoc();
2926 if (parseExp(input,
"expected input"))
2929 SmallVector<Value> domains;
2930 if (consumeIf(FIRToken::comma)) {
2931 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2933 if (parseExp(domain,
"expected domain"))
2935 domains.push_back(domain);
2939 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2943 locationProcessor.setLoc(loc);
2944 result = UnsafeDomainCastOp::create(builder, input, domains);
2948ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2949 auto loc = getToken().getLoc();
2950 consumeToken(FIRToken::lp_Unknown);
2954 if (parsePropertyType(type,
"expected property type") ||
2955 parseToken(FIRToken::r_paren,
"expected ')' in unknown property"))
2958 locationProcessor.setLoc(loc);
2959 result = UnknownValueOp::create(builder, type);
2980std::optional<ParseResult>
2981FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2982 switch (getToken().getKind()) {
2985 return std::nullopt;
2987 case FIRToken::period:
2988 case FIRToken::l_square:
2989 case FIRToken::kw_is:
2990 case FIRToken::less_equal:
2996 auto loc = keyword.
getLoc();
2998 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2999 return ParseResult(failure());
3005 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
3008 if (!consumeIf(FIRToken::period))
3009 return ParseResult(failure());
3011 StringRef fieldName;
3012 if (parseFieldId(fieldName,
"expected field name") ||
3013 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
3014 return ParseResult(failure());
3018 if (parseOptionalExpPostscript(lhs))
3019 return ParseResult(failure());
3021 return parseLeadingExpStmt(lhs);
3027ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
3030 if (getToken().isAny(FIRToken::eof, FIRToken::error))
3033 auto subIndent = getIndentation();
3034 if (!subIndent.has_value())
3035 return emitError(
"expected statement to be on its own line"), failure();
3037 if (*subIndent <= indent)
3041 if (parseSimpleStmt(*subIndent))
3046ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
3047 locationProcessor.startStatement();
3048 auto result = parseSimpleStmtImpl(stmtIndent);
3049 locationProcessor.endStatement(*
this);
3072ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
3073 auto kind = getToken().getKind();
3076 case FIRToken::kw_invalidate:
3077 case FIRToken::kw_connect:
3078 case FIRToken::kw_regreset:
3082 kind = FIRToken::identifier;
3089 case FIRToken::kw_attach:
3090 return parseAttach();
3091 case FIRToken::kw_infer:
3092 return parseMemPort(MemDirAttr::Infer);
3093 case FIRToken::kw_read:
3094 return parseMemPort(MemDirAttr::Read);
3095 case FIRToken::kw_write:
3096 return parseMemPort(MemDirAttr::Write);
3097 case FIRToken::kw_rdwr:
3098 return parseMemPort(MemDirAttr::ReadWrite);
3099 case FIRToken::kw_connect:
3100 return parseConnect();
3101 case FIRToken::kw_propassert:
3102 if (requireFeature({6, 0, 0},
"property assertions"))
3104 return parsePropAssert();
3105 case FIRToken::kw_propassign:
3106 if (requireFeature({3, 1, 0},
"properties"))
3108 return parsePropAssign();
3109 case FIRToken::kw_invalidate:
3110 return parseInvalidate();
3111 case FIRToken::lp_printf:
3112 return parsePrintf();
3113 case FIRToken::lp_fprintf:
3114 return parseFPrintf();
3115 case FIRToken::lp_fflush:
3116 return parseFFlush();
3117 case FIRToken::kw_skip:
3119 case FIRToken::lp_stop:
3121 case FIRToken::lp_assert:
3122 return parseAssert();
3123 case FIRToken::lp_assume:
3124 return parseAssume();
3125 case FIRToken::lp_cover:
3126 return parseCover();
3127 case FIRToken::kw_when:
3128 return parseWhen(stmtIndent);
3129 case FIRToken::kw_match:
3130 return parseMatch(stmtIndent);
3131 case FIRToken::kw_domain:
3133 return parseDomainInstantiation();
3134 case FIRToken::kw_domain_define:
3135 return parseDomainDefine();
3136 case FIRToken::kw_define:
3137 return parseRefDefine();
3138 case FIRToken::lp_force:
3139 return parseRefForce();
3140 case FIRToken::lp_force_initial:
3141 return parseRefForceInitial();
3142 case FIRToken::lp_release:
3143 return parseRefRelease();
3144 case FIRToken::lp_release_initial:
3145 return parseRefReleaseInitial();
3146 case FIRToken::kw_group:
3147 if (requireFeature({3, 2, 0},
"optional groups") ||
3148 removedFeature({3, 3, 0},
"optional groups"))
3150 return parseLayerBlockOrGroup(stmtIndent);
3151 case FIRToken::kw_layerblock:
3152 if (requireFeature({3, 3, 0},
"layers"))
3154 return parseLayerBlockOrGroup(stmtIndent);
3155 case FIRToken::lp_intrinsic:
3156 if (requireFeature({4, 0, 0},
"generic intrinsics"))
3158 return parseIntrinsicStmt();
3162 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
3169 return parseLeadingExpStmt(lhs);
3173 case FIRToken::kw_inst:
3174 return parseInstance();
3175 case FIRToken::kw_instchoice:
3176 return parseInstanceChoice();
3177 case FIRToken::kw_object:
3178 return parseObject();
3179 case FIRToken::kw_cmem:
3180 return parseCombMem();
3181 case FIRToken::kw_smem:
3182 return parseSeqMem();
3183 case FIRToken::kw_mem:
3184 return parseMem(stmtIndent);
3185 case FIRToken::kw_node:
3187 case FIRToken::kw_wire:
3189 case FIRToken::kw_reg:
3190 return parseRegister(stmtIndent);
3191 case FIRToken::kw_regreset:
3192 return parseRegisterWithReset();
3193 case FIRToken::kw_contract:
3194 return parseContract(stmtIndent);
3198ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3200 SymbolRefAttr layerSym) {
3202 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3203 moduleContext, &blockToInsertInto);
3208 UnbundledValueRestorer x(moduleContext.unbundledValues);
3212 auto subParser = std::make_unique<FIRStmtParser>(
3213 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3217 auto stmtIndent = getIndentation();
3220 if (!stmtIndent.has_value())
3221 return subParser->parseSimpleStmt(indent);
3223 if (*stmtIndent <= indent)
3224 return emitError(
"statement must be indented more than previous statement"),
3228 return subParser->parseSimpleStmtBlock(indent);
3232ParseResult FIRStmtParser::parseAttach() {
3233 auto startTok = consumeToken(FIRToken::kw_attach);
3236 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3239 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3242 SmallVector<Value, 4> operands;
3243 operands.push_back({});
3244 if (parseExp(operands.back(),
"expected operand in attach"))
3247 while (consumeIf(FIRToken::comma)) {
3248 operands.push_back({});
3249 if (parseExp(operands.back(),
"expected operand in attach"))
3252 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3255 if (parseOptionalInfo())
3258 locationProcessor.setLoc(startTok.getLoc());
3259 AttachOp::create(builder, operands);
3266ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3267 auto startTok = consumeToken();
3268 auto startLoc = startTok.getLoc();
3272 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3278 Value memory, indexExp, clock;
3279 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3280 parseId(
id,
"expected result name") ||
3281 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3282 parseId(memName,
"expected memory name") ||
3283 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3284 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3285 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3286 parseExp(indexExp,
"expected index expression") ||
3287 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3288 parseToken(FIRToken::comma,
"expected ','") ||
3289 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3292 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3294 return emitError(startLoc,
3295 "memory port should have behavioral memory type");
3296 auto resultType = memVType.getElementType();
3298 ArrayAttr annotations = getConstants().emptyArrayAttr;
3299 locationProcessor.setLoc(startLoc);
3302 Value memoryPort, memoryData;
3304 OpBuilder::InsertionGuard guard(builder);
3305 builder.setInsertionPointAfterValue(memory);
3306 auto memoryPortOp = MemoryPortOp::create(
3307 builder, resultType, CMemoryPortType::get(getContext()), memory,
3308 direction,
id, annotations);
3309 memoryData = memoryPortOp.getResult(0);
3310 memoryPort = memoryPortOp.getResult(1);
3314 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3316 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3322ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3323 StringRef formatString,
3324 ArrayRef<Value> specOperands,
3325 StringAttr &formatStringResult,
3326 SmallVectorImpl<Value> &operands) {
3329 operands.append(specOperands.begin(), specOperands.end());
3330 formatStringResult =
3336 auto loc = translateLocation(formatStringLoc);
3339 formatStringResult, operands);
3344ParseResult FIRStmtParser::parsePrintf() {
3345 auto startTok = consumeToken(FIRToken::lp_printf);
3347 Value clock, condition;
3348 StringRef formatString;
3349 if (parseExp(clock,
"expected clock expression in printf") ||
3350 parseToken(FIRToken::comma,
"expected ','") ||
3351 parseExp(condition,
"expected condition in printf") ||
3352 parseToken(FIRToken::comma,
"expected ','"))
3355 auto formatStringLoc = getToken().getLoc();
3356 if (parseGetSpelling(formatString) ||
3357 parseToken(FIRToken::string,
"expected format string in printf"))
3360 SmallVector<Value, 4> specOperands;
3361 while (consumeIf(FIRToken::comma)) {
3362 specOperands.push_back({});
3363 if (parseExp(specOperands.back(),
"expected operand in printf"))
3368 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3369 parseOptionalName(name) || parseOptionalInfo())
3372 locationProcessor.setLoc(startTok.getLoc());
3374 StringAttr formatStrUnescaped;
3375 SmallVector<Value> operands;
3377 formatStrUnescaped, operands))
3380 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3386ParseResult FIRStmtParser::parseFPrintf() {
3387 if (requireFeature({6, 0, 0},
"fprintf"))
3389 auto startTok = consumeToken(FIRToken::lp_fprintf);
3391 Value clock, condition;
3392 StringRef outputFile, formatString;
3393 if (parseExp(clock,
"expected clock expression in fprintf") ||
3394 parseToken(FIRToken::comma,
"expected ','") ||
3395 parseExp(condition,
"expected condition in fprintf") ||
3396 parseToken(FIRToken::comma,
"expected ','"))
3399 auto outputFileLoc = getToken().getLoc();
3400 if (parseGetSpelling(outputFile) ||
3401 parseToken(FIRToken::string,
"expected output file in fprintf"))
3404 SmallVector<Value, 4> outputFileSpecOperands;
3405 while (consumeIf(FIRToken::comma)) {
3407 if (getToken().getKind() == FIRToken::string)
3409 outputFileSpecOperands.push_back({});
3410 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3414 auto formatStringLoc = getToken().getLoc();
3415 if (parseGetSpelling(formatString) ||
3416 parseToken(FIRToken::string,
"expected format string in printf"))
3419 SmallVector<Value, 4> specOperands;
3420 while (consumeIf(FIRToken::comma)) {
3421 specOperands.push_back({});
3422 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3427 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3428 parseOptionalName(name) || parseOptionalInfo())
3431 locationProcessor.setLoc(startTok.getLoc());
3433 StringAttr outputFileNameStrUnescaped;
3434 SmallVector<Value> outputFileOperands;
3436 outputFileNameStrUnescaped, outputFileOperands))
3439 StringAttr formatStrUnescaped;
3440 SmallVector<Value> operands;
3442 formatStrUnescaped, operands))
3445 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3446 outputFileOperands, formatStrUnescaped, operands, name);
3451ParseResult FIRStmtParser::parseFFlush() {
3452 if (requireFeature({6, 0, 0},
"fflush"))
3455 auto startTok = consumeToken(FIRToken::lp_fflush);
3457 Value clock, condition;
3458 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3459 parseToken(FIRToken::comma,
"expected ','") ||
3460 parseExp(condition,
"expected condition in 'fflush'"))
3463 locationProcessor.setLoc(startTok.getLoc());
3464 StringAttr outputFileNameStrUnescaped;
3465 SmallVector<Value> outputFileOperands;
3467 if (consumeIf(FIRToken::comma)) {
3468 SmallVector<Value, 4> outputFileSpecOperands;
3469 auto outputFileLoc = getToken().getLoc();
3470 StringRef outputFile;
3471 if (parseGetSpelling(outputFile) ||
3472 parseToken(FIRToken::string,
"expected output file in fflush"))
3475 while (consumeIf(FIRToken::comma)) {
3476 outputFileSpecOperands.push_back({});
3477 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3482 outputFileNameStrUnescaped, outputFileOperands))
3486 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3487 parseOptionalInfo())
3490 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3491 outputFileOperands);
3496ParseResult FIRStmtParser::parseSkip() {
3497 auto startTok = consumeToken(FIRToken::kw_skip);
3501 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3504 if (parseOptionalInfo())
3507 locationProcessor.setLoc(startTok.getLoc());
3508 SkipOp::create(builder);
3513ParseResult FIRStmtParser::parseStop() {
3514 auto startTok = consumeToken(FIRToken::lp_stop);
3516 Value clock, condition;
3519 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3520 parseToken(FIRToken::comma,
"expected ','") ||
3521 parseExp(condition,
"expected condition in 'stop'") ||
3522 parseToken(FIRToken::comma,
"expected ','") ||
3523 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3524 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3525 parseOptionalName(name) || parseOptionalInfo())
3528 locationProcessor.setLoc(startTok.getLoc());
3529 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3535ParseResult FIRStmtParser::parseAssert() {
3536 auto startTok = consumeToken(FIRToken::lp_assert);
3538 Value clock, predicate, enable;
3539 StringRef formatString;
3541 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3542 parseToken(FIRToken::comma,
"expected ','") ||
3543 parseExp(predicate,
"expected predicate in 'assert'") ||
3544 parseToken(FIRToken::comma,
"expected ','") ||
3545 parseExp(enable,
"expected enable in 'assert'") ||
3546 parseToken(FIRToken::comma,
"expected ','") ||
3547 parseGetSpelling(formatString) ||
3548 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3551 SmallVector<Value, 4> operands;
3552 while (!consumeIf(FIRToken::r_paren)) {
3553 operands.push_back({});
3554 if (parseToken(FIRToken::comma,
"expected ','") ||
3555 parseExp(operands.back(),
"expected operand in 'assert'"))
3559 if (parseOptionalName(name) || parseOptionalInfo())
3562 locationProcessor.setLoc(startTok.getLoc());
3564 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3565 operands, name.getValue());
3570ParseResult FIRStmtParser::parseAssume() {
3571 auto startTok = consumeToken(FIRToken::lp_assume);
3573 Value clock, predicate, enable;
3574 StringRef formatString;
3576 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3577 parseToken(FIRToken::comma,
"expected ','") ||
3578 parseExp(predicate,
"expected predicate in 'assume'") ||
3579 parseToken(FIRToken::comma,
"expected ','") ||
3580 parseExp(enable,
"expected enable in 'assume'") ||
3581 parseToken(FIRToken::comma,
"expected ','") ||
3582 parseGetSpelling(formatString) ||
3583 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3586 SmallVector<Value, 4> operands;
3587 while (!consumeIf(FIRToken::r_paren)) {
3588 operands.push_back({});
3589 if (parseToken(FIRToken::comma,
"expected ','") ||
3590 parseExp(operands.back(),
"expected operand in 'assume'"))
3594 if (parseOptionalName(name) || parseOptionalInfo())
3597 locationProcessor.setLoc(startTok.getLoc());
3599 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3600 operands, name.getValue());
3605ParseResult FIRStmtParser::parseCover() {
3606 auto startTok = consumeToken(FIRToken::lp_cover);
3608 Value clock, predicate, enable;
3611 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3612 parseToken(FIRToken::comma,
"expected ','") ||
3613 parseExp(predicate,
"expected predicate in 'cover'") ||
3614 parseToken(FIRToken::comma,
"expected ','") ||
3615 parseExp(enable,
"expected enable in 'cover'") ||
3616 parseToken(FIRToken::comma,
"expected ','") ||
3617 parseGetSpelling(message) ||
3618 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3619 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3620 parseOptionalName(name) || parseOptionalInfo())
3623 locationProcessor.setLoc(startTok.getLoc());
3625 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3626 ValueRange{}, name.getValue());
3632ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3633 auto startTok = consumeToken(FIRToken::kw_when);
3637 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3641 if (parseExp(condition,
"expected condition in 'when'") ||
3642 parseToken(FIRToken::colon,
"expected ':' in when") ||
3643 parseOptionalInfo())
3646 locationProcessor.setLoc(startTok.getLoc());
3648 auto whenStmt = WhenOp::create(builder, condition,
false);
3651 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3655 if (getToken().isNot(FIRToken::kw_else))
3660 auto elseIndent = getIndentation();
3661 if (elseIndent && *elseIndent < whenIndent)
3664 consumeToken(FIRToken::kw_else);
3667 whenStmt.createElseRegion();
3673 if (getToken().is(FIRToken::kw_when)) {
3675 auto subParser = std::make_unique<FIRStmtParser>(
3676 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3679 return subParser->parseSimpleStmt(whenIndent);
3683 LocationAttr elseLoc;
3684 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3685 parseOptionalInfoLocator(elseLoc) ||
3686 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3695ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3696 auto startLoc = getToken().getLoc();
3697 locationProcessor.setLoc(startLoc);
3699 if (parseEnumType(type))
3703 auto enumType = type_dyn_cast<FEnumType>(type);
3705 return emitError(startLoc,
3706 "expected enumeration type in enumeration expression");
3709 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3710 parseId(tag,
"expected enumeration tag"))
3714 if (consumeIf(FIRToken::r_paren)) {
3717 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3718 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3719 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3720 input = ConstantOp::create(builder, type, attr);
3723 if (parseToken(FIRToken::comma,
"expected ','") ||
3724 parseExp(input,
"expected expression in enumeration value") ||
3725 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3729 value = FEnumCreateOp::create(builder, enumType, tag, input);
3737ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3738 auto startTok = consumeToken(FIRToken::kw_match);
3740 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3744 if (parseExp(input,
"expected expression in 'match'") ||
3745 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3746 parseOptionalInfo())
3749 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3751 return mlir::emitError(
3753 "expected enumeration type for 'match' statement, but got ")
3756 locationProcessor.setLoc(startTok.getLoc());
3758 SmallVector<Attribute> tags;
3759 SmallVector<std::unique_ptr<Region>> regions;
3761 auto tagLoc = getToken().getLoc();
3764 auto caseIndent = getIndentation();
3765 if (!caseIndent || *caseIndent <= matchIndent)
3769 StringRef tagSpelling;
3770 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3772 auto tagIndex = enumType.getElementIndex(tagSpelling);
3774 return emitError(tagLoc,
"tag ")
3775 << tagSpelling <<
" not a member of enumeration " << enumType;
3776 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3777 tags.push_back(tag);
3780 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3783 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3788 UnbundledValueRestorer x(moduleContext.unbundledValues);
3791 if (consumeIf(FIRToken::l_paren)) {
3792 StringAttr identifier;
3793 if (parseId(identifier,
"expected identifier for 'case' binding"))
3797 auto dataType = enumType.getElementType(*tagIndex);
3798 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3800 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3804 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3808 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3809 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3812 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3816 auto subParser = std::make_unique<FIRStmtParser>(
3817 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3819 if (subParser->parseSimpleStmtBlock(*caseIndent))
3823 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3830ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3831 auto loc = getToken().getLoc();
3834 if (parseId(
id,
"expected domain expression") ||
3835 moduleContext.lookupSymbolEntry(entry,
id, loc))
3838 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3840 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3841 parseFieldId(field,
"expected field name") ||
3842 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3846 if (parseOptionalExpPostscript(result,
false))
3849 auto type = result.getType();
3850 if (!type_isa<DomainType>(type))
3851 return emitError(loc) <<
"expected domain-type expression, got " << type;
3858ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3859 auto token = getToken().getKind();
3860 if (token == FIRToken::lp_probe)
3861 return parseProbe(result);
3862 if (token == FIRToken::lp_rwprobe)
3863 return parseRWProbe(result);
3868 return parseStaticRefExp(result, message);
3875ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3876 const Twine &message) {
3877 auto parseIdOrInstance = [&]() -> ParseResult {
3879 auto loc = getToken().getLoc();
3881 if (parseId(
id, message) ||
3882 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3886 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3889 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3892 StringRef fieldName;
3894 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3895 parseFieldId(fieldName,
"expected field name") ||
3896 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3898 return failure(parseIdOrInstance() ||
3899 parseOptionalExpPostscript(result,
false));
3910ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3912 const Twine &message) {
3913 auto loc = getToken().getLoc();
3917 if (parseId(
id, message) ||
3918 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3930 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3932 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3934 StringRef fieldName;
3935 auto loc = getToken().getLoc();
3936 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3937 parseFieldId(fieldName,
"expected field name"))
3942 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3943 for (
auto &elt : ubEntry) {
3944 if (elt.first == fieldAttr) {
3947 auto &instResult = elt.second;
3950 auto *defining = instResult.getDefiningOp();
3952 if (isa<WireOp>(defining)) {
3953 result = instResult;
3958 auto type = instResult.getType();
3962 auto annotations = getConstants().emptyArrayAttr;
3963 StringAttr sym = {};
3964 SmallString<64> name;
3965 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3966 locationProcessor.setLoc(loc);
3967 OpBuilder::InsertionGuard guard(builder);
3968 builder.setInsertionPoint(defining);
3970 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3972 auto bounceVal = bounce.getDataRaw();
3975 instResult.replaceAllUsesWith(bounceVal);
3978 builder.setInsertionPointAfter(defining);
3979 if (
foldFlow(instResult) == Flow::Source)
3981 getConstants().options.warnOnTruncation);
3984 getConstants().options.warnOnTruncation);
3988 result = instResult = bounce.getDataRaw();
3994 emitError(loc,
"use of invalid field name '")
3995 << fieldName <<
"' on bundle value";
4000 result = cast<Value>(symtabEntry);
4004 assert(isa<BlockArgument>(result) ||
4005 result.getDefiningOp<hw::InnerSymbolOpInterface>());
4011 type = result.getType();
4013 if (consumeIf(FIRToken::period)) {
4014 SmallVector<StringRef, 3> fields;
4015 if (parseFieldIdSeq(fields,
"expected field name"))
4017 for (
auto fieldName : fields) {
4018 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4019 if (
auto index = bundle.getElementIndex(fieldName)) {
4020 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4021 type = bundle.getElementTypePreservingConst(*index);
4024 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
4025 if (
auto index = bundle.getElementIndex(fieldName)) {
4026 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4027 type = bundle.getElementTypePreservingConst(*index);
4031 return emitError(loc,
"subfield requires bundle operand")
4032 <<
"got " << type <<
"\n";
4034 return emitError(loc,
4035 "unknown field '" + fieldName +
"' in bundle type ")
4040 if (consumeIf(FIRToken::l_square)) {
4041 auto loc = getToken().
getLoc();
4043 if (parseIntLit(index,
"expected index") ||
4044 parseToken(FIRToken::r_square,
"expected ']'"))
4048 return emitError(loc,
"invalid index specifier");
4050 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
4051 if ((
unsigned)index < vector.getNumElements()) {
4052 refResult = refResult.
getSubField(vector.getFieldID(index));
4053 type = vector.getElementTypePreservingConst();
4056 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
4057 if ((
unsigned)index < vector.getNumElements()) {
4058 refResult = refResult.
getSubField(vector.getFieldID(index));
4059 type = vector.getElementTypePreservingConst();
4063 return emitError(loc,
"subindex requires vector operand");
4065 return emitError(loc,
"out of range index '")
4066 << index <<
"' for vector type " << type;
4074ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4075 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4076 StringRef intrinsic;
4077 ArrayAttr parameters;
4080 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4081 parseOptionalParams(parameters))
4084 if (consumeIf(FIRToken::colon)) {
4085 if (
parseType(type,
"expected intrinsic return type"))
4087 }
else if (!isStatement)
4088 return emitError(
"expected ':' in intrinsic expression");
4090 SmallVector<Value> operands;
4091 auto loc = startTok.getLoc();
4092 if (consumeIf(FIRToken::comma)) {
4093 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4095 if (parseExp(operand,
"expected operand in intrinsic"))
4097 operands.push_back(operand);
4098 locationProcessor.setLoc(loc);
4103 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4108 if (parseOptionalInfo())
4111 locationProcessor.setLoc(loc);
4113 auto op = GenericIntrinsicOp::create(
4114 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4116 result = op.getResult();
4121ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4122 if (!consumeIf(FIRToken::less))
4125 SmallVector<Attribute, 8> parameters;
4126 SmallPtrSet<StringAttr, 8> seen;
4127 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4131 if (parseParameter(name, value, loc))
4133 auto typedValue = dyn_cast<TypedAttr>(value);
4135 return emitError(loc)
4136 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4137 if (!seen.insert(name).second)
4138 return emitError(loc,
"redefinition of parameter '" +
4139 name.getValue() +
"'");
4140 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4145 resultParameters = ArrayAttr::get(getContext(), parameters);
4151ParseResult FIRStmtParser::parsePathExp(Value &result) {
4152 auto startTok = consumeToken(FIRToken::lp_path);
4153 locationProcessor.setLoc(startTok.getLoc());
4155 if (parseGetSpelling(target) ||
4156 parseToken(FIRToken::string,
4157 "expected target string in path expression") ||
4158 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4160 result = UnresolvedPathOp::create(
4166ParseResult FIRStmtParser::parseDomainInstantiation() {
4167 auto startTok = consumeToken(FIRToken::kw_domain);
4168 auto startLoc = startTok.getLoc();
4171 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4174 locationProcessor.setLoc(startTok.getLoc());
4176 StringAttr instanceName;
4177 StringAttr domainKind;
4180 parseId(instanceName,
"expected domain instance name") ||
4181 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4182 parseId(domainKind,
"expected domain type name"))
4187 const auto &domainMap = getConstants().domainMap;
4188 auto lookup = domainMap.find(domainKind.getValue());
4189 if (lookup == domainMap.end())
4190 return emitError(startTok.getLoc())
4191 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4193 auto domainType = DomainType::getFromDomainOp(lookup->second);
4196 SmallVector<Value> fieldValues;
4197 if (consumeIf(FIRToken::l_paren)) {
4199 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4201 if (parseExp(value,
"expected field value expression"))
4203 fieldValues.push_back(value);
4209 if (parseOptionalInfo())
4212 locationProcessor.setLoc(startLoc);
4214 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4217 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4222ParseResult FIRStmtParser::parseDomainDefine() {
4223 auto startTok = consumeToken(FIRToken::kw_domain_define);
4224 auto startLoc = startTok.getLoc();
4225 locationProcessor.setLoc(startLoc);
4229 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4230 parseDomainExp(src) || parseOptionalInfo())
4233 emitConnect(builder, dest, src, getConstants().options.warnOnTruncation);
4238ParseResult FIRStmtParser::parseRefDefine() {
4239 auto startTok = consumeToken(FIRToken::kw_define);
4242 if (parseStaticRefExp(target,
4243 "expected static reference expression in 'define'") ||
4244 parseToken(FIRToken::equal,
4245 "expected '=' after define reference expression") ||
4246 parseRefExp(src,
"expected reference expression in 'define'") ||
4247 parseOptionalInfo())
4251 if (!type_isa<RefType>(target.getType()))
4252 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4253 "'define' target (LHS), got ")
4254 << target.getType();
4255 if (!type_isa<RefType>(src.getType()))
4256 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4257 "'define' source (RHS), got ")
4262 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4263 return emitError(startTok.getLoc(),
4264 "cannot define into a sub-element of a reference");
4266 locationProcessor.setLoc(startTok.getLoc());
4269 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4270 << target.getType() <<
" with incompatible reference of type "
4273 emitConnect(builder, target, src, getConstants().options.warnOnTruncation);
4280ParseResult FIRStmtParser::parseRefRead(Value &result) {
4281 auto startTok = consumeToken(FIRToken::lp_read);
4284 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4285 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4288 locationProcessor.setLoc(startTok.getLoc());
4291 if (!type_isa<RefType>(ref.getType()))
4292 return emitError(startTok.getLoc(),
4293 "expected reference-type expression in 'read', got ")
4296 result = RefResolveOp::create(builder, ref);
4302ParseResult FIRStmtParser::parseProbe(Value &result) {
4303 auto startTok = consumeToken(FIRToken::lp_probe);
4306 if (parseStaticRefExp(staticRef,
4307 "expected static reference expression in 'probe'") ||
4308 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4311 locationProcessor.setLoc(startTok.getLoc());
4314 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4315 return emitError(startTok.getLoc(),
4316 "expected base-type expression in 'probe', got ")
4317 << staticRef.getType();
4321 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4322 MemoryDebugPortOp, MemoryPortAccessOp>(
4323 staticRef.getDefiningOp()))
4324 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4326 result = RefSendOp::create(builder, staticRef);
4332ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4333 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4336 Type parsedTargetType;
4337 if (parseRWProbeStaticRefExp(
4338 staticRef, parsedTargetType,
4339 "expected static reference expression in 'rwprobe'") ||
4340 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4343 locationProcessor.setLoc(startTok.getLoc());
4349 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4351 return emitError(startTok.getLoc(),
4352 "expected base-type expression in 'rwprobe', got ")
4353 << parsedTargetType;
4356 auto *definingOp = root.getDefiningOp();
4358 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4359 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4360 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4364 return emitError(startTok.getLoc(),
"cannot force target of type ")
4368 auto op = RWProbeOp::create(builder, forceableType,
4369 getConstants().placeholderInnerRef);
4376ParseResult FIRStmtParser::parseRefForce() {
4377 auto startTok = consumeToken(FIRToken::lp_force);
4379 Value clock, pred, dest, src;
4380 if (parseExp(clock,
"expected clock expression in force") ||
4381 parseToken(FIRToken::comma,
"expected ','") ||
4382 parseExp(pred,
"expected predicate expression in force") ||
4383 parseToken(FIRToken::comma,
"expected ','") ||
4384 parseRefExp(dest,
"expected destination reference expression in force") ||
4385 parseToken(FIRToken::comma,
"expected ','") ||
4386 parseExp(src,
"expected source expression in force") ||
4387 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4388 parseOptionalInfo())
4392 auto ref = type_dyn_cast<RefType>(dest.getType());
4393 if (!ref || !ref.getForceable())
4396 "expected rwprobe-type expression for force destination, got ")
4398 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4400 return emitError(startTok.getLoc(),
4401 "expected base-type for force source, got ")
4403 if (!srcBaseType.isPassive())
4404 return emitError(startTok.getLoc(),
4405 "expected passive value for force source, got ")
4408 locationProcessor.setLoc(startTok.getLoc());
4411 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4412 if (noConstSrcType != ref.getType()) {
4414 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4416 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4418 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4419 << src.getType() <<
" cannot target destination "
4423 RefForceOp::create(builder, clock, pred, dest, src);
4429ParseResult FIRStmtParser::parseRefForceInitial() {
4430 auto startTok = consumeToken(FIRToken::lp_force_initial);
4434 dest,
"expected destination reference expression in force_initial") ||
4435 parseToken(FIRToken::comma,
"expected ','") ||
4436 parseExp(src,
"expected source expression in force_initial") ||
4437 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4438 parseOptionalInfo())
4442 auto ref = type_dyn_cast<RefType>(dest.getType());
4443 if (!ref || !ref.getForceable())
4444 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4445 "force_initial destination, got ")
4447 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4449 return emitError(startTok.getLoc(),
4450 "expected base-type expression for force_initial "
4453 if (!srcBaseType.isPassive())
4454 return emitError(startTok.getLoc(),
4455 "expected passive value for force_initial source, got ")
4458 locationProcessor.setLoc(startTok.getLoc());
4461 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4462 if (noConstSrcType != ref.getType()) {
4464 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4466 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4468 return emitError(startTok.getLoc(),
4469 "incompatible force_initial source of type ")
4470 << src.getType() <<
" cannot target destination "
4474 auto value = APInt::getAllOnes(1);
4475 auto type = UIntType::get(builder.getContext(), 1);
4476 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4477 value.getBitWidth(),
4478 IntegerType::Unsigned),
4480 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4481 RefForceInitialOp::create(builder, pred, dest, src);
4487ParseResult FIRStmtParser::parseRefRelease() {
4488 auto startTok = consumeToken(FIRToken::lp_release);
4490 Value clock, pred, dest;
4491 if (parseExp(clock,
"expected clock expression in release") ||
4492 parseToken(FIRToken::comma,
"expected ','") ||
4493 parseExp(pred,
"expected predicate expression in release") ||
4494 parseToken(FIRToken::comma,
"expected ','") ||
4496 "expected destination reference expression in release") ||
4497 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4498 parseOptionalInfo())
4502 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4503 !ref || !ref.getForceable())
4506 "expected rwprobe-type expression for release destination, got ")
4509 locationProcessor.setLoc(startTok.getLoc());
4511 RefReleaseOp::create(builder, clock, pred, dest);
4517ParseResult FIRStmtParser::parseRefReleaseInitial() {
4518 auto startTok = consumeToken(FIRToken::lp_release_initial);
4523 "expected destination reference expression in release_initial") ||
4524 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4525 parseOptionalInfo())
4529 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4530 !ref || !ref.getForceable())
4531 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4532 "release_initial destination, got ")
4535 locationProcessor.setLoc(startTok.getLoc());
4537 auto value = APInt::getAllOnes(1);
4538 auto type = UIntType::get(builder.getContext(), 1);
4539 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4540 value.getBitWidth(),
4541 IntegerType::Unsigned),
4543 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4544 RefReleaseInitialOp::create(builder, pred, dest);
4550ParseResult FIRStmtParser::parseConnect() {
4551 auto startTok = consumeToken(FIRToken::kw_connect);
4552 auto loc = startTok.getLoc();
4555 if (parseExp(lhs,
"expected connect expression") ||
4556 parseToken(FIRToken::comma,
"expected ','") ||
4557 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4560 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4561 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4562 if (!lhsType || !rhsType)
4563 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4564 "cannot connect reference or property types");
4566 if (lhsType.containsReference() || rhsType.containsReference())
4567 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4568 "cannot connect types containing references");
4571 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4572 "cannot connect non-equivalent type ")
4573 << rhsType <<
" to " << lhsType;
4575 locationProcessor.setLoc(loc);
4577 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4578 getConstants().options.warnOnTruncation);
4589ParseResult FIRStmtParser::parsePropAssert() {
4590 auto startTok = consumeToken(FIRToken::kw_propassert);
4591 auto loc = startTok.getLoc();
4593 llvm::SMLoc conditionLoc = getToken().getLoc(), messageLoc;
4594 Value condition, message;
4595 if (parseExp(condition,
"expected condition in 'propassert'") ||
4596 parseToken(FIRToken::comma,
"expected ','"))
4599 if (getToken().is(FIRToken::string)) {
4600 if (removedFeature({8, 0, 0},
"string messages in property asserts"))
4602 StringRef messageStr;
4603 messageLoc = getToken().getLoc();
4604 if (parseGetSpelling(messageStr) ||
4605 parseToken(FIRToken::string,
"expected message string in 'propassert'"))
4607 locationProcessor.setLoc(messageLoc);
4609 message = moduleContext.getCachedConstant<StringConstantOp>(
4610 builder, attr, builder.getType<StringType>(), attr);
4614 "string property expression message in property asserts"))
4616 messageLoc = getToken().getLoc();
4617 if (parseExp(message,
"expected message in 'propassert'"))
4621 if (!isa<BoolType>(condition.getType()))
4622 return emitError(conditionLoc,
4623 "propassert condition must be of boolean type");
4626 if (!type_isa<StringType>(message.getType()))
4627 return emitError(messageLoc,
"propassert message must be a string type");
4629 if (parseOptionalInfo())
4632 locationProcessor.setLoc(loc);
4633 PropertyAssertOp::create(builder, condition, message);
4638ParseResult FIRStmtParser::parsePropAssign() {
4639 auto startTok = consumeToken(FIRToken::kw_propassign);
4640 auto loc = startTok.getLoc();
4643 if (parseExp(lhs,
"expected propassign expression") ||
4644 parseToken(FIRToken::comma,
"expected ','") ||
4645 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4648 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4649 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4650 if (!lhsType || !rhsType)
4651 return emitError(loc,
"can only propassign property types");
4652 locationProcessor.setLoc(loc);
4653 if (lhsType != rhsType) {
4655 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4656 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4658 return emitError(loc,
"cannot propassign non-equivalent type ")
4659 << rhsType <<
" to " << lhsType;
4661 PropAssignOp::create(builder, lhs, rhs);
4666ParseResult FIRStmtParser::parseInvalidate() {
4667 auto startTok = consumeToken(FIRToken::kw_invalidate);
4672 auto loc = getToken().getLoc();
4674 if (parseId(
id,
"expected static reference expression") ||
4675 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4680 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4681 if (parseOptionalExpPostscript(lhs,
false) ||
4682 parseOptionalInfo())
4685 locationProcessor.setLoc(startTok.getLoc());
4686 emitInvalidate(lhs);
4693 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4695 if (getToken().isNot(FIRToken::period)) {
4696 locationProcessor.setLoc(loc);
4698 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4700 for (
auto elt : ubEntry)
4701 emitInvalidate(elt.second);
4707 StringRef fieldName;
4708 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4709 parseFieldId(fieldName,
"expected field name") ||
4710 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4714 if (parseOptionalExpPostscript(lhs,
false) ||
4715 parseOptionalInfo())
4718 locationProcessor.setLoc(startTok.getLoc());
4719 emitInvalidate(lhs);
4723ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4725 auto startTok = consumeToken();
4726 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4727 "consumed an unexpected token");
4728 auto loc = startTok.getLoc();
4731 if (parseId(
id,
"expected layer identifer") ||
4732 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4733 parseOptionalInfo())
4736 locationProcessor.setLoc(loc);
4738 StringRef rootLayer;
4739 SmallVector<FlatSymbolRefAttr> nestedLayers;
4743 rootLayer = layerSym.getRootReference();
4744 auto nestedRefs = layerSym.getNestedReferences();
4745 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4746 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4749 auto layerBlockOp = LayerBlockOp::create(
4751 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4752 layerBlockOp->getRegion(0).push_back(
new Block());
4754 if (getIndentation() > indent)
4755 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4756 layerBlockOp.getLayerName()))
4764ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4765 auto loc = getToken().getLoc();
4768 if (consumeIf(FIRToken::kw_is)) {
4769 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4770 parseOptionalInfo())
4773 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4776 locationProcessor.setLoc(loc);
4777 emitInvalidate(lhs);
4781 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4784 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4788 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4791 locationProcessor.setLoc(loc);
4793 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4794 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4795 if (!lhsType || !rhsType)
4796 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4797 "cannot connect reference or property types");
4799 if (lhsType.containsReference() || rhsType.containsReference())
4800 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4801 "cannot connect types containing references");
4804 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4805 "cannot connect non-equivalent type ")
4806 << rhsType <<
" to " << lhsType;
4808 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4809 getConstants().options.warnOnTruncation);
4817ParseResult FIRStmtParser::parseInstance() {
4818 auto startTok = consumeToken(FIRToken::kw_inst);
4822 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4826 StringRef moduleName;
4827 if (parseId(
id,
"expected instance name") ||
4828 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4829 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4832 locationProcessor.setLoc(startTok.getLoc());
4835 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4836 if (!referencedModule)
4839 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4841 auto annotations = getConstants().emptyArrayAttr;
4842 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4844 hw::InnerSymAttr sym = {};
4845 auto result = InstanceOp::create(
4846 builder, referencedModule,
id, NameKindEnum::InterestingName,
4847 annotations.getValue(), portAnnotations,
false,
false, sym);
4853 unbundledValueEntry.reserve(modulePorts.size());
4854 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4855 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4859 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4860 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4861 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4866ParseResult FIRStmtParser::parseInstanceChoice() {
4867 auto startTok = consumeToken(FIRToken::kw_instchoice);
4868 SMLoc loc = startTok.getLoc();
4871 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4878 StringRef defaultModuleName;
4879 StringRef optionGroupName;
4880 if (parseId(
id,
"expected instance name") ||
4881 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4882 parseId(defaultModuleName,
"expected module name") ||
4883 parseToken(FIRToken::comma,
"expected ','") ||
4884 parseId(optionGroupName,
"expected option group name") ||
4885 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4886 parseOptionalInfo())
4889 locationProcessor.setLoc(startTok.getLoc());
4893 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4897 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4900 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4902 return emitError(loc,
4903 "use of undefined option group '" + optionGroupName +
"'");
4905 auto baseIndent = getIndentation();
4906 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4907 while (getIndentation() == baseIndent) {
4909 StringRef caseModuleName;
4910 if (parseId(caseId,
"expected a case identifier") ||
4911 parseToken(FIRToken::equal_greater,
4912 "expected '=> in instance choice definition") ||
4913 parseId(caseModuleName,
"expected module name"))
4916 auto caseModule = getReferencedModule(loc, caseModuleName);
4920 for (
const auto &[defaultPort, casePort] :
4921 llvm::zip(modulePorts, caseModule.getPorts())) {
4922 if (defaultPort.name != casePort.name)
4923 return emitError(loc,
"instance case module port '")
4924 << casePort.name.getValue()
4925 <<
"' does not match the default module port '"
4926 << defaultPort.name.getValue() <<
"'";
4927 if (defaultPort.type != casePort.type)
4928 return emitError(loc,
"instance case port '")
4929 << casePort.name.getValue()
4930 <<
"' type does not match the default module port";
4934 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4936 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4937 caseModules.emplace_back(optionCase, caseModule);
4940 auto annotations = getConstants().emptyArrayAttr;
4941 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4945 auto result = InstanceChoiceOp::create(
4946 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4947 annotations.getValue(), portAnnotations, sym);
4951 unbundledValueEntry.reserve(modulePorts.size());
4952 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4953 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4955 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4956 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4957 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4960FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4961 StringRef moduleName) {
4962 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4963 if (!referencedModule) {
4965 "use of undefined module name '" + moduleName +
"' in instance");
4968 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4969 emitError(loc,
"cannot create instance of class '" + moduleName +
4970 "', did you mean object?");
4973 return referencedModule;
4977ParseResult FIRStmtParser::parseObject() {
4978 auto startTok = consumeToken(FIRToken::kw_object);
4982 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4985 if (requireFeature({6, 0, 0},
"object statements"))
4989 StringRef className;
4990 if (parseId(
id,
"expected object name") ||
4991 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4992 parseId(className,
"expected class name") || parseOptionalInfo())
4995 locationProcessor.setLoc(startTok.getLoc());
4998 const auto &classMap = getConstants().classMap;
4999 auto lookup = classMap.find(className);
5000 if (lookup == classMap.end())
5001 return emitError(startTok.getLoc(),
"use of undefined class name '" +
5002 className +
"' in object");
5003 auto referencedClass = lookup->getSecond();
5004 auto result = ObjectOp::create(builder, referencedClass,
id);
5005 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5009ParseResult FIRStmtParser::parseCombMem() {
5011 auto startTok = consumeToken(FIRToken::kw_cmem);
5015 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5020 if (parseId(
id,
"expected cmem name") ||
5021 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
5022 parseType(type,
"expected cmem type") || parseOptionalInfo())
5025 locationProcessor.setLoc(startTok.getLoc());
5028 auto vectorType = type_dyn_cast<FVectorType>(type);
5030 return emitError(
"cmem requires vector type");
5032 auto annotations = getConstants().emptyArrayAttr;
5033 StringAttr sym = {};
5034 auto result = CombMemOp::create(
5035 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
5036 NameKindEnum::InterestingName, annotations, sym);
5037 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5041ParseResult FIRStmtParser::parseSeqMem() {
5043 auto startTok = consumeToken(FIRToken::kw_smem);
5047 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5052 RUWBehavior ruw = RUWBehavior::Undefined;
5054 if (parseId(
id,
"expected smem name") ||
5055 parseToken(FIRToken::colon,
"expected ':' in smem") ||
5059 if (consumeIf(FIRToken::comma)) {
5064 if (parseOptionalInfo()) {
5068 locationProcessor.setLoc(startTok.getLoc());
5071 auto vectorType = type_dyn_cast<FVectorType>(type);
5073 return emitError(
"smem requires vector type");
5075 auto annotations = getConstants().emptyArrayAttr;
5076 StringAttr sym = {};
5077 auto result = SeqMemOp::create(
5078 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
5079 id, NameKindEnum::InterestingName, annotations, sym);
5080 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5092ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
5093 auto startTok = consumeToken(FIRToken::kw_mem);
5097 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5101 if (parseId(
id,
"expected mem name") ||
5102 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
5106 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5107 RUWBehavior ruw = RUWBehavior::Undefined;
5109 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5113 auto nextIndent = getIndentation();
5114 if (!nextIndent || *nextIndent <= memIndent)
5117 auto spelling = getTokenSpelling();
5118 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
5119 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
5122 if (spelling ==
"data-type") {
5124 return emitError(
"'mem' type specified multiple times"), failure();
5126 if (
parseType(type,
"expected type in data-type declaration"))
5130 if (spelling ==
"depth") {
5131 if (parseIntLit(depth,
"expected integer in depth specification"))
5135 if (spelling ==
"read-latency") {
5136 if (parseIntLit(readLatency,
"expected integer latency"))
5140 if (spelling ==
"write-latency") {
5141 if (parseIntLit(writeLatency,
"expected integer latency"))
5145 if (spelling ==
"read-under-write") {
5146 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5147 FIRToken::kw_undefined))
5148 return emitError(
"expected specifier"), failure();
5150 if (parseOptionalRUW(ruw))
5155 MemOp::PortKind portKind;
5156 if (spelling ==
"reader")
5157 portKind = MemOp::PortKind::Read;
5158 else if (spelling ==
"writer")
5159 portKind = MemOp::PortKind::Write;
5160 else if (spelling ==
"readwriter")
5161 portKind = MemOp::PortKind::ReadWrite;
5163 return emitError(
"unexpected field in 'mem' declaration"), failure();
5166 if (parseId(portName,
"expected port name"))
5168 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5170 return emitError(
"unexpected type, must be base type");
5171 ports.push_back({builder.getStringAttr(portName),
5172 MemOp::getTypeForPort(depth, baseType, portKind)});
5174 while (!getIndentation().has_value()) {
5175 if (parseId(portName,
"expected port name"))
5177 ports.push_back({builder.getStringAttr(portName),
5178 MemOp::getTypeForPort(depth, baseType, portKind)});
5189 llvm::array_pod_sort(ports.begin(), ports.end(),
5190 [](
const std::pair<StringAttr, Type> *lhs,
5191 const std::pair<StringAttr, Type> *rhs) ->
int {
5192 return lhs->first.getValue().compare(
5193 rhs->first.getValue());
5196 auto annotations = getConstants().emptyArrayAttr;
5197 SmallVector<Attribute, 4> resultNames;
5198 SmallVector<Type, 4> resultTypes;
5199 SmallVector<Attribute, 4> resultAnnotations;
5200 for (
auto p : ports) {
5201 resultNames.push_back(p.first);
5202 resultTypes.push_back(p.second);
5203 resultAnnotations.push_back(annotations);
5206 locationProcessor.setLoc(startTok.getLoc());
5208 auto result = MemOp::create(
5209 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5210 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5211 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5212 MemoryInitAttr(), StringAttr());
5215 unbundledValueEntry.reserve(result.getNumResults());
5216 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5217 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5219 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5220 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5221 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5225ParseResult FIRStmtParser::parseNode() {
5226 auto startTok = consumeToken(FIRToken::kw_node);
5230 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5235 if (parseId(
id,
"expected node name") ||
5236 parseToken(FIRToken::equal,
"expected '=' in node") ||
5237 parseExp(initializer,
"expected expression for node") ||
5238 parseOptionalInfo())
5241 locationProcessor.setLoc(startTok.getLoc());
5253 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5254 auto initializerBaseType =
5255 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5256 if (type_isa<AnalogType>(initializerType) ||
5257 !(initializerBaseType && initializerBaseType.isPassive())) {
5258 emitError(startTok.getLoc())
5259 <<
"Node cannot be analog and must be passive or passive under a flip "
5260 << initializer.getType();
5264 auto annotations = getConstants().emptyArrayAttr;
5265 StringAttr sym = {};
5267 auto result = NodeOp::create(builder, initializer,
id,
5268 NameKindEnum::InterestingName, annotations, sym);
5269 return moduleContext.addSymbolEntry(
id, result.getResult(),
5274ParseResult FIRStmtParser::parseWire() {
5275 auto startTok = consumeToken(FIRToken::kw_wire);
5279 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5284 if (parseId(
id,
"expected wire name") ||
5285 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5290 SmallVector<Value> domains;
5291 if (consumeIf(FIRToken::kw_domains)) {
5295 if (parseToken(FIRToken::l_square,
"expected '[' after 'domains'"))
5298 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5299 StringRef domainName;
5300 auto domainLoc = getToken().getLoc();
5301 if (parseId(domainName,
"expected domain name"))
5306 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5311 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5314 if (!isa<DomainType>(domainValue.getType()))
5315 return emitError(domainLoc)
5316 <<
"'" << domainName <<
"' is not a domain";
5318 domains.push_back(domainValue);
5324 if (parseOptionalInfo())
5327 locationProcessor.setLoc(startTok.getLoc());
5329 auto annotations = getConstants().emptyArrayAttr;
5330 StringAttr sym = {};
5333 auto namekind = isa<PropertyType, RefType>(type)
5334 ? NameKindEnum::DroppableName
5335 : NameKindEnum::InterestingName;
5337 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym,
5339 return moduleContext.addSymbolEntry(
id, result.getResult(),
5353ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5354 auto startTok = consumeToken(FIRToken::kw_reg);
5358 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5367 if (parseId(
id,
"expected reg name") ||
5368 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5370 parseToken(FIRToken::comma,
"expected ','") ||
5371 parseExp(clock,
"expected expression for register clock"))
5374 if (!type_isa<FIRRTLBaseType>(type))
5375 return emitError(startTok.getLoc(),
"register must have base type");
5378 Value resetSignal, resetValue;
5379 if (consumeIf(FIRToken::kw_with)) {
5380 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5383 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5391 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5393 auto indent = getIndentation();
5394 if (!indent || *indent <= regIndent)
5395 if (!hasExtraLParen)
5396 return emitError(
"expected indented reset specifier in reg"), failure();
5398 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5399 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5400 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5401 parseExp(resetSignal,
"expected expression for reset signal") ||
5402 parseToken(FIRToken::comma,
"expected ','"))
5410 if (getTokenSpelling() ==
id) {
5412 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5414 resetSignal = Value();
5416 if (parseExp(resetValue,
"expected expression for reset value") ||
5417 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5421 if (hasExtraLParen &&
5422 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5428 if (parseOptionalInfo())
5431 locationProcessor.setLoc(startTok.getLoc());
5433 ArrayAttr annotations = getConstants().emptyArrayAttr;
5435 StringAttr sym = {};
5438 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5439 NameKindEnum::InterestingName, annotations, sym)
5442 result = RegOp::create(builder, type, clock,
id,
5443 NameKindEnum::InterestingName, annotations, sym)
5445 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5453ParseResult FIRStmtParser::parseRegisterWithReset() {
5454 auto startTok = consumeToken(FIRToken::kw_regreset);
5458 Value clock, resetSignal, resetValue;
5460 if (parseId(
id,
"expected reg name") ||
5461 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5463 parseToken(FIRToken::comma,
"expected ','") ||
5464 parseExp(clock,
"expected expression for register clock") ||
5465 parseToken(FIRToken::comma,
"expected ','") ||
5466 parseExp(resetSignal,
"expected expression for register reset") ||
5467 parseToken(FIRToken::comma,
"expected ','") ||
5468 parseExp(resetValue,
"expected expression for register reset value") ||
5469 parseOptionalInfo())
5472 if (!type_isa<FIRRTLBaseType>(type))
5473 return emitError(startTok.getLoc(),
"register must have base type");
5475 locationProcessor.setLoc(startTok.getLoc());
5478 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5479 NameKindEnum::InterestingName,
5480 getConstants().emptyArrayAttr, StringAttr{})
5483 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5488ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5492 auto startTok = consumeToken(FIRToken::kw_contract);
5495 SmallVector<StringRef> ids;
5496 SmallVector<SMLoc> locs;
5497 SmallVector<Value> values;
5498 SmallVector<Type> types;
5499 if (!consumeIf(FIRToken::colon)) {
5500 auto parseContractId = [&] {
5502 locs.push_back(getToken().
getLoc());
5503 if (parseId(
id,
"expected contract result name"))
5508 auto parseContractValue = [&] {
5510 if (parseExp(value,
"expected expression for contract result"))
5512 values.push_back(value);
5513 types.push_back(value.getType());
5516 if (parseListUntil(FIRToken::equal, parseContractId) ||
5517 parseListUntil(FIRToken::colon, parseContractValue))
5520 if (parseOptionalInfo())
5524 if (ids.size() != values.size())
5525 return emitError(startTok.getLoc())
5526 <<
"contract requires same number of results and expressions; got "
5527 << ids.size() <<
" results and " << values.size()
5528 <<
" expressions instead";
5530 locationProcessor.setLoc(startTok.getLoc());
5534 auto contract = ContractOp::create(builder, types, values);
5535 auto &block = contract.getBody().emplaceBlock();
5539 FIRModuleContext::ContextScope scope(moduleContext, &block);
5540 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5541 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5542 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5545 if (getIndentation() > blockIndent)
5546 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5551 for (
auto [
id, loc, value, result] :
5552 llvm::zip(ids, locs, values, contract.getResults())) {
5554 moduleContext.removeSymbolEntry(
id);
5555 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5568struct FIRCircuitParser :
public FIRParser {
5569 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5571 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5574 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5575 mlir::TimingScope &ts);
5580 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5581 SmallVectorImpl<Attribute> &attrs);
5583 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5585 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5586 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5587 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5588 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5589 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5590 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5591 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5592 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5594 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5596 ParseResult parseLayerName(SymbolRefAttr &result);
5597 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5598 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5599 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5600 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5601 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5602 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5603 ArrayAttr &knownLayers,
5604 ArrayAttr &externalRequirements);
5606 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5607 SmallVectorImpl<SMLoc> &resultPortLocs,
5611 ParseResult skipToModuleEnd(
unsigned indent);
5613 ParseResult parseTypeDecl();
5615 ParseResult parseOptionDecl(CircuitOp circuit);
5617 ParseResult parseLayer(CircuitOp circuit);
5619 ParseResult resolveDomains(
5620 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5621 const DenseMap<Attribute, size_t> &nameToIndex,
5622 SmallVectorImpl<Attribute> &domainsByIndex);
5625 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5626 const DenseMap<Attribute, size_t> &nameToIndex);
5628 struct DeferredModuleToParse {
5629 FModuleLike moduleOp;
5630 SmallVector<SMLoc> portLocs;
5635 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5636 DeferredModuleToParse &deferredModule,
5637 InnerSymFixups &fixups);
5639 SmallVector<DeferredModuleToParse, 0> deferredModules;
5641 SmallVector<InnerSymFixups, 0> moduleFixups;
5645 ModuleOp mlirModule;
5650FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5651 SmallVectorImpl<Attribute> &attrs) {
5653 auto annotations = json::parse(annotationsStr);
5654 if (
auto err = annotations.takeError()) {
5655 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5656 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5657 diag.attachNote() << a.message();
5662 json::Path::Root root;
5663 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5666 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5667 std::string jsonErrorMessage =
5668 "See inline comments for problem area in JSON:\n";
5669 llvm::raw_string_ostream
s(jsonErrorMessage);
5670 root.printErrorContext(annotations.get(), s);
5671 diag.attachNote() << jsonErrorMessage;
5678ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5680 SmallVector<StringRef> strings;
5683 if (parseId(name,
"expected layer name"))
5685 strings.push_back(name);
5686 }
while (consumeIf(FIRToken::period));
5688 SmallVector<FlatSymbolRefAttr> nested;
5689 nested.reserve(strings.size() - 1);
5690 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5691 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5693 result = SymbolRefAttr::get(
context, strings[0], nested);
5697ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5698 SmallVector<Attribute> enabledLayersBuffer;
5700 auto tokenKind = getToken().getKind();
5702 if (tokenKind == FIRToken::kw_enablelayer) {
5703 if (parseEnableLayerSpec(enabledLayersBuffer))
5711 if (enabledLayersBuffer.size() != 0)
5712 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5715 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5719ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5720 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5721 ArrayAttr &externalRequirements) {
5722 SmallVector<Attribute> enabledLayersBuffer;
5723 SmallVector<Attribute> knownLayersBuffer;
5724 SmallVector<Attribute> requirementsBuffer;
5726 auto tokenKind = getToken().getKind();
5728 if (tokenKind == FIRToken::kw_enablelayer) {
5729 if (parseEnableLayerSpec(enabledLayersBuffer))
5734 if (tokenKind == FIRToken::kw_knownlayer) {
5735 if (parseKnownLayerSpec(knownLayersBuffer))
5740 if (tokenKind == FIRToken::kw_requires) {
5741 if (parseRequiresSpec(requirementsBuffer))
5749 if (enabledLayersBuffer.size() != 0)
5750 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5753 if (knownLayersBuffer.size() != 0)
5754 if (requireFeature({6, 0, 0},
"extmodules with known layers"))
5757 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5758 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5759 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5764FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5766 SymbolRefAttr layer;
5767 if (parseLayerName(layer))
5769 result.push_back(layer);
5770 }
while (consumeIf(FIRToken::comma));
5775FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5776 consumeToken(FIRToken::kw_enablelayer);
5777 return parseLayerList(result);
5781FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5782 consumeToken(FIRToken::kw_knownlayer);
5783 return parseLayerList(result);
5787FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5788 consumeToken(FIRToken::kw_requires);
5790 StringRef requireStr;
5791 if (parseGetSpelling(requireStr) ||
5792 parseToken(FIRToken::string,
"expected string after 'requires'"))
5796 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5797 }
while (consumeIf(FIRToken::comma));
5805FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5806 SmallVectorImpl<SMLoc> &resultPortLocs,
5812 DenseMap<Attribute, size_t> nameToIndex;
5813 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5816 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5818 getIndentation() > indent) {
5824 auto backtrackState = getLexer().getCursor();
5826 bool isOutput = getToken().is(FIRToken::kw_output);
5831 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5832 !getToken().isKeyword()) {
5833 backtrackState.restore(getLexer());
5840 if (parseId(name,
"expected port name") ||
5841 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5842 parseType(type,
"expected a type in port declaration"))
5844 Attribute domainInfoElement = {};
5845 size_t portIdx = resultPorts.size();
5846 if (
auto domainType = dyn_cast<DomainType>(type)) {
5849 domainInfoElement = ArrayAttr::get(getContext(), {});
5851 if (getToken().is(FIRToken::kw_domains))
5852 if (parseDomains(domainNames[portIdx], nameToIndex))
5856 if (
info.parseOptionalInfo())
5859 StringAttr innerSym = {};
5860 resultPorts.push_back(
PortInfo{name,
5866 domainInfoElement});
5867 resultPortLocs.push_back(
info.getFIRLoc());
5868 nameToIndex.insert({name, portIdx});
5872 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5873 auto &port = resultPorts[portIdx];
5874 Attribute &attr = port.domains;
5878 SmallVector<Attribute> domainInfo;
5879 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5881 attr = ArrayAttr::get(getContext(), domainInfo);
5886 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5887 PortInfo &port = std::get<0>(portAndLoc);
5888 auto &entry = portIds[port.
name];
5889 if (!entry.isValid()) {
5890 entry = std::get<1>(portAndLoc);
5894 emitError(std::get<1>(portAndLoc),
5895 "redefinition of name '" + port.
getName() +
"'")
5896 .attachNote(translateLocation(entry))
5897 <<
"previous definition here";
5906ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5908 switch (getToken().getKind()) {
5912 case FIRToken::error:
5916 case FIRToken::kw_class:
5917 case FIRToken::kw_domain:
5918 case FIRToken::kw_declgroup:
5919 case FIRToken::kw_extclass:
5920 case FIRToken::kw_extmodule:
5921 case FIRToken::kw_intmodule:
5922 case FIRToken::kw_formal:
5923 case FIRToken::kw_module:
5924 case FIRToken::kw_public:
5925 case FIRToken::kw_layer:
5926 case FIRToken::kw_option:
5927 case FIRToken::kw_simulation:
5928 case FIRToken::kw_type:
5932 if (getIndentation() == indent)
5944ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5945 SmallVector<Attribute, 8> parameters;
5946 SmallPtrSet<StringAttr, 8> seen;
5947 while (consumeIf(FIRToken::kw_parameter)) {
5951 if (parseParameter(name, value, loc))
5953 auto typedValue = dyn_cast<TypedAttr>(value);
5955 return emitError(loc)
5956 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5957 if (!seen.insert(name).second)
5958 return emitError(loc,
5959 "redefinition of parameter '" + name.getValue() +
"'");
5960 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5962 resultParameters = ArrayAttr::get(getContext(), parameters);
5967ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5969 SmallVector<PortInfo, 8> portList;
5970 SmallVector<SMLoc> portLocs;
5973 if (requireFeature({6, 0, 0},
"classes"))
5976 consumeToken(FIRToken::kw_class);
5977 if (parseId(name,
"expected class name") ||
5978 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5982 if (name == circuit.getName())
5983 return mlir::emitError(
info.getLoc(),
5984 "class cannot be the top of a circuit");
5986 for (
auto &portInfo : portList)
5988 return
mlir::emitError(portInfo.loc,
5989 "ports on classes must be properties");
5992 auto builder = circuit.getBodyBuilder();
5993 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5994 classOp.setPrivate();
5995 deferredModules.emplace_back(
5996 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5999 getConstants().classMap[name.getValue()] = classOp;
6000 return skipToModuleEnd(indent);
6004ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
6005 consumeToken(FIRToken::kw_domain);
6009 if (parseId(name,
"domain name") ||
6010 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
6011 info.parseOptionalInfo())
6014 SmallVector<Attribute> fields;
6016 auto nextIndent = getIndentation();
6017 if (!nextIndent || *nextIndent <= indent)
6020 StringAttr fieldName;
6022 if (parseId(fieldName,
"field name") ||
6023 parseToken(FIRToken::colon,
"expected ':' after field name") ||
6024 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
6028 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
6031 auto builder = circuit.getBodyBuilder();
6032 auto domainOp = DomainOp::create(builder,
info.getLoc(), name,
6033 builder.getArrayAttr(fields));
6037 getConstants().domainMap[name.getValue()] = domainOp;
6043ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
6046 SmallVector<PortInfo, 8> portList;
6047 SmallVector<SMLoc> portLocs;
6050 if (requireFeature({6, 0, 0},
"classes"))
6053 consumeToken(FIRToken::kw_extclass);
6054 if (parseId(name,
"expected extclass name") ||
6055 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
6059 if (name == circuit.getName())
6060 return mlir::emitError(
info.getLoc(),
6061 "extclass cannot be the top of a circuit");
6063 for (
auto &portInfo : portList)
6065 return
mlir::emitError(portInfo.loc,
6066 "ports on extclasses must be properties");
6069 auto builder = circuit.getBodyBuilder();
6070 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
6073 getConstants().classMap[name.getValue()] = extClassOp;
6074 return skipToModuleEnd(indent);
6082ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
6085 ArrayAttr enabledLayers;
6086 ArrayAttr knownLayers;
6087 ArrayAttr externalRequirements;
6088 SmallVector<PortInfo, 8> portList;
6089 SmallVector<SMLoc> portLocs;
6091 consumeToken(FIRToken::kw_extmodule);
6092 if (parseId(name,
"expected extmodule name") ||
6093 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
6094 externalRequirements) ||
6095 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
6100 if (consumeIf(FIRToken::kw_defname)) {
6101 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
6102 parseId(defName,
"expected defname name"))
6106 ArrayAttr parameters;
6111 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6112 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6113 if (ftype.hasUninferredWidth())
6114 return emitError(loc,
"extmodule port must have known width");
6119 auto builder = circuit.getBodyBuilder();
6120 auto isMainModule = (name == circuit.getName());
6122 (isMainModule && getConstants().options.scalarizePublicModules) ||
6123 getConstants().options.scalarizeExtModules
6124 ? Convention::Scalarized
6125 : Convention::Internal;
6126 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6127 auto annotations = ArrayAttr::get(getContext(), {});
6128 auto extModuleOp = FExtModuleOp::create(
6129 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
6130 defName, annotations, parameters, enabledLayers, externalRequirements);
6131 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6132 : SymbolTable::Visibility::Private;
6133 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6141ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6145 ArrayAttr enabledLayers;
6146 SmallVector<PortInfo, 8> portList;
6147 SmallVector<SMLoc> portLocs;
6149 consumeToken(FIRToken::kw_intmodule);
6150 if (parseId(name,
"expected intmodule name") ||
6151 parseModuleLayerSpec(enabledLayers) ||
6152 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
6154 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
6155 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
6156 parseId(intName,
"expected intrinsic name"))
6159 ArrayAttr parameters;
6163 ArrayAttr annotations = getConstants().emptyArrayAttr;
6164 auto builder = circuit.getBodyBuilder();
6165 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
6166 annotations, parameters, enabledLayers)
6172ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
6175 SmallVector<PortInfo, 8> portList;
6176 SmallVector<SMLoc> portLocs;
6177 ArrayAttr enabledLayers;
6178 auto modLoc = getToken().getLoc();
6179 LocWithInfo
info(modLoc,
this);
6180 consumeToken(FIRToken::kw_module);
6181 if (parseId(name,
"expected module name") ||
6182 parseModuleLayerSpec(enabledLayers) ||
6183 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
6188 if (name == circuit.getName()) {
6189 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
6194 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
6195 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6196 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6197 if (ftype.hasUninferredWidth())
6198 return emitError(loc,
"public module port must have known width");
6199 if (ftype.hasUninferredReset())
6200 return emitError(loc,
6201 "public module port must have concrete reset type");
6206 ArrayAttr annotations = getConstants().emptyArrayAttr;
6207 auto convention = Convention::Internal;
6208 if (isPublic && getConstants().options.scalarizePublicModules)
6209 convention = Convention::Scalarized;
6210 if (!isPublic && getConstants().options.scalarizeInternalModules)
6211 convention = Convention::Scalarized;
6212 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6213 auto builder = circuit.getBodyBuilder();
6215 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6216 annotations, enabledLayers);
6218 auto visibility = isPublic ? SymbolTable::Visibility::Public
6219 : SymbolTable::Visibility::Private;
6220 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6224 deferredModules.emplace_back(DeferredModuleToParse{
6225 moduleOp, portLocs, getLexer().getCursor(), indent});
6227 if (skipToModuleEnd(indent))
6233ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6234 consumeToken(FIRToken::kw_formal);
6235 return parseFormalLike<FormalOp>(circuit, indent);
6239ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6241 consumeToken(FIRToken::kw_simulation);
6242 return parseFormalLike<SimulationOp>(circuit, indent);
6249ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6251 StringRef id, moduleName;
6254 auto builder = circuit.getBodyBuilder();
6257 if (parseId(
id,
"expected test name") ||
6258 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6259 parseId(moduleName,
"expected module name"))
6263 NamedAttrList params;
6264 if (consumeIf(FIRToken::comma)) {
6266 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6267 return emitError(
"expected 'bound' after ','");
6269 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6270 parseIntLit(bound,
"expected integer bound after '='"))
6273 return emitError(
"bound must be a positive integer");
6274 if (
info.parseOptionalInfo())
6276 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6279 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6280 info.parseOptionalInfo())
6282 while (getIndentation() > indent) {
6283 StringAttr paramName;
6284 Attribute paramValue;
6286 if (parseParameter(paramName, paramValue, paramLoc,
6289 if (params.set(paramName, paramValue))
6290 return emitError(paramLoc,
"redefinition of parameter '" +
6291 paramName.getValue() +
"'");
6295 Op::create(builder,
info.getLoc(),
id, moduleName,
6296 params.getDictionary(getContext()));
6300ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6302 switch (getToken().getKind()) {
6303 case FIRToken::kw_class:
6304 return parseClass(circuit, indent);
6305 case FIRToken::kw_declgroup:
6306 if (requireFeature({3, 2, 0},
"optional groups") ||
6307 removedFeature({3, 3, 0},
"optional groups"))
6309 return parseLayer(circuit);
6310 case FIRToken::kw_domain:
6313 return parseDomain(circuit, indent);
6314 case FIRToken::kw_extclass:
6315 return parseExtClass(circuit, indent);
6316 case FIRToken::kw_extmodule:
6317 return parseExtModule(circuit, indent);
6318 case FIRToken::kw_formal:
6319 if (requireFeature({4, 0, 0},
"formal tests"))
6321 return parseFormal(circuit, indent);
6322 case FIRToken::kw_intmodule:
6323 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6324 removedFeature({4, 0, 0},
"intrinsic modules"))
6326 return parseIntModule(circuit, indent);
6327 case FIRToken::kw_layer:
6328 if (requireFeature({3, 3, 0},
"layers"))
6330 return parseLayer(circuit);
6331 case FIRToken::kw_module:
6332 return parseModule(circuit,
false, indent);
6333 case FIRToken::kw_public:
6334 if (requireFeature({3, 3, 0},
"public modules"))
6337 if (getToken().getKind() == FIRToken::kw_module)
6338 return parseModule(circuit,
true, indent);
6339 return emitError(getToken().
getLoc(),
"only modules may be public");
6340 case FIRToken::kw_simulation:
6343 return parseSimulation(circuit, indent);
6344 case FIRToken::kw_type:
6345 return parseTypeDecl();
6346 case FIRToken::kw_option:
6349 return parseOptionDecl(circuit);
6351 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6356ParseResult FIRCircuitParser::parseTypeDecl() {
6360 auto loc = getToken().getLoc();
6362 if (getToken().isKeyword())
6363 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6364 <<
"' for type alias name";
6366 if (parseId(
id,
"expected type name") ||
6367 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6370 auto name = StringAttr::get(type.getContext(),
id);
6373 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6374 type = BaseTypeAliasType::get(name, base);
6377 <<
"type alias for non-base type " << type
6378 <<
" is currently not supported. Type alias is stripped immediately";
6380 if (!getConstants().aliasMap.insert({id, type}).second)
6381 return emitError(loc) <<
"type alias `" << name.getValue()
6382 <<
"` is already defined";
6387ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6390 auto loc = getToken().getLoc();
6393 if (parseId(
id,
"expected an option group name") ||
6394 parseToken(FIRToken::colon,
6395 "expected ':' after option group definition") ||
6396 info.parseOptionalInfo())
6399 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6400 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6401 auto *block =
new Block;
6402 optionOp.getBody().push_back(block);
6403 builder.setInsertionPointToEnd(block);
6405 auto baseIndent = getIndentation();
6407 while (getIndentation() == baseIndent) {
6409 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6410 if (parseId(
id,
"expected an option case ID") ||
6411 caseInfo.parseOptionalInfo())
6414 if (!cases.insert(
id).second)
6415 return emitError(loc)
6416 <<
"duplicate option case definition '" <<
id <<
"'";
6418 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6425ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6426 auto baseIndent = getIndentation();
6429 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6432 auto parseOne = [&](
Block *block) -> ParseResult {
6433 auto indent = getIndentation();
6434 StringRef id, convention;
6437 if (parseId(
id,
"expected layer name") ||
6438 parseToken(FIRToken::comma,
"expected ','") ||
6439 parseGetSpelling(convention))
6442 auto layerConvention = symbolizeLayerConvention(convention);
6443 if (!layerConvention) {
6444 emitError() <<
"unknown convention '" << convention
6445 <<
"' (did you misspell it?)";
6448 if (layerConvention == LayerConvention::Inline &&
6449 requireFeature({4, 1, 0},
"inline layers"))
6453 hw::OutputFileAttr outputDir;
6454 if (consumeIf(FIRToken::comma)) {
6455 if (getToken().getKind() == FIRToken::string) {
6456 auto text = getToken().getStringValue();
6458 return emitError() <<
"output directory must not be blank";
6459 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6460 consumeToken(FIRToken::string);
6464 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6465 info.parseOptionalInfo())
6467 auto builder = OpBuilder::atBlockEnd(block);
6470 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6471 layerOp->getRegion(0).push_back(
new Block());
6473 layerOp->setAttr(
"output_file", outputDir);
6474 layerStack.push_back({indent, layerOp});
6478 if (parseOne(circuit.getBodyBlock()))
6482 while (getIndentation() > baseIndent) {
6483 switch (getToken().getKind()) {
6484 case FIRToken::kw_declgroup:
6485 case FIRToken::kw_layer: {
6488 while (layerStack.back().first >= getIndentation())
6489 layerStack.pop_back();
6490 auto parentLayer = layerStack.back().second;
6491 if (parseOne(&parentLayer.getBody().front()))
6496 return emitError(
"expected 'layer'"), failure();
6503ParseResult FIRCircuitParser::resolveDomains(
6504 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6505 const DenseMap<Attribute, size_t> &nameToIndex,
6506 SmallVectorImpl<Attribute> &domainsByIndex) {
6508 for (
auto [attr, loc] : domainsByName) {
6509 auto domain = cast<StringAttr>(attr);
6510 auto indexItr = nameToIndex.find(domain);
6511 if (indexItr == nameToIndex.end()) {
6512 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6515 domainsByIndex.push_back(IntegerAttr::get(
6516 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6523ParseResult FIRCircuitParser::parseDomains(
6524 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6525 const DenseMap<Attribute, size_t> &nameToIndex) {
6528 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6529 parseToken(FIRToken::l_square,
"expected '['"))
6532 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6534 auto domainLoc = getToken().getLoc();
6535 if (parseId(domain,
"expected domain name"))
6537 domains.push_back({domain, domainLoc});
6547FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6548 DeferredModuleToParse &deferredModule,
6549 InnerSymFixups &fixups) {
6550 FModuleLike moduleOp = deferredModule.moduleOp;
6551 auto &body = moduleOp->getRegion(0).front();
6552 auto &portLocs = deferredModule.portLocs;
6556 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6559 deferredModule.lexerCursor.restore(moduleBodyLexer);
6561 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6566 auto portList = moduleOp.getPorts();
6567 auto portArgs = body.getArguments();
6568 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6569 PortInfo &port = std::get<0>(tuple);
6570 llvm::SMLoc loc = std::get<1>(tuple);
6571 BlockArgument portArg = std::get<2>(tuple);
6573 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6577 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6580 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6593ParseResult FIRCircuitParser::parseCircuit(
6594 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6595 mlir::TimingScope &ts) {
6597 auto indent = getIndentation();
6598 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6600 if (!indent.has_value())
6601 return emitError(
"'FIRRTL' must be first token on its line");
6602 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6603 parseVersionLit(
"expected version literal"))
6605 indent = getIndentation();
6607 if (!indent.has_value())
6608 return emitError(
"'circuit' must be first token on its line");
6609 unsigned circuitIndent = *indent;
6613 SMLoc inlineAnnotationsLoc;
6614 StringRef inlineAnnotations;
6617 if (parseToken(FIRToken::kw_circuit,
6618 "expected a top-level 'circuit' definition") ||
6619 parseId(name,
"expected circuit name") ||
6620 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6621 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6622 info.parseOptionalInfo())
6626 OpBuilder b(mlirModule.getBodyRegion());
6627 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6630 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6636 SmallVector<Attribute> annos;
6637 if (!inlineAnnotations.empty())
6638 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6642 for (
auto *annotationsBuf : annotationsBufs)
6643 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6647 parseAnnotationTimer.stop();
6655 auto parseTimer = ts.nest(
"Parse modules");
6656 deferredModules.reserve(16);
6660 switch (getToken().getKind()) {
6668 case FIRToken::error:
6672 emitError(
"unexpected token in circuit");
6675 case FIRToken::kw_class:
6676 case FIRToken::kw_declgroup:
6677 case FIRToken::kw_domain:
6678 case FIRToken::kw_extclass:
6679 case FIRToken::kw_extmodule:
6680 case FIRToken::kw_intmodule:
6681 case FIRToken::kw_layer:
6682 case FIRToken::kw_formal:
6683 case FIRToken::kw_module:
6684 case FIRToken::kw_option:
6685 case FIRToken::kw_public:
6686 case FIRToken::kw_simulation:
6687 case FIRToken::kw_type: {
6688 auto indent = getIndentation();
6689 if (!indent.has_value())
6690 return emitError(
"'module' must be first token on its line"), failure();
6691 unsigned definitionIndent = *indent;
6693 if (definitionIndent <= circuitIndent)
6694 return emitError(
"module should be indented more"), failure();
6696 if (parseToplevelDefinition(circuit, definitionIndent))
6710 (void)getLexer().translateLocation(
info.getFIRLoc());
6716 DenseMap<Attribute, Location> nameToOrigLoc;
6720 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6725 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6728 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6729 .attachNote(it.first->second)
6730 .append(
"see existing symbol definition here");
6736 SymbolTable circuitSymTbl(circuit);
6738 moduleFixups.resize(deferredModules.size());
6743 for (
auto &d : deferredModules)
6744 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6747 auto anyFailed = mlir::failableParallelForEachN(
6748 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6749 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6750 moduleFixups[index]))
6754 if (failed(anyFailed))
6759 for (
auto &fixups : moduleFixups) {
6760 if (failed(fixups.resolve(innerSymbolNamespaces)))
6766 auto parseLayerName = [&](StringRef name) -> Attribute {
6768 auto [head, rest] = name.split(
".");
6769 SmallVector<FlatSymbolRefAttr> nestedRefs;
6770 while (!rest.empty()) {
6772 std::tie(next, rest) = rest.split(
".");
6773 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6775 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6778 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6779 SmallVector<Attribute> attrArray;
6781 for (
const auto &str : strArray)
6782 attrArray.push_back(getAttr(str));
6783 if (attrArray.empty())
6785 return ArrayAttr::get(
context, attrArray);
6788 if (
auto enableLayers =
6789 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6790 circuit.setEnableLayersAttr(enableLayers);
6791 if (
auto disableLayers =
6792 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6793 circuit.setDisableLayersAttr(disableLayers);
6795 auto getStrAttr = [&](StringRef str) -> Attribute {
6796 return StringAttr::get(getContext(), str);
6799 if (
auto selectInstChoice =
6800 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6801 circuit.setSelectInstChoiceAttr(selectInstChoice);
6803 circuit.setDefaultLayerSpecialization(
6804 getConstants().options.defaultLayerSpecialization);
6817 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6818 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6819 unsigned fileID = 1;
6821 annotationsBufs.push_back(
6822 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6824 context->loadDialect<CHIRRTLDialect>();
6825 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6829 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6832 SharedParserConstants state(
context, options);
6835 .parseCircuit(annotationsBufs, ts))
6840 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6841 if (failed(verify(*module)))
6848 static mlir::TranslateToMLIRRegistration fromFIR(
6849 "import-firrtl",
"import .fir",
6850 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6851 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
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.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
constexpr FIRVersion nextFIRVersion(7, 0, 0)
The next version of FIRRTL that is not yet released.
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
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.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs, bool warnOnTruncation=false)
Emit a connect between two values.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
The FIRRTL specification version.
static std::optional< FIRVersion > fromString(StringRef str)
Parse a version string of the form "major.minor.patch".
This holds the name and type that describes the module's ports.
StringRef getName() const