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: {
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: {
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:
1221 consumeToken(FIRToken::kw_Bool);
1222 result = BoolType::get(getContext());
1224 case FIRToken::kw_Double:
1227 consumeToken(FIRToken::kw_Double);
1228 result = DoubleType::get(getContext());
1230 case FIRToken::kw_Path:
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");
1791 void endStatement(FIRParser &parser) {
1792 assert(isActive &&
"Not parsing a statement");
1796 for (
auto opAndSMLoc : subOps) {
1800 switch (parser.getConstants().options.infoLocatorHandling) {
1801 case ILH::IgnoreInfo:
1803 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1805 case ILH::PreferInfo:
1806 opAndSMLoc.first->setLoc(infoLoc);
1808 case ILH::FusedInfo:
1809 opAndSMLoc.first->setLoc(FusedLoc::get(
1810 infoLoc.getContext(),
1811 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1818 for (
auto opAndSMLoc : subOps)
1819 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1824 infoLoc = LocationAttr();
1825 currentSMLoc = SMLoc();
1830 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1833 void setInfoLoc(LocationAttr loc) {
1834 assert(!infoLoc &&
"Info location multiply specified");
1840 void notifyOperationInserted(Operation *op,
1841 mlir::IRRewriter::InsertPoint)
override {
1842 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1843 assert(isActive &&
"Not parsing a statement");
1844 subOps.push_back({op, currentSMLoc});
1849 bool isActive =
false;
1857 LocationAttr infoLoc;
1864 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1866 void operator=(
const LazyLocationListener &) =
delete;
1867 LazyLocationListener(
const LazyLocationListener &) =
delete;
1875struct InnerSymFixups {
1878 fixups.push_back({user, target});
1887 hw::InnerRefUserOpInterface innerRefUser;
1890 SmallVector<Fixup, 0> fixups;
1896 for (
auto &f : fixups) {
1899 return isnc.get(module);
1901 assert(ref &&
"unable to resolve inner symbol target");
1905 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1906 .Case<RWProbeOp>([ref](RWProbeOp op) {
1907 op.setTargetAttr(ref);
1910 .Default([](
auto *op) {
1911 return op->emitError(
"unknown inner-ref user requiring fixup");
1922struct FIRStmtParser :
public FIRParser {
1923 explicit FIRStmtParser(Block &blockToInsertInto,
1924 FIRModuleContext &moduleContext,
1925 InnerSymFixups &innerSymFixups,
1926 const SymbolTable &circuitSymTbl,
FIRVersion version,
1927 SymbolRefAttr layerSym = {})
1928 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1930 builder(UnknownLoc::
get(getContext()), getContext()),
1931 locationProcessor(this->builder), moduleContext(moduleContext),
1932 innerSymFixups(innerSymFixups), layerSym(layerSym),
1933 circuitSymTbl(circuitSymTbl) {
1934 builder.setInsertionPointToEnd(&blockToInsertInto);
1937 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1938 ParseResult parseSimpleStmtBlock(
unsigned indent);
1941 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1944 void emitInvalidate(Value val,
Flow flow);
1950 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1953 ParseResult parseOptionalInfo() {
1955 if (failed(parseOptionalInfoLocator(loc)))
1957 locationProcessor.setInfoLoc(loc);
1962 ParseResult parseExpImpl(Value &result,
const Twine &message,
1963 bool isLeadingStmt);
1964 ParseResult parseExp(Value &result,
const Twine &message) {
1965 return parseExpImpl(result, message,
false);
1967 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1968 return parseExpImpl(result, message,
true);
1970 ParseResult parseEnumExp(Value &result);
1971 ParseResult parsePathExp(Value &result);
1972 ParseResult parseDomainExp(Value &result);
1973 ParseResult parseRefExp(Value &result,
const Twine &message);
1974 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1975 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1976 const Twine &message);
1979 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1980 ParseResult parseIntrinsicStmt() {
1982 return parseIntrinsic(unused,
true);
1984 ParseResult parseIntrinsicExp(Value &result) {
1985 return parseIntrinsic(result,
false);
1987 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1989 template <
typename subop>
1990 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1991 ParseResult parseOptionalExpPostscript(Value &result,
1992 bool allowDynamic =
true);
1993 ParseResult parsePostFixFieldId(Value &result);
1994 ParseResult parsePostFixIntSubscript(Value &result);
1995 ParseResult parsePostFixDynamicSubscript(Value &result);
1997 parseIntegerLiteralExp(Value &result,
bool isSigned,
1998 std::optional<int32_t> allocatedWidth = {});
1999 ParseResult parseListExp(Value &result);
2000 ParseResult parseListConcatExp(Value &result);
2001 ParseResult parseCatExp(Value &result);
2002 ParseResult parseStringConcatExp(Value &result);
2003 ParseResult parsePropEqExp(Value &result);
2004 ParseResult parseUnsafeDomainCast(Value &result);
2005 ParseResult parseUnknownProperty(Value &result);
2007 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
2008 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2010 auto loc = getToken().getLoc();
2011 locationProcessor.setLoc(loc);
2014 auto vals = std::array<Value, M>();
2015 auto ints = std::array<int64_t, N>();
2019 for (
size_t i = 0; i < M; ++i) {
2021 if (parseToken(FIRToken::comma,
"expected ','"))
2023 if (parseExp(vals[i],
"expected expression in primitive operand"))
2029 for (
size_t i = 0; i < N; ++i) {
2031 if (parseToken(FIRToken::comma,
"expected ','"))
2033 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2038 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2042 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2046 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2047 translateLocation(loc));
2052 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2053 result = op.getResult();
2057 template <
typename T,
unsigned M,
unsigned N>
2058 ParseResult parsePrimExp(Value &result) {
2059 auto ms = std::make_index_sequence<M>();
2060 auto ns = std::make_index_sequence<N>();
2061 return parsePrim<T, M, N>(ms, ns, result);
2064 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2067 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2068 SymbolRefAttr layerSym);
2069 ParseResult parseAttach();
2070 ParseResult parseMemPort(MemDirAttr direction);
2076 ArrayRef<Value> specOperands,
2077 StringAttr &formatStringResult,
2078 SmallVectorImpl<Value> &operands);
2079 ParseResult parsePrintf();
2080 ParseResult parseFPrintf();
2081 ParseResult parseFFlush();
2082 ParseResult parseSkip();
2083 ParseResult parseStop();
2084 ParseResult parseAssert();
2085 ParseResult parseAssume();
2086 ParseResult parseCover();
2087 ParseResult parseWhen(
unsigned whenIndent);
2088 ParseResult parseMatch(
unsigned matchIndent);
2089 ParseResult parseDomainInstantiation();
2090 ParseResult parseDomainDefine();
2091 ParseResult parseRefDefine();
2092 ParseResult parseRefForce();
2093 ParseResult parseRefForceInitial();
2094 ParseResult parseRefRelease();
2095 ParseResult parseRefReleaseInitial();
2096 ParseResult parseRefRead(Value &result);
2097 ParseResult parseProbe(Value &result);
2098 ParseResult parsePropAssert();
2099 ParseResult parsePropAssign();
2100 ParseResult parseRWProbe(Value &result);
2101 ParseResult parseLeadingExpStmt(Value lhs);
2102 ParseResult parseConnect();
2103 ParseResult parseInvalidate();
2104 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2107 ParseResult parseInstance();
2108 ParseResult parseInstanceChoice();
2109 ParseResult parseObject();
2110 ParseResult parseCombMem();
2111 ParseResult parseSeqMem();
2112 ParseResult parseMem(
unsigned memIndent);
2113 ParseResult parseNode();
2114 ParseResult parseWire();
2115 ParseResult parseRegister(
unsigned regIndent);
2116 ParseResult parseRegisterWithReset();
2117 ParseResult parseContract(
unsigned blockIndent);
2120 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2123 ImplicitLocOpBuilder builder;
2124 LazyLocationListener locationProcessor;
2127 FIRModuleContext &moduleContext;
2130 InnerSymFixups &innerSymFixups;
2134 SymbolRefAttr layerSym;
2136 const SymbolTable &circuitSymTbl;
2143void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2144 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2151 auto props = tpe.getRecursiveTypeProperties();
2152 if (props.isPassive && !props.containsAnalog) {
2153 if (flow == Flow::Source)
2155 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2166 TypeSwitch<FIRRTLType>(tpe)
2167 .Case<BundleType>([&](
auto tpe) {
2168 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2169 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2171 OpBuilder::InsertionGuard guard(builder);
2172 builder.setInsertionPointAfterValue(val);
2173 subfield = SubfieldOp::create(builder, val, i);
2175 emitInvalidate(subfield,
2176 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2179 .Case<FVectorType>([&](
auto tpe) {
2180 auto tpex = tpe.getElementType();
2181 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2182 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2184 OpBuilder::InsertionGuard guard(builder);
2185 builder.setInsertionPointAfterValue(val);
2186 subindex = SubindexOp::create(builder, tpex, val, i);
2188 emitInvalidate(subindex, flow);
2216ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2217 bool isLeadingStmt) {
2218 auto token = getToken();
2219 auto kind = token.getKind();
2221 case FIRToken::lp_integer_add:
2222 case FIRToken::lp_integer_mul:
2223 case FIRToken::lp_integer_shr:
2224 case FIRToken::lp_integer_shl:
2225 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2234#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2236 case FIRToken::lp_##SPELLING: \
2237 if (requireFeature(VERSION, FEATURE)) \
2239 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2242#include "FIRTokenKinds.def"
2244 case FIRToken::l_brace_bar:
2246 return emitError(
"unexpected enumeration as start of statement");
2247 if (parseEnumExp(result))
2250 case FIRToken::lp_read:
2252 return emitError(
"unexpected read() as start of statement");
2253 if (parseRefRead(result))
2256 case FIRToken::lp_probe:
2258 return emitError(
"unexpected probe() as start of statement");
2259 if (parseProbe(result))
2262 case FIRToken::lp_rwprobe:
2264 return emitError(
"unexpected rwprobe() as start of statement");
2265 if (parseRWProbe(result))
2269 case FIRToken::langle_UInt:
2270 case FIRToken::langle_SInt: {
2273 bool isSigned = getToken().is(FIRToken::langle_SInt);
2276 if (parseWidth(width))
2280 if (parseIntegerLiteralExp(result, isSigned, width))
2285 case FIRToken::lp_UInt:
2286 if (parseIntegerLiteralExp(result,
false))
2289 case FIRToken::lp_SInt:
2290 if (parseIntegerLiteralExp(result,
true))
2293 case FIRToken::lp_String: {
2294 if (requireFeature({3, 1, 0},
"Strings"))
2296 locationProcessor.setLoc(getToken().
getLoc());
2297 consumeToken(FIRToken::lp_String);
2299 if (parseGetSpelling(spelling) ||
2300 parseToken(FIRToken::string,
2301 "expected string literal in String expression") ||
2302 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2305 result = moduleContext.getCachedConstant<StringConstantOp>(
2306 builder, attr, builder.getType<StringType>(), attr);
2309 case FIRToken::lp_Integer: {
2310 if (requireFeature({3, 1, 0},
"Integers"))
2312 locationProcessor.setLoc(getToken().
getLoc());
2313 consumeToken(FIRToken::lp_Integer);
2315 if (parseIntLit(value,
"expected integer literal in Integer expression") ||
2316 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2318 APSInt apint(value,
false);
2319 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2320 builder, IntegerAttr::get(getContext(), apint),
2321 builder.getType<FIntegerType>(), apint);
2324 case FIRToken::lp_Bool: {
2327 locationProcessor.setLoc(getToken().
getLoc());
2328 consumeToken(FIRToken::lp_Bool);
2330 if (consumeIf(FIRToken::kw_true))
2332 else if (consumeIf(FIRToken::kw_false))
2335 return emitError(
"expected true or false in Bool expression");
2336 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2338 auto attr = builder.getBoolAttr(value);
2339 result = moduleContext.getCachedConstant<BoolConstantOp>(
2340 builder, attr, builder.getType<BoolType>(), value);
2343 case FIRToken::lp_Double: {
2346 locationProcessor.setLoc(getToken().
getLoc());
2347 consumeToken(FIRToken::lp_Double);
2348 auto spelling = getTokenSpelling();
2349 if (parseToken(FIRToken::floatingpoint,
2350 "expected floating point in Double expression") ||
2351 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2356 if (!llvm::to_float(spelling, d))
2357 return emitError(
"invalid double");
2358 auto attr = builder.getF64FloatAttr(d);
2359 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2360 builder, attr, builder.getType<DoubleType>(), attr);
2363 case FIRToken::lp_List:
2364 case FIRToken::langle_List: {
2365 if (requireFeature({4, 0, 0},
"Lists"))
2368 return emitError(
"unexpected List<>() as start of statement");
2369 if (parseListExp(result))
2374 case FIRToken::lp_list_concat: {
2376 return emitError(
"unexpected list_create() as start of statement");
2377 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2382 case FIRToken::lp_path:
2384 return emitError(
"unexpected path() as start of statement");
2389 case FIRToken::lp_intrinsic:
2390 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2391 parseIntrinsicExp(result))
2395 case FIRToken::lp_cat:
2396 if (parseCatExp(result))
2400 case FIRToken::lp_string_concat:
2401 if (parseStringConcatExp(result))
2405 case FIRToken::lp_prop_eq:
2407 parsePropEqExp(result))
2411 case FIRToken::lp_unsafe_domain_cast:
2413 parseUnsafeDomainCast(result))
2416 case FIRToken::lp_Unknown:
2417 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2418 parseUnknownProperty(result))
2424 case FIRToken::identifier:
2425 case FIRToken::literal_identifier:
2426 case FIRToken::kw_UInt:
2427 case FIRToken::kw_SInt:
2428 case FIRToken::kw_String:
2429 case FIRToken::kw_Integer:
2430 case FIRToken::kw_Bool:
2431 case FIRToken::kw_Double:
2432 case FIRToken::kw_List:
2435 auto loc = getToken().getLoc();
2437 if (parseId(name, message) ||
2438 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2442 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2445 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2450 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2451 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2452 parseOptionalInfo())
2455 locationProcessor.setLoc(loc);
2457 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2459 moduleContext.getUnbundledEntry(unbundledId);
2460 for (
auto elt : ubEntry)
2461 emitInvalidate(elt.second);
2469 StringRef fieldName;
2470 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2471 parseFieldId(fieldName,
"expected field name") ||
2472 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2480 case FIRToken::lp_shr:
2483 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2484 result = PadPrimOp::create(builder, result, 1);
2490 return parseOptionalExpPostscript(result);
2500ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2501 bool allowDynamic) {
2506 if (consumeIf(FIRToken::period)) {
2507 if (parsePostFixFieldId(result))
2514 if (consumeIf(FIRToken::l_square)) {
2515 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2516 if (parsePostFixIntSubscript(result))
2521 return emitError(
"subaccess not allowed here");
2522 if (parsePostFixDynamicSubscript(result))
2532template <
typename subop>
2534FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2536 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2542 auto baseType = cast<FIRRTLType>(base.getType());
2543 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2546 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2552 locationProcessor.setLoc(loc);
2553 OpBuilder::InsertionGuard guard(builder);
2554 builder.setInsertionPointAfterValue(base);
2555 auto op = subop::create(builder, resultType, base, indexNo);
2558 return value = op.getResult();
2565ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2566 auto loc = getToken().getLoc();
2567 SmallVector<StringRef, 3> fields;
2568 if (parseFieldIdSeq(fields,
"expected field name"))
2570 for (
auto fieldName : fields) {
2571 std::optional<unsigned> indexV;
2572 auto type = result.getType();
2573 if (
auto refTy = type_dyn_cast<RefType>(type))
2574 type = refTy.getType();
2575 if (
auto bundle = type_dyn_cast<BundleType>(type))
2576 indexV = bundle.getElementIndex(fieldName);
2577 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2578 indexV = bundle.getElementIndex(fieldName);
2579 else if (
auto klass = type_dyn_cast<ClassType>(type))
2580 indexV = klass.getElementIndex(fieldName);
2581 else if (
auto domain = type_dyn_cast<DomainType>(type))
2582 indexV = domain.getFieldIndex(fieldName);
2584 return emitError(loc,
2585 "subfield requires bundle, object, or domain operand ");
2587 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2588 << result.getType();
2589 auto indexNo = *indexV;
2591 FailureOr<Value> subResult;
2592 if (type_isa<RefType>(result.getType()))
2593 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2594 else if (type_isa<ClassType>(type))
2595 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2596 else if (type_isa<DomainType>(type))
2597 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2598 else if (type_isa<BundleType>(type))
2599 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2601 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2603 if (failed(subResult))
2605 result = *subResult;
2614ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2615 auto loc = getToken().getLoc();
2617 if (parseIntLit(indexNo,
"expected index") ||
2618 parseToken(FIRToken::r_square,
"expected ']'"))
2622 return emitError(loc,
"invalid index specifier"), failure();
2624 FailureOr<Value> subResult;
2625 if (type_isa<RefType>(result.getType()))
2626 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2627 else if (type_isa<FVectorType>(result.getType()))
2628 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2630 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2632 if (failed(subResult))
2634 result = *subResult;
2642ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2643 auto loc = getToken().getLoc();
2645 if (parseExp(index,
"expected subscript index expression") ||
2646 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2650 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2652 return emitError(
"expected base type for index expression");
2653 indexType = indexType.getPassiveType();
2654 locationProcessor.setLoc(loc);
2659 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2662 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2663 translateLocation(loc));
2668 auto op = SubaccessOp::create(builder, resultType, result, index);
2669 result = op.getResult();
2680FIRStmtParser::parseIntegerLiteralExp(Value &result,
bool isSigned,
2681 std::optional<int32_t> allocatedWidth) {
2682 auto loc = getToken().getLoc();
2685 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2690 int32_t width = allocatedWidth.value_or(-1);
2696 parseToken(FIRToken::l_paren,
"expected '(' in integer expression"))
2699 if (parseIntLit(value,
"expected integer value") ||
2700 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2705 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2707 IntegerType::SignednessSemantics signedness =
2708 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2710 if (!value.isZero())
2711 return emitError(loc,
"zero bit constant must be zero");
2712 value = value.trunc(0);
2713 }
else if (width != -1) {
2715 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2717 return emitError(loc,
"initializer too wide for declared width");
2718 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2722 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2723 auto attr = builder.getIntegerAttr(attrType, value);
2725 locationProcessor.setLoc(loc);
2726 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2731ParseResult FIRStmtParser::parseListExp(Value &result) {
2732 auto loc = getToken().getLoc();
2733 bool hasLAngle = getToken().is(FIRToken::langle_List);
2734 bool hasLParen = getToken().is(FIRToken::lp_List);
2739 if (!hasLAngle && parseToken(FIRToken::less,
"expected '<' in List type"))
2742 if (parsePropertyType(
elementType,
"expected List element type") ||
2743 parseToken(FIRToken::greater,
"expected '>' in List type"))
2746 auto listType = ListType::get(getContext(),
elementType);
2750 parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2753 SmallVector<Value, 3> operands;
2754 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2756 locationProcessor.setLoc(loc);
2757 if (parseExp(operand,
"expected expression in List expression"))
2761 if (!isa<AnyRefType>(elementType) ||
2762 !isa<ClassType>(operand.getType()))
2763 return emitError(loc,
"unexpected expression of type ")
2764 << operand.getType() <<
" in List expression of type "
2766 operand = ObjectAnyRefCastOp::create(builder, operand);
2769 operands.push_back(operand);
2774 locationProcessor.setLoc(loc);
2775 result = ListCreateOp::create(builder, listType, operands);
2780ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2781 consumeToken(FIRToken::lp_list_concat);
2783 auto loc = getToken().getLoc();
2785 SmallVector<Value, 3> operands;
2786 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2788 locationProcessor.setLoc(loc);
2789 if (parseExp(operand,
"expected expression in List concat expression"))
2792 if (!type_isa<ListType>(operand.getType()))
2793 return emitError(loc,
"unexpected expression of type ")
2794 << operand.getType() <<
" in List concat expression";
2797 type = type_cast<ListType>(operand.getType());
2799 if (operand.getType() != type)
2800 return emitError(loc,
"unexpected expression of type ")
2801 << operand.getType() <<
" in List concat expression of type "
2804 operands.push_back(operand);
2809 if (operands.empty())
2810 return emitError(loc,
"need at least one List to concatenate");
2812 locationProcessor.setLoc(loc);
2813 result = ListConcatOp::create(builder, type, operands);
2818ParseResult FIRStmtParser::parseCatExp(Value &result) {
2819 consumeToken(FIRToken::lp_cat);
2821 auto loc = getToken().getLoc();
2822 SmallVector<Value, 3> operands;
2823 std::optional<bool> isSigned;
2824 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2826 locationProcessor.setLoc(loc);
2827 auto operandLoc = getToken().getLoc();
2828 if (parseExp(operand,
"expected expression in cat expression"))
2830 if (!type_isa<IntType>(operand.getType())) {
2831 auto diag = emitError(loc,
"all operands must be Int type");
2832 diag.attachNote(translateLocation(operandLoc))
2833 <<
"non-integer operand is here";
2837 isSigned = type_isa<SIntType>(operand.getType());
2838 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2839 auto diag = emitError(loc,
"all operands must have same signedness");
2840 diag.attachNote(translateLocation(operandLoc))
2841 <<
"operand with different signedness is here";
2845 operands.push_back(operand);
2850 if (operands.size() != 2) {
2855 locationProcessor.setLoc(loc);
2856 result = CatPrimOp::create(builder, operands);
2861ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2862 consumeToken(FIRToken::lp_string_concat);
2864 auto loc = getToken().getLoc();
2865 SmallVector<Value, 3> operands;
2866 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2868 locationProcessor.setLoc(loc);
2869 if (parseExp(operand,
2870 "expected expression in string_concat expression"))
2872 if (!type_isa<StringType>(operand.getType()))
2873 return emitError(loc,
"all operands must be String type");
2874 operands.push_back(operand);
2879 if (operands.empty())
2880 return emitError(loc,
"need at least one String to concatenate");
2882 locationProcessor.setLoc(loc);
2883 auto type = StringType::get(builder.getContext());
2884 result = builder.create<StringConcatOp>(type, operands);
2889ParseResult FIRStmtParser::parsePropEqExp(Value &result) {
2890 consumeToken(FIRToken::lp_prop_eq);
2892 auto loc = getToken().getLoc();
2894 locationProcessor.setLoc(loc);
2895 if (parseExp(lhs,
"expected lhs expression in prop_eq expression") ||
2896 parseToken(FIRToken::comma,
"expected ','") ||
2897 parseExp(rhs,
"expected rhs expression in prop_eq expression") ||
2898 parseToken(FIRToken::r_paren,
"expected ')'"))
2901 auto isValidType = [](Type t) {
2902 return type_isa<StringType>(t) || type_isa<BoolType>(t) ||
2903 type_isa<FIntegerType>(t);
2905 if (!isValidType(lhs.getType()))
2906 return emitError(loc,
2907 "lhs of prop_eq must be String, Bool, or Integer type");
2908 if (!isValidType(rhs.getType()))
2909 return emitError(loc,
2910 "rhs of prop_eq must be String, Bool, or Integer type");
2911 if (lhs.getType() != rhs.getType())
2912 return emitError(loc,
"prop_eq operands must have the same type");
2914 locationProcessor.setLoc(loc);
2915 result = PropEqOp::create(builder, lhs, rhs);
2919ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2920 consumeToken(FIRToken::lp_unsafe_domain_cast);
2922 auto loc = getToken().getLoc();
2924 if (parseExp(input,
"expected input"))
2927 SmallVector<Value> domains;
2928 if (consumeIf(FIRToken::comma)) {
2929 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2931 if (parseExp(domain,
"expected domain"))
2933 domains.push_back(domain);
2937 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2941 locationProcessor.setLoc(loc);
2942 result = UnsafeDomainCastOp::create(builder, input, domains);
2946ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2947 auto loc = getToken().getLoc();
2948 consumeToken(FIRToken::lp_Unknown);
2952 if (parsePropertyType(type,
"expected property type") ||
2953 parseToken(FIRToken::r_paren,
"expected ')' in unknown property"))
2956 locationProcessor.setLoc(loc);
2957 result = UnknownValueOp::create(builder, type);
2978std::optional<ParseResult>
2979FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2980 switch (getToken().getKind()) {
2983 return std::nullopt;
2985 case FIRToken::period:
2986 case FIRToken::l_square:
2987 case FIRToken::kw_is:
2988 case FIRToken::less_equal:
2994 auto loc = keyword.
getLoc();
2996 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2997 return ParseResult(failure());
3003 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
3006 if (!consumeIf(FIRToken::period))
3007 return ParseResult(failure());
3009 StringRef fieldName;
3010 if (parseFieldId(fieldName,
"expected field name") ||
3011 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
3012 return ParseResult(failure());
3016 if (parseOptionalExpPostscript(lhs))
3017 return ParseResult(failure());
3019 return parseLeadingExpStmt(lhs);
3025ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
3028 if (getToken().isAny(FIRToken::eof, FIRToken::error))
3031 auto subIndent = getIndentation();
3032 if (!subIndent.has_value())
3033 return emitError(
"expected statement to be on its own line"), failure();
3035 if (*subIndent <= indent)
3039 if (parseSimpleStmt(*subIndent))
3044ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
3045 locationProcessor.startStatement();
3046 auto result = parseSimpleStmtImpl(stmtIndent);
3047 locationProcessor.endStatement(*
this);
3070ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
3071 auto kind = getToken().getKind();
3074 case FIRToken::kw_invalidate:
3075 case FIRToken::kw_connect:
3076 case FIRToken::kw_regreset:
3080 kind = FIRToken::identifier;
3087 case FIRToken::kw_attach:
3088 return parseAttach();
3089 case FIRToken::kw_infer:
3090 return parseMemPort(MemDirAttr::Infer);
3091 case FIRToken::kw_read:
3092 return parseMemPort(MemDirAttr::Read);
3093 case FIRToken::kw_write:
3094 return parseMemPort(MemDirAttr::Write);
3095 case FIRToken::kw_rdwr:
3096 return parseMemPort(MemDirAttr::ReadWrite);
3097 case FIRToken::kw_connect:
3098 return parseConnect();
3099 case FIRToken::kw_propassert:
3102 return parsePropAssert();
3103 case FIRToken::kw_propassign:
3104 if (requireFeature({3, 1, 0},
"properties"))
3106 return parsePropAssign();
3107 case FIRToken::kw_invalidate:
3108 return parseInvalidate();
3109 case FIRToken::lp_printf:
3110 return parsePrintf();
3111 case FIRToken::lp_fprintf:
3112 return parseFPrintf();
3113 case FIRToken::lp_fflush:
3114 return parseFFlush();
3115 case FIRToken::kw_skip:
3117 case FIRToken::lp_stop:
3119 case FIRToken::lp_assert:
3120 return parseAssert();
3121 case FIRToken::lp_assume:
3122 return parseAssume();
3123 case FIRToken::lp_cover:
3124 return parseCover();
3125 case FIRToken::kw_when:
3126 return parseWhen(stmtIndent);
3127 case FIRToken::kw_match:
3128 return parseMatch(stmtIndent);
3129 case FIRToken::kw_domain:
3131 return parseDomainInstantiation();
3132 case FIRToken::kw_domain_define:
3133 return parseDomainDefine();
3134 case FIRToken::kw_define:
3135 return parseRefDefine();
3136 case FIRToken::lp_force:
3137 return parseRefForce();
3138 case FIRToken::lp_force_initial:
3139 return parseRefForceInitial();
3140 case FIRToken::lp_release:
3141 return parseRefRelease();
3142 case FIRToken::lp_release_initial:
3143 return parseRefReleaseInitial();
3144 case FIRToken::kw_group:
3145 if (requireFeature({3, 2, 0},
"optional groups") ||
3146 removedFeature({3, 3, 0},
"optional groups"))
3148 return parseLayerBlockOrGroup(stmtIndent);
3149 case FIRToken::kw_layerblock:
3150 if (requireFeature({3, 3, 0},
"layers"))
3152 return parseLayerBlockOrGroup(stmtIndent);
3153 case FIRToken::lp_intrinsic:
3154 if (requireFeature({4, 0, 0},
"generic intrinsics"))
3156 return parseIntrinsicStmt();
3160 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
3167 return parseLeadingExpStmt(lhs);
3171 case FIRToken::kw_inst:
3172 return parseInstance();
3173 case FIRToken::kw_instchoice:
3174 return parseInstanceChoice();
3175 case FIRToken::kw_object:
3176 return parseObject();
3177 case FIRToken::kw_cmem:
3178 return parseCombMem();
3179 case FIRToken::kw_smem:
3180 return parseSeqMem();
3181 case FIRToken::kw_mem:
3182 return parseMem(stmtIndent);
3183 case FIRToken::kw_node:
3185 case FIRToken::kw_wire:
3187 case FIRToken::kw_reg:
3188 return parseRegister(stmtIndent);
3189 case FIRToken::kw_regreset:
3190 return parseRegisterWithReset();
3191 case FIRToken::kw_contract:
3192 return parseContract(stmtIndent);
3196ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3198 SymbolRefAttr layerSym) {
3200 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3201 moduleContext, &blockToInsertInto);
3206 UnbundledValueRestorer x(moduleContext.unbundledValues);
3210 auto subParser = std::make_unique<FIRStmtParser>(
3211 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3215 auto stmtIndent = getIndentation();
3218 if (!stmtIndent.has_value())
3219 return subParser->parseSimpleStmt(indent);
3221 if (*stmtIndent <= indent)
3222 return emitError(
"statement must be indented more than previous statement"),
3226 return subParser->parseSimpleStmtBlock(indent);
3230ParseResult FIRStmtParser::parseAttach() {
3231 auto startTok = consumeToken(FIRToken::kw_attach);
3234 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3237 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3240 SmallVector<Value, 4> operands;
3241 operands.push_back({});
3242 if (parseExp(operands.back(),
"expected operand in attach"))
3245 while (consumeIf(FIRToken::comma)) {
3246 operands.push_back({});
3247 if (parseExp(operands.back(),
"expected operand in attach"))
3250 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3253 if (parseOptionalInfo())
3256 locationProcessor.setLoc(startTok.getLoc());
3257 AttachOp::create(builder, operands);
3264ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3265 auto startTok = consumeToken();
3266 auto startLoc = startTok.getLoc();
3270 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3276 Value memory, indexExp, clock;
3277 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3278 parseId(
id,
"expected result name") ||
3279 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3280 parseId(memName,
"expected memory name") ||
3281 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3282 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3283 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3284 parseExp(indexExp,
"expected index expression") ||
3285 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3286 parseToken(FIRToken::comma,
"expected ','") ||
3287 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3290 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3292 return emitError(startLoc,
3293 "memory port should have behavioral memory type");
3294 auto resultType = memVType.getElementType();
3296 ArrayAttr annotations = getConstants().emptyArrayAttr;
3297 locationProcessor.setLoc(startLoc);
3300 Value memoryPort, memoryData;
3302 OpBuilder::InsertionGuard guard(builder);
3303 builder.setInsertionPointAfterValue(memory);
3304 auto memoryPortOp = MemoryPortOp::create(
3305 builder, resultType, CMemoryPortType::get(getContext()), memory,
3306 direction,
id, annotations);
3307 memoryData = memoryPortOp.getResult(0);
3308 memoryPort = memoryPortOp.getResult(1);
3312 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3314 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3320ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3321 StringRef formatString,
3322 ArrayRef<Value> specOperands,
3323 StringAttr &formatStringResult,
3324 SmallVectorImpl<Value> &operands) {
3327 operands.append(specOperands.begin(), specOperands.end());
3328 formatStringResult =
3334 auto loc = translateLocation(formatStringLoc);
3337 formatStringResult, operands);
3342ParseResult FIRStmtParser::parsePrintf() {
3343 auto startTok = consumeToken(FIRToken::lp_printf);
3345 Value clock, condition;
3346 StringRef formatString;
3347 if (parseExp(clock,
"expected clock expression in printf") ||
3348 parseToken(FIRToken::comma,
"expected ','") ||
3349 parseExp(condition,
"expected condition in printf") ||
3350 parseToken(FIRToken::comma,
"expected ','"))
3353 auto formatStringLoc = getToken().getLoc();
3354 if (parseGetSpelling(formatString) ||
3355 parseToken(FIRToken::string,
"expected format string in printf"))
3358 SmallVector<Value, 4> specOperands;
3359 while (consumeIf(FIRToken::comma)) {
3360 specOperands.push_back({});
3361 if (parseExp(specOperands.back(),
"expected operand in printf"))
3366 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3367 parseOptionalName(name) || parseOptionalInfo())
3370 locationProcessor.setLoc(startTok.getLoc());
3372 StringAttr formatStrUnescaped;
3373 SmallVector<Value> operands;
3375 formatStrUnescaped, operands))
3378 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3384ParseResult FIRStmtParser::parseFPrintf() {
3387 auto startTok = consumeToken(FIRToken::lp_fprintf);
3389 Value clock, condition;
3390 StringRef outputFile, formatString;
3391 if (parseExp(clock,
"expected clock expression in fprintf") ||
3392 parseToken(FIRToken::comma,
"expected ','") ||
3393 parseExp(condition,
"expected condition in fprintf") ||
3394 parseToken(FIRToken::comma,
"expected ','"))
3397 auto outputFileLoc = getToken().getLoc();
3398 if (parseGetSpelling(outputFile) ||
3399 parseToken(FIRToken::string,
"expected output file in fprintf"))
3402 SmallVector<Value, 4> outputFileSpecOperands;
3403 while (consumeIf(FIRToken::comma)) {
3405 if (getToken().getKind() == FIRToken::string)
3407 outputFileSpecOperands.push_back({});
3408 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3412 auto formatStringLoc = getToken().getLoc();
3413 if (parseGetSpelling(formatString) ||
3414 parseToken(FIRToken::string,
"expected format string in printf"))
3417 SmallVector<Value, 4> specOperands;
3418 while (consumeIf(FIRToken::comma)) {
3419 specOperands.push_back({});
3420 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3425 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3426 parseOptionalName(name) || parseOptionalInfo())
3429 locationProcessor.setLoc(startTok.getLoc());
3431 StringAttr outputFileNameStrUnescaped;
3432 SmallVector<Value> outputFileOperands;
3434 outputFileNameStrUnescaped, outputFileOperands))
3437 StringAttr formatStrUnescaped;
3438 SmallVector<Value> operands;
3440 formatStrUnescaped, operands))
3443 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3444 outputFileOperands, formatStrUnescaped, operands, name);
3449ParseResult FIRStmtParser::parseFFlush() {
3453 auto startTok = consumeToken(FIRToken::lp_fflush);
3455 Value clock, condition;
3456 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3457 parseToken(FIRToken::comma,
"expected ','") ||
3458 parseExp(condition,
"expected condition in 'fflush'"))
3461 locationProcessor.setLoc(startTok.getLoc());
3462 StringAttr outputFileNameStrUnescaped;
3463 SmallVector<Value> outputFileOperands;
3465 if (consumeIf(FIRToken::comma)) {
3466 SmallVector<Value, 4> outputFileSpecOperands;
3467 auto outputFileLoc = getToken().getLoc();
3468 StringRef outputFile;
3469 if (parseGetSpelling(outputFile) ||
3470 parseToken(FIRToken::string,
"expected output file in fflush"))
3473 while (consumeIf(FIRToken::comma)) {
3474 outputFileSpecOperands.push_back({});
3475 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3480 outputFileNameStrUnescaped, outputFileOperands))
3484 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3485 parseOptionalInfo())
3488 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3489 outputFileOperands);
3494ParseResult FIRStmtParser::parseSkip() {
3495 auto startTok = consumeToken(FIRToken::kw_skip);
3499 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3502 if (parseOptionalInfo())
3505 locationProcessor.setLoc(startTok.getLoc());
3506 SkipOp::create(builder);
3511ParseResult FIRStmtParser::parseStop() {
3512 auto startTok = consumeToken(FIRToken::lp_stop);
3514 Value clock, condition;
3517 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3518 parseToken(FIRToken::comma,
"expected ','") ||
3519 parseExp(condition,
"expected condition in 'stop'") ||
3520 parseToken(FIRToken::comma,
"expected ','") ||
3521 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3522 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3523 parseOptionalName(name) || parseOptionalInfo())
3526 locationProcessor.setLoc(startTok.getLoc());
3527 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3533ParseResult FIRStmtParser::parseAssert() {
3534 auto startTok = consumeToken(FIRToken::lp_assert);
3536 Value clock, predicate, enable;
3537 StringRef formatString;
3539 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3540 parseToken(FIRToken::comma,
"expected ','") ||
3541 parseExp(predicate,
"expected predicate in 'assert'") ||
3542 parseToken(FIRToken::comma,
"expected ','") ||
3543 parseExp(enable,
"expected enable in 'assert'") ||
3544 parseToken(FIRToken::comma,
"expected ','") ||
3545 parseGetSpelling(formatString) ||
3546 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3549 SmallVector<Value, 4> operands;
3550 while (!consumeIf(FIRToken::r_paren)) {
3551 operands.push_back({});
3552 if (parseToken(FIRToken::comma,
"expected ','") ||
3553 parseExp(operands.back(),
"expected operand in 'assert'"))
3557 if (parseOptionalName(name) || parseOptionalInfo())
3560 locationProcessor.setLoc(startTok.getLoc());
3562 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3563 operands, name.getValue());
3568ParseResult FIRStmtParser::parseAssume() {
3569 auto startTok = consumeToken(FIRToken::lp_assume);
3571 Value clock, predicate, enable;
3572 StringRef formatString;
3574 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3575 parseToken(FIRToken::comma,
"expected ','") ||
3576 parseExp(predicate,
"expected predicate in 'assume'") ||
3577 parseToken(FIRToken::comma,
"expected ','") ||
3578 parseExp(enable,
"expected enable in 'assume'") ||
3579 parseToken(FIRToken::comma,
"expected ','") ||
3580 parseGetSpelling(formatString) ||
3581 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3584 SmallVector<Value, 4> operands;
3585 while (!consumeIf(FIRToken::r_paren)) {
3586 operands.push_back({});
3587 if (parseToken(FIRToken::comma,
"expected ','") ||
3588 parseExp(operands.back(),
"expected operand in 'assume'"))
3592 if (parseOptionalName(name) || parseOptionalInfo())
3595 locationProcessor.setLoc(startTok.getLoc());
3597 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3598 operands, name.getValue());
3603ParseResult FIRStmtParser::parseCover() {
3604 auto startTok = consumeToken(FIRToken::lp_cover);
3606 Value clock, predicate, enable;
3609 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3610 parseToken(FIRToken::comma,
"expected ','") ||
3611 parseExp(predicate,
"expected predicate in 'cover'") ||
3612 parseToken(FIRToken::comma,
"expected ','") ||
3613 parseExp(enable,
"expected enable in 'cover'") ||
3614 parseToken(FIRToken::comma,
"expected ','") ||
3615 parseGetSpelling(message) ||
3616 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3617 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3618 parseOptionalName(name) || parseOptionalInfo())
3621 locationProcessor.setLoc(startTok.getLoc());
3623 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3624 ValueRange{}, name.getValue());
3630ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3631 auto startTok = consumeToken(FIRToken::kw_when);
3635 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3639 if (parseExp(condition,
"expected condition in 'when'") ||
3640 parseToken(FIRToken::colon,
"expected ':' in when") ||
3641 parseOptionalInfo())
3644 locationProcessor.setLoc(startTok.getLoc());
3646 auto whenStmt = WhenOp::create(builder, condition,
false);
3649 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3653 if (getToken().isNot(FIRToken::kw_else))
3658 auto elseIndent = getIndentation();
3659 if (elseIndent && *elseIndent < whenIndent)
3662 consumeToken(FIRToken::kw_else);
3665 whenStmt.createElseRegion();
3671 if (getToken().is(FIRToken::kw_when)) {
3673 auto subParser = std::make_unique<FIRStmtParser>(
3674 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3677 return subParser->parseSimpleStmt(whenIndent);
3681 LocationAttr elseLoc;
3682 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3683 parseOptionalInfoLocator(elseLoc) ||
3684 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3693ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3694 auto startLoc = getToken().getLoc();
3695 locationProcessor.setLoc(startLoc);
3697 if (parseEnumType(type))
3701 auto enumType = type_dyn_cast<FEnumType>(type);
3703 return emitError(startLoc,
3704 "expected enumeration type in enumeration expression");
3707 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3708 parseId(tag,
"expected enumeration tag"))
3712 if (consumeIf(FIRToken::r_paren)) {
3715 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3716 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3717 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3718 input = ConstantOp::create(builder, type, attr);
3721 if (parseToken(FIRToken::comma,
"expected ','") ||
3722 parseExp(input,
"expected expression in enumeration value") ||
3723 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3727 value = FEnumCreateOp::create(builder, enumType, tag, input);
3735ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3736 auto startTok = consumeToken(FIRToken::kw_match);
3738 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3742 if (parseExp(input,
"expected expression in 'match'") ||
3743 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3744 parseOptionalInfo())
3747 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3749 return mlir::emitError(
3751 "expected enumeration type for 'match' statement, but got ")
3754 locationProcessor.setLoc(startTok.getLoc());
3756 SmallVector<Attribute> tags;
3757 SmallVector<std::unique_ptr<Region>> regions;
3759 auto tagLoc = getToken().getLoc();
3762 auto caseIndent = getIndentation();
3763 if (!caseIndent || *caseIndent <= matchIndent)
3767 StringRef tagSpelling;
3768 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3770 auto tagIndex = enumType.getElementIndex(tagSpelling);
3772 return emitError(tagLoc,
"tag ")
3773 << tagSpelling <<
" not a member of enumeration " << enumType;
3774 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3775 tags.push_back(tag);
3778 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3781 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3786 UnbundledValueRestorer x(moduleContext.unbundledValues);
3789 if (consumeIf(FIRToken::l_paren)) {
3790 StringAttr identifier;
3791 if (parseId(identifier,
"expected identifier for 'case' binding"))
3795 auto dataType = enumType.getElementType(*tagIndex);
3796 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3798 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3802 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3806 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3807 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3810 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3814 auto subParser = std::make_unique<FIRStmtParser>(
3815 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3817 if (subParser->parseSimpleStmtBlock(*caseIndent))
3821 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3828ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3829 auto loc = getToken().getLoc();
3832 if (parseId(
id,
"expected domain expression") ||
3833 moduleContext.lookupSymbolEntry(entry,
id, loc))
3836 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3838 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3839 parseFieldId(field,
"expected field name") ||
3840 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3844 if (parseOptionalExpPostscript(result,
false))
3847 auto type = result.getType();
3848 if (!type_isa<DomainType>(type))
3849 return emitError(loc) <<
"expected domain-type expression, got " << type;
3856ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3857 auto token = getToken().getKind();
3858 if (token == FIRToken::lp_probe)
3859 return parseProbe(result);
3860 if (token == FIRToken::lp_rwprobe)
3861 return parseRWProbe(result);
3866 return parseStaticRefExp(result, message);
3873ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3874 const Twine &message) {
3875 auto parseIdOrInstance = [&]() -> ParseResult {
3877 auto loc = getToken().getLoc();
3879 if (parseId(
id, message) ||
3880 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3884 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3887 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3890 StringRef fieldName;
3892 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3893 parseFieldId(fieldName,
"expected field name") ||
3894 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3896 return failure(parseIdOrInstance() ||
3897 parseOptionalExpPostscript(result,
false));
3908ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3910 const Twine &message) {
3911 auto loc = getToken().getLoc();
3915 if (parseId(
id, message) ||
3916 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3928 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3930 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3932 StringRef fieldName;
3933 auto loc = getToken().getLoc();
3934 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3935 parseFieldId(fieldName,
"expected field name"))
3940 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3941 for (
auto &elt : ubEntry) {
3942 if (elt.first == fieldAttr) {
3945 auto &instResult = elt.second;
3948 auto *defining = instResult.getDefiningOp();
3950 if (isa<WireOp>(defining)) {
3951 result = instResult;
3956 auto type = instResult.getType();
3960 auto annotations = getConstants().emptyArrayAttr;
3961 StringAttr sym = {};
3962 SmallString<64> name;
3963 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3964 locationProcessor.setLoc(loc);
3965 OpBuilder::InsertionGuard guard(builder);
3966 builder.setInsertionPoint(defining);
3968 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3970 auto bounceVal = bounce.getDataRaw();
3973 instResult.replaceAllUsesWith(bounceVal);
3976 builder.setInsertionPointAfter(defining);
3977 if (
foldFlow(instResult) == Flow::Source)
3984 result = instResult = bounce.getDataRaw();
3990 emitError(loc,
"use of invalid field name '")
3991 << fieldName <<
"' on bundle value";
3996 result = cast<Value>(symtabEntry);
4000 assert(isa<BlockArgument>(result) ||
4001 result.getDefiningOp<hw::InnerSymbolOpInterface>());
4007 type = result.getType();
4009 if (consumeIf(FIRToken::period)) {
4010 SmallVector<StringRef, 3> fields;
4011 if (parseFieldIdSeq(fields,
"expected field name"))
4013 for (
auto fieldName : fields) {
4014 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4015 if (
auto index = bundle.getElementIndex(fieldName)) {
4016 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4017 type = bundle.getElementTypePreservingConst(*index);
4020 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
4021 if (
auto index = bundle.getElementIndex(fieldName)) {
4022 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4023 type = bundle.getElementTypePreservingConst(*index);
4027 return emitError(loc,
"subfield requires bundle operand")
4028 <<
"got " << type <<
"\n";
4030 return emitError(loc,
4031 "unknown field '" + fieldName +
"' in bundle type ")
4036 if (consumeIf(FIRToken::l_square)) {
4037 auto loc = getToken().
getLoc();
4039 if (parseIntLit(index,
"expected index") ||
4040 parseToken(FIRToken::r_square,
"expected ']'"))
4044 return emitError(loc,
"invalid index specifier");
4046 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
4047 if ((
unsigned)index < vector.getNumElements()) {
4048 refResult = refResult.
getSubField(vector.getFieldID(index));
4049 type = vector.getElementTypePreservingConst();
4052 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
4053 if ((
unsigned)index < vector.getNumElements()) {
4054 refResult = refResult.
getSubField(vector.getFieldID(index));
4055 type = vector.getElementTypePreservingConst();
4059 return emitError(loc,
"subindex requires vector operand");
4061 return emitError(loc,
"out of range index '")
4062 << index <<
"' for vector type " << type;
4070ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4071 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4072 StringRef intrinsic;
4073 ArrayAttr parameters;
4076 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4077 parseOptionalParams(parameters))
4080 if (consumeIf(FIRToken::colon)) {
4081 if (
parseType(type,
"expected intrinsic return type"))
4083 }
else if (!isStatement)
4084 return emitError(
"expected ':' in intrinsic expression");
4086 SmallVector<Value> operands;
4087 auto loc = startTok.getLoc();
4088 if (consumeIf(FIRToken::comma)) {
4089 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4091 if (parseExp(operand,
"expected operand in intrinsic"))
4093 operands.push_back(operand);
4094 locationProcessor.setLoc(loc);
4099 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4104 if (parseOptionalInfo())
4107 locationProcessor.setLoc(loc);
4109 auto op = GenericIntrinsicOp::create(
4110 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4112 result = op.getResult();
4117ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4118 if (!consumeIf(FIRToken::less))
4121 SmallVector<Attribute, 8> parameters;
4122 SmallPtrSet<StringAttr, 8> seen;
4123 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4127 if (parseParameter(name, value, loc))
4129 auto typedValue = dyn_cast<TypedAttr>(value);
4131 return emitError(loc)
4132 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4133 if (!seen.insert(name).second)
4134 return emitError(loc,
"redefinition of parameter '" +
4135 name.getValue() +
"'");
4136 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4141 resultParameters = ArrayAttr::get(getContext(), parameters);
4147ParseResult FIRStmtParser::parsePathExp(Value &result) {
4148 auto startTok = consumeToken(FIRToken::lp_path);
4149 locationProcessor.setLoc(startTok.getLoc());
4151 if (parseGetSpelling(target) ||
4152 parseToken(FIRToken::string,
4153 "expected target string in path expression") ||
4154 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4156 result = UnresolvedPathOp::create(
4162ParseResult FIRStmtParser::parseDomainInstantiation() {
4163 auto startTok = consumeToken(FIRToken::kw_domain);
4164 auto startLoc = startTok.getLoc();
4167 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4170 locationProcessor.setLoc(startTok.getLoc());
4172 StringAttr instanceName;
4173 StringAttr domainKind;
4176 parseId(instanceName,
"expected domain instance name") ||
4177 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4178 parseId(domainKind,
"expected domain type name"))
4183 const auto &domainMap = getConstants().domainMap;
4184 auto lookup = domainMap.find(domainKind.getValue());
4185 if (lookup == domainMap.end())
4186 return emitError(startTok.getLoc())
4187 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4189 auto domainType = DomainType::getFromDomainOp(lookup->second);
4192 SmallVector<Value> fieldValues;
4193 if (consumeIf(FIRToken::l_paren)) {
4195 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4197 if (parseExp(value,
"expected field value expression"))
4199 fieldValues.push_back(value);
4205 if (parseOptionalInfo())
4208 locationProcessor.setLoc(startLoc);
4210 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4213 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4218ParseResult FIRStmtParser::parseDomainDefine() {
4219 auto startTok = consumeToken(FIRToken::kw_domain_define);
4220 auto startLoc = startTok.getLoc();
4221 locationProcessor.setLoc(startLoc);
4225 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4226 parseDomainExp(src) || parseOptionalInfo())
4234ParseResult FIRStmtParser::parseRefDefine() {
4235 auto startTok = consumeToken(FIRToken::kw_define);
4238 if (parseStaticRefExp(target,
4239 "expected static reference expression in 'define'") ||
4240 parseToken(FIRToken::equal,
4241 "expected '=' after define reference expression") ||
4242 parseRefExp(src,
"expected reference expression in 'define'") ||
4243 parseOptionalInfo())
4247 if (!type_isa<RefType>(target.getType()))
4248 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4249 "'define' target (LHS), got ")
4250 << target.getType();
4251 if (!type_isa<RefType>(src.getType()))
4252 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4253 "'define' source (RHS), got ")
4258 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4259 return emitError(startTok.getLoc(),
4260 "cannot define into a sub-element of a reference");
4262 locationProcessor.setLoc(startTok.getLoc());
4265 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4266 << target.getType() <<
" with incompatible reference of type "
4276ParseResult FIRStmtParser::parseRefRead(Value &result) {
4277 auto startTok = consumeToken(FIRToken::lp_read);
4280 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4281 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4284 locationProcessor.setLoc(startTok.getLoc());
4287 if (!type_isa<RefType>(ref.getType()))
4288 return emitError(startTok.getLoc(),
4289 "expected reference-type expression in 'read', got ")
4292 result = RefResolveOp::create(builder, ref);
4298ParseResult FIRStmtParser::parseProbe(Value &result) {
4299 auto startTok = consumeToken(FIRToken::lp_probe);
4302 if (parseStaticRefExp(staticRef,
4303 "expected static reference expression in 'probe'") ||
4304 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4307 locationProcessor.setLoc(startTok.getLoc());
4310 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4311 return emitError(startTok.getLoc(),
4312 "expected base-type expression in 'probe', got ")
4313 << staticRef.getType();
4317 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4318 MemoryDebugPortOp, MemoryPortAccessOp>(
4319 staticRef.getDefiningOp()))
4320 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4322 result = RefSendOp::create(builder, staticRef);
4328ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4329 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4332 Type parsedTargetType;
4333 if (parseRWProbeStaticRefExp(
4334 staticRef, parsedTargetType,
4335 "expected static reference expression in 'rwprobe'") ||
4336 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4339 locationProcessor.setLoc(startTok.getLoc());
4345 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4347 return emitError(startTok.getLoc(),
4348 "expected base-type expression in 'rwprobe', got ")
4349 << parsedTargetType;
4352 auto *definingOp = root.getDefiningOp();
4354 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4355 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4356 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4360 return emitError(startTok.getLoc(),
"cannot force target of type ")
4364 auto op = RWProbeOp::create(builder, forceableType,
4365 getConstants().placeholderInnerRef);
4372ParseResult FIRStmtParser::parseRefForce() {
4373 auto startTok = consumeToken(FIRToken::lp_force);
4375 Value clock, pred, dest, src;
4376 if (parseExp(clock,
"expected clock expression in force") ||
4377 parseToken(FIRToken::comma,
"expected ','") ||
4378 parseExp(pred,
"expected predicate expression in force") ||
4379 parseToken(FIRToken::comma,
"expected ','") ||
4380 parseRefExp(dest,
"expected destination reference expression in force") ||
4381 parseToken(FIRToken::comma,
"expected ','") ||
4382 parseExp(src,
"expected source expression in force") ||
4383 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4384 parseOptionalInfo())
4388 auto ref = type_dyn_cast<RefType>(dest.getType());
4389 if (!ref || !ref.getForceable())
4392 "expected rwprobe-type expression for force destination, got ")
4394 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4396 return emitError(startTok.getLoc(),
4397 "expected base-type for force source, got ")
4399 if (!srcBaseType.isPassive())
4400 return emitError(startTok.getLoc(),
4401 "expected passive value for force source, got ")
4404 locationProcessor.setLoc(startTok.getLoc());
4407 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4408 if (noConstSrcType != ref.getType()) {
4410 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4412 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4414 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4415 << src.getType() <<
" cannot target destination "
4419 RefForceOp::create(builder, clock, pred, dest, src);
4425ParseResult FIRStmtParser::parseRefForceInitial() {
4426 auto startTok = consumeToken(FIRToken::lp_force_initial);
4430 dest,
"expected destination reference expression in force_initial") ||
4431 parseToken(FIRToken::comma,
"expected ','") ||
4432 parseExp(src,
"expected source expression in force_initial") ||
4433 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4434 parseOptionalInfo())
4438 auto ref = type_dyn_cast<RefType>(dest.getType());
4439 if (!ref || !ref.getForceable())
4440 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4441 "force_initial destination, got ")
4443 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4445 return emitError(startTok.getLoc(),
4446 "expected base-type expression for force_initial "
4449 if (!srcBaseType.isPassive())
4450 return emitError(startTok.getLoc(),
4451 "expected passive value for force_initial source, got ")
4454 locationProcessor.setLoc(startTok.getLoc());
4457 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4458 if (noConstSrcType != ref.getType()) {
4460 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4462 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4464 return emitError(startTok.getLoc(),
4465 "incompatible force_initial source of type ")
4466 << src.getType() <<
" cannot target destination "
4470 auto value = APInt::getAllOnes(1);
4471 auto type = UIntType::get(builder.getContext(), 1);
4472 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4473 value.getBitWidth(),
4474 IntegerType::Unsigned),
4476 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4477 RefForceInitialOp::create(builder, pred, dest, src);
4483ParseResult FIRStmtParser::parseRefRelease() {
4484 auto startTok = consumeToken(FIRToken::lp_release);
4486 Value clock, pred, dest;
4487 if (parseExp(clock,
"expected clock expression in release") ||
4488 parseToken(FIRToken::comma,
"expected ','") ||
4489 parseExp(pred,
"expected predicate expression in release") ||
4490 parseToken(FIRToken::comma,
"expected ','") ||
4492 "expected destination reference expression in release") ||
4493 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4494 parseOptionalInfo())
4498 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4499 !ref || !ref.getForceable())
4502 "expected rwprobe-type expression for release destination, got ")
4505 locationProcessor.setLoc(startTok.getLoc());
4507 RefReleaseOp::create(builder, clock, pred, dest);
4513ParseResult FIRStmtParser::parseRefReleaseInitial() {
4514 auto startTok = consumeToken(FIRToken::lp_release_initial);
4519 "expected destination reference expression in release_initial") ||
4520 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4521 parseOptionalInfo())
4525 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4526 !ref || !ref.getForceable())
4527 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4528 "release_initial destination, got ")
4531 locationProcessor.setLoc(startTok.getLoc());
4533 auto value = APInt::getAllOnes(1);
4534 auto type = UIntType::get(builder.getContext(), 1);
4535 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4536 value.getBitWidth(),
4537 IntegerType::Unsigned),
4539 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4540 RefReleaseInitialOp::create(builder, pred, dest);
4546ParseResult FIRStmtParser::parseConnect() {
4547 auto startTok = consumeToken(FIRToken::kw_connect);
4548 auto loc = startTok.getLoc();
4551 if (parseExp(lhs,
"expected connect expression") ||
4552 parseToken(FIRToken::comma,
"expected ','") ||
4553 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4556 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4557 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4558 if (!lhsType || !rhsType)
4559 return emitError(loc,
"cannot connect reference or property types");
4561 if (lhsType.containsReference() || rhsType.containsReference())
4562 return emitError(loc,
"cannot connect types containing references");
4565 return emitError(loc,
"cannot connect non-equivalent type ")
4566 << rhsType <<
" to " << lhsType;
4568 locationProcessor.setLoc(loc);
4574ParseResult FIRStmtParser::parsePropAssert() {
4575 auto startTok = consumeToken(FIRToken::kw_propassert);
4576 auto loc = startTok.getLoc();
4580 if (parseExp(condition,
"expected condition in 'propassert'") ||
4581 parseToken(FIRToken::comma,
"expected ','") ||
4582 parseGetSpelling(message) ||
4583 parseToken(FIRToken::string,
"expected message string in 'propassert'"))
4586 if (!isa<BoolType>(condition.getType()))
4587 return emitError(loc,
"propassert condition must be of boolean type");
4589 if (parseOptionalInfo())
4592 locationProcessor.setLoc(loc);
4594 PropertyAssertOp::create(builder, condition,
4595 builder.getStringAttr(messageUnescaped));
4600ParseResult FIRStmtParser::parsePropAssign() {
4601 auto startTok = consumeToken(FIRToken::kw_propassign);
4602 auto loc = startTok.getLoc();
4605 if (parseExp(lhs,
"expected propassign expression") ||
4606 parseToken(FIRToken::comma,
"expected ','") ||
4607 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4610 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4611 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4612 if (!lhsType || !rhsType)
4613 return emitError(loc,
"can only propassign property types");
4614 locationProcessor.setLoc(loc);
4615 if (lhsType != rhsType) {
4617 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4618 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4620 return emitError(loc,
"cannot propassign non-equivalent type ")
4621 << rhsType <<
" to " << lhsType;
4623 PropAssignOp::create(builder, lhs, rhs);
4628ParseResult FIRStmtParser::parseInvalidate() {
4629 auto startTok = consumeToken(FIRToken::kw_invalidate);
4634 auto loc = getToken().getLoc();
4636 if (parseId(
id,
"expected static reference expression") ||
4637 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4642 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4643 if (parseOptionalExpPostscript(lhs,
false) ||
4644 parseOptionalInfo())
4647 locationProcessor.setLoc(startTok.getLoc());
4648 emitInvalidate(lhs);
4655 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4657 if (getToken().isNot(FIRToken::period)) {
4658 locationProcessor.setLoc(loc);
4660 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4662 for (
auto elt : ubEntry)
4663 emitInvalidate(elt.second);
4669 StringRef fieldName;
4670 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4671 parseFieldId(fieldName,
"expected field name") ||
4672 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4676 if (parseOptionalExpPostscript(lhs,
false) ||
4677 parseOptionalInfo())
4680 locationProcessor.setLoc(startTok.getLoc());
4681 emitInvalidate(lhs);
4685ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4687 auto startTok = consumeToken();
4688 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4689 "consumed an unexpected token");
4690 auto loc = startTok.getLoc();
4693 if (parseId(
id,
"expected layer identifer") ||
4694 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4695 parseOptionalInfo())
4698 locationProcessor.setLoc(loc);
4700 StringRef rootLayer;
4701 SmallVector<FlatSymbolRefAttr> nestedLayers;
4705 rootLayer = layerSym.getRootReference();
4706 auto nestedRefs = layerSym.getNestedReferences();
4707 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4708 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4711 auto layerBlockOp = LayerBlockOp::create(
4713 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4714 layerBlockOp->getRegion(0).push_back(
new Block());
4716 if (getIndentation() > indent)
4717 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4718 layerBlockOp.getLayerName()))
4726ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4727 auto loc = getToken().getLoc();
4730 if (consumeIf(FIRToken::kw_is)) {
4731 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4732 parseOptionalInfo())
4735 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4738 locationProcessor.setLoc(loc);
4739 emitInvalidate(lhs);
4743 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4746 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4750 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4753 locationProcessor.setLoc(loc);
4755 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4756 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4757 if (!lhsType || !rhsType)
4758 return emitError(loc,
"cannot connect reference or property types");
4760 if (lhsType.containsReference() || rhsType.containsReference())
4761 return emitError(loc,
"cannot connect types containing references");
4764 return emitError(loc,
"cannot connect non-equivalent type ")
4765 << rhsType <<
" to " << lhsType;
4774ParseResult FIRStmtParser::parseInstance() {
4775 auto startTok = consumeToken(FIRToken::kw_inst);
4779 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4783 StringRef moduleName;
4784 if (parseId(
id,
"expected instance name") ||
4785 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4786 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4789 locationProcessor.setLoc(startTok.getLoc());
4792 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4793 if (!referencedModule)
4796 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4798 auto annotations = getConstants().emptyArrayAttr;
4799 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4801 hw::InnerSymAttr sym = {};
4802 auto result = InstanceOp::create(
4803 builder, referencedModule,
id, NameKindEnum::InterestingName,
4804 annotations.getValue(), portAnnotations,
false,
false, sym);
4810 unbundledValueEntry.reserve(modulePorts.size());
4811 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4812 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4816 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4817 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4818 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4823ParseResult FIRStmtParser::parseInstanceChoice() {
4824 auto startTok = consumeToken(FIRToken::kw_instchoice);
4825 SMLoc loc = startTok.getLoc();
4828 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4835 StringRef defaultModuleName;
4836 StringRef optionGroupName;
4837 if (parseId(
id,
"expected instance name") ||
4838 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4839 parseId(defaultModuleName,
"expected module name") ||
4840 parseToken(FIRToken::comma,
"expected ','") ||
4841 parseId(optionGroupName,
"expected option group name") ||
4842 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4843 parseOptionalInfo())
4846 locationProcessor.setLoc(startTok.getLoc());
4850 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4854 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4857 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4859 return emitError(loc,
4860 "use of undefined option group '" + optionGroupName +
"'");
4862 auto baseIndent = getIndentation();
4863 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4864 while (getIndentation() == baseIndent) {
4866 StringRef caseModuleName;
4867 if (parseId(caseId,
"expected a case identifier") ||
4868 parseToken(FIRToken::equal_greater,
4869 "expected '=> in instance choice definition") ||
4870 parseId(caseModuleName,
"expected module name"))
4873 auto caseModule = getReferencedModule(loc, caseModuleName);
4877 for (
const auto &[defaultPort, casePort] :
4878 llvm::zip(modulePorts, caseModule.getPorts())) {
4879 if (defaultPort.name != casePort.name)
4880 return emitError(loc,
"instance case module port '")
4881 << casePort.name.getValue()
4882 <<
"' does not match the default module port '"
4883 << defaultPort.name.getValue() <<
"'";
4884 if (defaultPort.type != casePort.type)
4885 return emitError(loc,
"instance case port '")
4886 << casePort.name.getValue()
4887 <<
"' type does not match the default module port";
4891 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4893 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4894 caseModules.emplace_back(optionCase, caseModule);
4897 auto annotations = getConstants().emptyArrayAttr;
4898 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4902 auto result = InstanceChoiceOp::create(
4903 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4904 annotations.getValue(), portAnnotations, sym);
4908 unbundledValueEntry.reserve(modulePorts.size());
4909 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4910 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4912 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4913 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4914 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4917FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4918 StringRef moduleName) {
4919 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4920 if (!referencedModule) {
4922 "use of undefined module name '" + moduleName +
"' in instance");
4925 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4926 emitError(loc,
"cannot create instance of class '" + moduleName +
4927 "', did you mean object?");
4930 return referencedModule;
4934ParseResult FIRStmtParser::parseObject() {
4935 auto startTok = consumeToken(FIRToken::kw_object);
4939 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4946 StringRef className;
4947 if (parseId(
id,
"expected object name") ||
4948 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4949 parseId(className,
"expected class name") || parseOptionalInfo())
4952 locationProcessor.setLoc(startTok.getLoc());
4955 const auto &classMap = getConstants().classMap;
4956 auto lookup = classMap.find(className);
4957 if (lookup == classMap.end())
4958 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4959 className +
"' in object");
4960 auto referencedClass = lookup->getSecond();
4961 auto result = ObjectOp::create(builder, referencedClass,
id);
4962 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4966ParseResult FIRStmtParser::parseCombMem() {
4968 auto startTok = consumeToken(FIRToken::kw_cmem);
4972 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4977 if (parseId(
id,
"expected cmem name") ||
4978 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4979 parseType(type,
"expected cmem type") || parseOptionalInfo())
4982 locationProcessor.setLoc(startTok.getLoc());
4985 auto vectorType = type_dyn_cast<FVectorType>(type);
4987 return emitError(
"cmem requires vector type");
4989 auto annotations = getConstants().emptyArrayAttr;
4990 StringAttr sym = {};
4991 auto result = CombMemOp::create(
4992 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4993 NameKindEnum::InterestingName, annotations, sym);
4994 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4998ParseResult FIRStmtParser::parseSeqMem() {
5000 auto startTok = consumeToken(FIRToken::kw_smem);
5004 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5009 RUWBehavior ruw = RUWBehavior::Undefined;
5011 if (parseId(
id,
"expected smem name") ||
5012 parseToken(FIRToken::colon,
"expected ':' in smem") ||
5016 if (consumeIf(FIRToken::comma)) {
5021 if (parseOptionalInfo()) {
5025 locationProcessor.setLoc(startTok.getLoc());
5028 auto vectorType = type_dyn_cast<FVectorType>(type);
5030 return emitError(
"smem requires vector type");
5032 auto annotations = getConstants().emptyArrayAttr;
5033 StringAttr sym = {};
5034 auto result = SeqMemOp::create(
5035 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
5036 id, NameKindEnum::InterestingName, annotations, sym);
5037 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5049ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
5050 auto startTok = consumeToken(FIRToken::kw_mem);
5054 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5058 if (parseId(
id,
"expected mem name") ||
5059 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
5063 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5064 RUWBehavior ruw = RUWBehavior::Undefined;
5066 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5070 auto nextIndent = getIndentation();
5071 if (!nextIndent || *nextIndent <= memIndent)
5074 auto spelling = getTokenSpelling();
5075 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
5076 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
5079 if (spelling ==
"data-type") {
5081 return emitError(
"'mem' type specified multiple times"), failure();
5083 if (
parseType(type,
"expected type in data-type declaration"))
5087 if (spelling ==
"depth") {
5088 if (parseIntLit(depth,
"expected integer in depth specification"))
5092 if (spelling ==
"read-latency") {
5093 if (parseIntLit(readLatency,
"expected integer latency"))
5097 if (spelling ==
"write-latency") {
5098 if (parseIntLit(writeLatency,
"expected integer latency"))
5102 if (spelling ==
"read-under-write") {
5103 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5104 FIRToken::kw_undefined))
5105 return emitError(
"expected specifier"), failure();
5107 if (parseOptionalRUW(ruw))
5112 MemOp::PortKind portKind;
5113 if (spelling ==
"reader")
5114 portKind = MemOp::PortKind::Read;
5115 else if (spelling ==
"writer")
5116 portKind = MemOp::PortKind::Write;
5117 else if (spelling ==
"readwriter")
5118 portKind = MemOp::PortKind::ReadWrite;
5120 return emitError(
"unexpected field in 'mem' declaration"), failure();
5123 if (parseId(portName,
"expected port name"))
5125 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5127 return emitError(
"unexpected type, must be base type");
5128 ports.push_back({builder.getStringAttr(portName),
5129 MemOp::getTypeForPort(depth, baseType, portKind)});
5131 while (!getIndentation().has_value()) {
5132 if (parseId(portName,
"expected port name"))
5134 ports.push_back({builder.getStringAttr(portName),
5135 MemOp::getTypeForPort(depth, baseType, portKind)});
5146 llvm::array_pod_sort(ports.begin(), ports.end(),
5147 [](
const std::pair<StringAttr, Type> *lhs,
5148 const std::pair<StringAttr, Type> *rhs) ->
int {
5149 return lhs->first.getValue().compare(
5150 rhs->first.getValue());
5153 auto annotations = getConstants().emptyArrayAttr;
5154 SmallVector<Attribute, 4> resultNames;
5155 SmallVector<Type, 4> resultTypes;
5156 SmallVector<Attribute, 4> resultAnnotations;
5157 for (
auto p : ports) {
5158 resultNames.push_back(p.first);
5159 resultTypes.push_back(p.second);
5160 resultAnnotations.push_back(annotations);
5163 locationProcessor.setLoc(startTok.getLoc());
5165 auto result = MemOp::create(
5166 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5167 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5168 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5169 MemoryInitAttr(), StringAttr());
5172 unbundledValueEntry.reserve(result.getNumResults());
5173 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5174 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5176 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5177 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5178 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5182ParseResult FIRStmtParser::parseNode() {
5183 auto startTok = consumeToken(FIRToken::kw_node);
5187 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5192 if (parseId(
id,
"expected node name") ||
5193 parseToken(FIRToken::equal,
"expected '=' in node") ||
5194 parseExp(initializer,
"expected expression for node") ||
5195 parseOptionalInfo())
5198 locationProcessor.setLoc(startTok.getLoc());
5210 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5211 auto initializerBaseType =
5212 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5213 if (type_isa<AnalogType>(initializerType) ||
5214 !(initializerBaseType && initializerBaseType.isPassive())) {
5215 emitError(startTok.getLoc())
5216 <<
"Node cannot be analog and must be passive or passive under a flip "
5217 << initializer.getType();
5221 auto annotations = getConstants().emptyArrayAttr;
5222 StringAttr sym = {};
5224 auto result = NodeOp::create(builder, initializer,
id,
5225 NameKindEnum::InterestingName, annotations, sym);
5226 return moduleContext.addSymbolEntry(
id, result.getResult(),
5231ParseResult FIRStmtParser::parseWire() {
5232 auto startTok = consumeToken(FIRToken::kw_wire);
5236 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5241 if (parseId(
id,
"expected wire name") ||
5242 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5247 SmallVector<Value> domains;
5248 if (consumeIf(FIRToken::kw_domains)) {
5252 if (parseToken(FIRToken::l_square,
"expected '[' after 'domains'"))
5255 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5256 StringRef domainName;
5257 auto domainLoc = getToken().getLoc();
5258 if (parseId(domainName,
"expected domain name"))
5263 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5268 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5271 if (!isa<DomainType>(domainValue.getType()))
5272 return emitError(domainLoc)
5273 <<
"'" << domainName <<
"' is not a domain";
5275 domains.push_back(domainValue);
5281 if (parseOptionalInfo())
5284 locationProcessor.setLoc(startTok.getLoc());
5286 auto annotations = getConstants().emptyArrayAttr;
5287 StringAttr sym = {};
5290 auto namekind = isa<PropertyType, RefType>(type)
5291 ? NameKindEnum::DroppableName
5292 : NameKindEnum::InterestingName;
5294 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym,
5296 return moduleContext.addSymbolEntry(
id, result.getResult(),
5310ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5311 auto startTok = consumeToken(FIRToken::kw_reg);
5315 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5324 if (parseId(
id,
"expected reg name") ||
5325 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5327 parseToken(FIRToken::comma,
"expected ','") ||
5328 parseExp(clock,
"expected expression for register clock"))
5331 if (!type_isa<FIRRTLBaseType>(type))
5332 return emitError(startTok.getLoc(),
"register must have base type");
5335 Value resetSignal, resetValue;
5336 if (consumeIf(FIRToken::kw_with)) {
5337 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5340 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5348 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5350 auto indent = getIndentation();
5351 if (!indent || *indent <= regIndent)
5352 if (!hasExtraLParen)
5353 return emitError(
"expected indented reset specifier in reg"), failure();
5355 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5356 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5357 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5358 parseExp(resetSignal,
"expected expression for reset signal") ||
5359 parseToken(FIRToken::comma,
"expected ','"))
5367 if (getTokenSpelling() ==
id) {
5369 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5371 resetSignal = Value();
5373 if (parseExp(resetValue,
"expected expression for reset value") ||
5374 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5378 if (hasExtraLParen &&
5379 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5385 if (parseOptionalInfo())
5388 locationProcessor.setLoc(startTok.getLoc());
5390 ArrayAttr annotations = getConstants().emptyArrayAttr;
5392 StringAttr sym = {};
5395 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5396 NameKindEnum::InterestingName, annotations, sym)
5399 result = RegOp::create(builder, type, clock,
id,
5400 NameKindEnum::InterestingName, annotations, sym)
5402 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5410ParseResult FIRStmtParser::parseRegisterWithReset() {
5411 auto startTok = consumeToken(FIRToken::kw_regreset);
5415 Value clock, resetSignal, resetValue;
5417 if (parseId(
id,
"expected reg name") ||
5418 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5420 parseToken(FIRToken::comma,
"expected ','") ||
5421 parseExp(clock,
"expected expression for register clock") ||
5422 parseToken(FIRToken::comma,
"expected ','") ||
5423 parseExp(resetSignal,
"expected expression for register reset") ||
5424 parseToken(FIRToken::comma,
"expected ','") ||
5425 parseExp(resetValue,
"expected expression for register reset value") ||
5426 parseOptionalInfo())
5429 if (!type_isa<FIRRTLBaseType>(type))
5430 return emitError(startTok.getLoc(),
"register must have base type");
5432 locationProcessor.setLoc(startTok.getLoc());
5435 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5436 NameKindEnum::InterestingName,
5437 getConstants().emptyArrayAttr, StringAttr{})
5440 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5445ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5449 auto startTok = consumeToken(FIRToken::kw_contract);
5452 SmallVector<StringRef> ids;
5453 SmallVector<SMLoc> locs;
5454 SmallVector<Value> values;
5455 SmallVector<Type> types;
5456 if (!consumeIf(FIRToken::colon)) {
5457 auto parseContractId = [&] {
5459 locs.push_back(getToken().
getLoc());
5460 if (parseId(
id,
"expected contract result name"))
5465 auto parseContractValue = [&] {
5467 if (parseExp(value,
"expected expression for contract result"))
5469 values.push_back(value);
5470 types.push_back(value.getType());
5473 if (parseListUntil(FIRToken::equal, parseContractId) ||
5474 parseListUntil(FIRToken::colon, parseContractValue))
5477 if (parseOptionalInfo())
5481 if (ids.size() != values.size())
5482 return emitError(startTok.getLoc())
5483 <<
"contract requires same number of results and expressions; got "
5484 << ids.size() <<
" results and " << values.size()
5485 <<
" expressions instead";
5487 locationProcessor.setLoc(startTok.getLoc());
5491 auto contract = ContractOp::create(builder, types, values);
5492 auto &block = contract.getBody().emplaceBlock();
5496 FIRModuleContext::ContextScope scope(moduleContext, &block);
5497 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5498 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5499 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5502 if (getIndentation() > blockIndent)
5503 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5508 for (
auto [
id, loc, value, result] :
5509 llvm::zip(ids, locs, values, contract.getResults())) {
5511 moduleContext.removeSymbolEntry(
id);
5512 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5525struct FIRCircuitParser :
public FIRParser {
5526 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5528 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5531 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5532 mlir::TimingScope &ts);
5537 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5538 SmallVectorImpl<Attribute> &attrs);
5540 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5542 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5543 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5544 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5545 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5546 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5547 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5548 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5549 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5551 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5553 ParseResult parseLayerName(SymbolRefAttr &result);
5554 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5555 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5556 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5557 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5558 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5559 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5560 ArrayAttr &knownLayers,
5561 ArrayAttr &externalRequirements);
5563 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5564 SmallVectorImpl<SMLoc> &resultPortLocs,
5568 ParseResult skipToModuleEnd(
unsigned indent);
5570 ParseResult parseTypeDecl();
5572 ParseResult parseOptionDecl(CircuitOp circuit);
5574 ParseResult parseLayer(CircuitOp circuit);
5576 ParseResult resolveDomains(
5577 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5578 const DenseMap<Attribute, size_t> &nameToIndex,
5579 SmallVectorImpl<Attribute> &domainsByIndex);
5582 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5583 const DenseMap<Attribute, size_t> &nameToIndex);
5585 struct DeferredModuleToParse {
5586 FModuleLike moduleOp;
5587 SmallVector<SMLoc> portLocs;
5592 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5593 DeferredModuleToParse &deferredModule,
5594 InnerSymFixups &fixups);
5596 SmallVector<DeferredModuleToParse, 0> deferredModules;
5598 SmallVector<InnerSymFixups, 0> moduleFixups;
5602 ModuleOp mlirModule;
5607FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5608 SmallVectorImpl<Attribute> &attrs) {
5610 auto annotations = json::parse(annotationsStr);
5611 if (
auto err = annotations.takeError()) {
5612 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5613 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5614 diag.attachNote() <<
a.message();
5619 json::Path::Root root;
5620 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5623 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5624 std::string jsonErrorMessage =
5625 "See inline comments for problem area in JSON:\n";
5626 llvm::raw_string_ostream
s(jsonErrorMessage);
5627 root.printErrorContext(annotations.get(), s);
5628 diag.attachNote() << jsonErrorMessage;
5635ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5637 SmallVector<StringRef> strings;
5640 if (parseId(name,
"expected layer name"))
5642 strings.push_back(name);
5643 }
while (consumeIf(FIRToken::period));
5645 SmallVector<FlatSymbolRefAttr> nested;
5646 nested.reserve(strings.size() - 1);
5647 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5648 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5650 result = SymbolRefAttr::get(
context, strings[0], nested);
5654ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5655 SmallVector<Attribute> enabledLayersBuffer;
5657 auto tokenKind = getToken().getKind();
5659 if (tokenKind == FIRToken::kw_enablelayer) {
5660 if (parseEnableLayerSpec(enabledLayersBuffer))
5668 if (enabledLayersBuffer.size() != 0)
5669 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5672 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5676ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5677 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5678 ArrayAttr &externalRequirements) {
5679 SmallVector<Attribute> enabledLayersBuffer;
5680 SmallVector<Attribute> knownLayersBuffer;
5681 SmallVector<Attribute> requirementsBuffer;
5683 auto tokenKind = getToken().getKind();
5685 if (tokenKind == FIRToken::kw_enablelayer) {
5686 if (parseEnableLayerSpec(enabledLayersBuffer))
5691 if (tokenKind == FIRToken::kw_knownlayer) {
5692 if (parseKnownLayerSpec(knownLayersBuffer))
5697 if (tokenKind == FIRToken::kw_requires) {
5698 if (parseRequiresSpec(requirementsBuffer))
5706 if (enabledLayersBuffer.size() != 0)
5707 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5710 if (knownLayersBuffer.size() != 0)
5711 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5714 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5715 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5716 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5721FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5723 SymbolRefAttr layer;
5724 if (parseLayerName(layer))
5726 result.push_back(layer);
5727 }
while (consumeIf(FIRToken::comma));
5732FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5733 consumeToken(FIRToken::kw_enablelayer);
5734 return parseLayerList(result);
5738FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5739 consumeToken(FIRToken::kw_knownlayer);
5740 return parseLayerList(result);
5744FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5745 consumeToken(FIRToken::kw_requires);
5747 StringRef requireStr;
5748 if (parseGetSpelling(requireStr) ||
5749 parseToken(FIRToken::string,
"expected string after 'requires'"))
5753 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5754 }
while (consumeIf(FIRToken::comma));
5762FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5763 SmallVectorImpl<SMLoc> &resultPortLocs,
5769 DenseMap<Attribute, size_t> nameToIndex;
5770 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5773 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5775 getIndentation() > indent) {
5781 auto backtrackState = getLexer().getCursor();
5783 bool isOutput = getToken().is(FIRToken::kw_output);
5788 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5789 !getToken().isKeyword()) {
5790 backtrackState.restore(getLexer());
5797 if (parseId(name,
"expected port name") ||
5798 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5799 parseType(type,
"expected a type in port declaration"))
5801 Attribute domainInfoElement = {};
5802 size_t portIdx = resultPorts.size();
5803 if (
auto domainType = dyn_cast<DomainType>(type)) {
5806 domainInfoElement = ArrayAttr::get(getContext(), {});
5808 if (getToken().is(FIRToken::kw_domains))
5809 if (parseDomains(domainNames[portIdx], nameToIndex))
5813 if (
info.parseOptionalInfo())
5816 StringAttr innerSym = {};
5817 resultPorts.push_back(
PortInfo{name,
5823 domainInfoElement});
5824 resultPortLocs.push_back(
info.getFIRLoc());
5825 nameToIndex.insert({name, portIdx});
5829 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5830 auto &port = resultPorts[portIdx];
5831 Attribute &attr = port.domains;
5835 SmallVector<Attribute> domainInfo;
5836 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5838 attr = ArrayAttr::get(getContext(), domainInfo);
5843 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5844 PortInfo &port = std::get<0>(portAndLoc);
5845 auto &entry = portIds[port.
name];
5846 if (!entry.isValid()) {
5847 entry = std::get<1>(portAndLoc);
5851 emitError(std::get<1>(portAndLoc),
5852 "redefinition of name '" + port.
getName() +
"'")
5853 .attachNote(translateLocation(entry))
5854 <<
"previous definition here";
5863ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5865 switch (getToken().getKind()) {
5869 case FIRToken::error:
5873 case FIRToken::kw_class:
5874 case FIRToken::kw_domain:
5875 case FIRToken::kw_declgroup:
5876 case FIRToken::kw_extclass:
5877 case FIRToken::kw_extmodule:
5878 case FIRToken::kw_intmodule:
5879 case FIRToken::kw_formal:
5880 case FIRToken::kw_module:
5881 case FIRToken::kw_public:
5882 case FIRToken::kw_layer:
5883 case FIRToken::kw_option:
5884 case FIRToken::kw_simulation:
5885 case FIRToken::kw_type:
5889 if (getIndentation() == indent)
5901ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5902 SmallVector<Attribute, 8> parameters;
5903 SmallPtrSet<StringAttr, 8> seen;
5904 while (consumeIf(FIRToken::kw_parameter)) {
5908 if (parseParameter(name, value, loc))
5910 auto typedValue = dyn_cast<TypedAttr>(value);
5912 return emitError(loc)
5913 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5914 if (!seen.insert(name).second)
5915 return emitError(loc,
5916 "redefinition of parameter '" + name.getValue() +
"'");
5917 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5919 resultParameters = ArrayAttr::get(getContext(), parameters);
5924ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5926 SmallVector<PortInfo, 8> portList;
5927 SmallVector<SMLoc> portLocs;
5933 consumeToken(FIRToken::kw_class);
5934 if (parseId(name,
"expected class name") ||
5935 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5939 if (name == circuit.getName())
5940 return mlir::emitError(
info.getLoc(),
5941 "class cannot be the top of a circuit");
5943 for (
auto &portInfo : portList)
5945 return
mlir::emitError(portInfo.loc,
5946 "ports on classes must be properties");
5949 auto builder = circuit.getBodyBuilder();
5950 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5951 classOp.setPrivate();
5952 deferredModules.emplace_back(
5953 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5956 getConstants().classMap[name.getValue()] = classOp;
5957 return skipToModuleEnd(indent);
5961ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5962 consumeToken(FIRToken::kw_domain);
5966 if (parseId(name,
"domain name") ||
5967 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5968 info.parseOptionalInfo())
5971 SmallVector<Attribute> fields;
5973 auto nextIndent = getIndentation();
5974 if (!nextIndent || *nextIndent <= indent)
5977 StringAttr fieldName;
5979 if (parseId(fieldName,
"field name") ||
5980 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5981 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5985 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5988 auto builder = circuit.getBodyBuilder();
5989 auto domainOp = DomainOp::create(builder,
info.getLoc(), name,
5990 builder.getArrayAttr(fields));
5994 getConstants().domainMap[name.getValue()] = domainOp;
6000ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
6003 SmallVector<PortInfo, 8> portList;
6004 SmallVector<SMLoc> portLocs;
6010 consumeToken(FIRToken::kw_extclass);
6011 if (parseId(name,
"expected extclass name") ||
6012 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
6016 if (name == circuit.getName())
6017 return mlir::emitError(
info.getLoc(),
6018 "extclass cannot be the top of a circuit");
6020 for (
auto &portInfo : portList)
6022 return
mlir::emitError(portInfo.loc,
6023 "ports on extclasses must be properties");
6026 auto builder = circuit.getBodyBuilder();
6027 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
6030 getConstants().classMap[name.getValue()] = extClassOp;
6031 return skipToModuleEnd(indent);
6039ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
6042 ArrayAttr enabledLayers;
6043 ArrayAttr knownLayers;
6044 ArrayAttr externalRequirements;
6045 SmallVector<PortInfo, 8> portList;
6046 SmallVector<SMLoc> portLocs;
6048 consumeToken(FIRToken::kw_extmodule);
6049 if (parseId(name,
"expected extmodule name") ||
6050 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
6051 externalRequirements) ||
6052 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
6057 if (consumeIf(FIRToken::kw_defname)) {
6058 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
6059 parseId(defName,
"expected defname name"))
6063 ArrayAttr parameters;
6068 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6069 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6070 if (ftype.hasUninferredWidth())
6071 return emitError(loc,
"extmodule port must have known width");
6076 auto builder = circuit.getBodyBuilder();
6077 auto isMainModule = (name == circuit.getName());
6079 (isMainModule && getConstants().options.scalarizePublicModules) ||
6080 getConstants().options.scalarizeExtModules
6081 ? Convention::Scalarized
6082 : Convention::Internal;
6083 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6084 auto annotations = ArrayAttr::get(getContext(), {});
6085 auto extModuleOp = FExtModuleOp::create(
6086 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
6087 defName, annotations, parameters, enabledLayers, externalRequirements);
6088 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6089 : SymbolTable::Visibility::Private;
6090 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6098ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6102 ArrayAttr enabledLayers;
6103 SmallVector<PortInfo, 8> portList;
6104 SmallVector<SMLoc> portLocs;
6106 consumeToken(FIRToken::kw_intmodule);
6107 if (parseId(name,
"expected intmodule name") ||
6108 parseModuleLayerSpec(enabledLayers) ||
6109 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
6111 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
6112 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
6113 parseId(intName,
"expected intrinsic name"))
6116 ArrayAttr parameters;
6120 ArrayAttr annotations = getConstants().emptyArrayAttr;
6121 auto builder = circuit.getBodyBuilder();
6122 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
6123 annotations, parameters, enabledLayers)
6129ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
6132 SmallVector<PortInfo, 8> portList;
6133 SmallVector<SMLoc> portLocs;
6134 ArrayAttr enabledLayers;
6135 auto modLoc = getToken().getLoc();
6136 LocWithInfo
info(modLoc,
this);
6137 consumeToken(FIRToken::kw_module);
6138 if (parseId(name,
"expected module name") ||
6139 parseModuleLayerSpec(enabledLayers) ||
6140 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
6145 if (name == circuit.getName()) {
6146 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
6151 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
6152 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6153 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6154 if (ftype.hasUninferredWidth())
6155 return emitError(loc,
"public module port must have known width");
6156 if (ftype.hasUninferredReset())
6157 return emitError(loc,
6158 "public module port must have concrete reset type");
6163 ArrayAttr annotations = getConstants().emptyArrayAttr;
6164 auto convention = Convention::Internal;
6165 if (isPublic && getConstants().options.scalarizePublicModules)
6166 convention = Convention::Scalarized;
6167 if (!isPublic && getConstants().options.scalarizeInternalModules)
6168 convention = Convention::Scalarized;
6169 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6170 auto builder = circuit.getBodyBuilder();
6172 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6173 annotations, enabledLayers);
6175 auto visibility = isPublic ? SymbolTable::Visibility::Public
6176 : SymbolTable::Visibility::Private;
6177 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6181 deferredModules.emplace_back(DeferredModuleToParse{
6182 moduleOp, portLocs, getLexer().getCursor(), indent});
6184 if (skipToModuleEnd(indent))
6190ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6191 consumeToken(FIRToken::kw_formal);
6192 return parseFormalLike<FormalOp>(circuit, indent);
6196ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6198 consumeToken(FIRToken::kw_simulation);
6199 return parseFormalLike<SimulationOp>(circuit, indent);
6206ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6208 StringRef id, moduleName;
6211 auto builder = circuit.getBodyBuilder();
6214 if (parseId(
id,
"expected test name") ||
6215 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6216 parseId(moduleName,
"expected module name"))
6220 NamedAttrList params;
6221 if (consumeIf(FIRToken::comma)) {
6223 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6224 return emitError(
"expected 'bound' after ','");
6226 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6227 parseIntLit(bound,
"expected integer bound after '='"))
6230 return emitError(
"bound must be a positive integer");
6231 if (
info.parseOptionalInfo())
6233 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6236 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6237 info.parseOptionalInfo())
6239 while (getIndentation() > indent) {
6240 StringAttr paramName;
6241 Attribute paramValue;
6243 if (parseParameter(paramName, paramValue, paramLoc,
6246 if (params.set(paramName, paramValue))
6247 return emitError(paramLoc,
"redefinition of parameter '" +
6248 paramName.getValue() +
"'");
6252 Op::create(builder,
info.getLoc(),
id, moduleName,
6253 params.getDictionary(getContext()));
6257ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6259 switch (getToken().getKind()) {
6260 case FIRToken::kw_class:
6261 return parseClass(circuit, indent);
6262 case FIRToken::kw_declgroup:
6263 if (requireFeature({3, 2, 0},
"optional groups") ||
6264 removedFeature({3, 3, 0},
"optional groups"))
6266 return parseLayer(circuit);
6267 case FIRToken::kw_domain:
6270 return parseDomain(circuit, indent);
6271 case FIRToken::kw_extclass:
6272 return parseExtClass(circuit, indent);
6273 case FIRToken::kw_extmodule:
6274 return parseExtModule(circuit, indent);
6275 case FIRToken::kw_formal:
6276 if (requireFeature({4, 0, 0},
"formal tests"))
6278 return parseFormal(circuit, indent);
6279 case FIRToken::kw_intmodule:
6280 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6281 removedFeature({4, 0, 0},
"intrinsic modules"))
6283 return parseIntModule(circuit, indent);
6284 case FIRToken::kw_layer:
6285 if (requireFeature({3, 3, 0},
"layers"))
6287 return parseLayer(circuit);
6288 case FIRToken::kw_module:
6289 return parseModule(circuit,
false, indent);
6290 case FIRToken::kw_public:
6291 if (requireFeature({3, 3, 0},
"public modules"))
6294 if (getToken().getKind() == FIRToken::kw_module)
6295 return parseModule(circuit,
true, indent);
6296 return emitError(getToken().
getLoc(),
"only modules may be public");
6297 case FIRToken::kw_simulation:
6300 return parseSimulation(circuit, indent);
6301 case FIRToken::kw_type:
6302 return parseTypeDecl();
6303 case FIRToken::kw_option:
6306 return parseOptionDecl(circuit);
6308 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6313ParseResult FIRCircuitParser::parseTypeDecl() {
6317 auto loc = getToken().getLoc();
6319 if (getToken().isKeyword())
6320 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6321 <<
"' for type alias name";
6323 if (parseId(
id,
"expected type name") ||
6324 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6327 auto name = StringAttr::get(type.getContext(),
id);
6330 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6331 type = BaseTypeAliasType::get(name, base);
6334 <<
"type alias for non-base type " << type
6335 <<
" is currently not supported. Type alias is stripped immediately";
6337 if (!getConstants().aliasMap.insert({id, type}).second)
6338 return emitError(loc) <<
"type alias `" << name.getValue()
6339 <<
"` is already defined";
6344ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6347 auto loc = getToken().getLoc();
6350 if (parseId(
id,
"expected an option group name") ||
6351 parseToken(FIRToken::colon,
6352 "expected ':' after option group definition") ||
6353 info.parseOptionalInfo())
6356 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6357 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6358 auto *block =
new Block;
6359 optionOp.getBody().push_back(block);
6360 builder.setInsertionPointToEnd(block);
6362 auto baseIndent = getIndentation();
6364 while (getIndentation() == baseIndent) {
6366 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6367 if (parseId(
id,
"expected an option case ID") ||
6368 caseInfo.parseOptionalInfo())
6371 if (!cases.insert(
id).second)
6372 return emitError(loc)
6373 <<
"duplicate option case definition '" <<
id <<
"'";
6375 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6382ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6383 auto baseIndent = getIndentation();
6386 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6389 auto parseOne = [&](
Block *block) -> ParseResult {
6390 auto indent = getIndentation();
6391 StringRef id, convention;
6394 if (parseId(
id,
"expected layer name") ||
6395 parseToken(FIRToken::comma,
"expected ','") ||
6396 parseGetSpelling(convention))
6399 auto layerConvention = symbolizeLayerConvention(convention);
6400 if (!layerConvention) {
6401 emitError() <<
"unknown convention '" << convention
6402 <<
"' (did you misspell it?)";
6405 if (layerConvention == LayerConvention::Inline &&
6406 requireFeature({4, 1, 0},
"inline layers"))
6410 hw::OutputFileAttr outputDir;
6411 if (consumeIf(FIRToken::comma)) {
6412 if (getToken().getKind() == FIRToken::string) {
6413 auto text = getToken().getStringValue();
6415 return emitError() <<
"output directory must not be blank";
6416 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6417 consumeToken(FIRToken::string);
6421 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6422 info.parseOptionalInfo())
6424 auto builder = OpBuilder::atBlockEnd(block);
6427 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6428 layerOp->getRegion(0).push_back(
new Block());
6430 layerOp->setAttr(
"output_file", outputDir);
6431 layerStack.push_back({indent, layerOp});
6435 if (parseOne(circuit.getBodyBlock()))
6439 while (getIndentation() > baseIndent) {
6440 switch (getToken().getKind()) {
6441 case FIRToken::kw_declgroup:
6442 case FIRToken::kw_layer: {
6445 while (layerStack.back().first >= getIndentation())
6446 layerStack.pop_back();
6447 auto parentLayer = layerStack.back().second;
6448 if (parseOne(&parentLayer.getBody().front()))
6453 return emitError(
"expected 'layer'"), failure();
6460ParseResult FIRCircuitParser::resolveDomains(
6461 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6462 const DenseMap<Attribute, size_t> &nameToIndex,
6463 SmallVectorImpl<Attribute> &domainsByIndex) {
6465 for (
auto [attr, loc] : domainsByName) {
6466 auto domain = cast<StringAttr>(attr);
6467 auto indexItr = nameToIndex.find(domain);
6468 if (indexItr == nameToIndex.end()) {
6469 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6472 domainsByIndex.push_back(IntegerAttr::get(
6473 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6480ParseResult FIRCircuitParser::parseDomains(
6481 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6482 const DenseMap<Attribute, size_t> &nameToIndex) {
6485 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6486 parseToken(FIRToken::l_square,
"expected '['"))
6489 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6491 auto domainLoc = getToken().getLoc();
6492 if (parseId(domain,
"expected domain name"))
6494 domains.push_back({domain, domainLoc});
6504FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6505 DeferredModuleToParse &deferredModule,
6506 InnerSymFixups &fixups) {
6507 FModuleLike moduleOp = deferredModule.moduleOp;
6508 auto &body = moduleOp->getRegion(0).front();
6509 auto &portLocs = deferredModule.portLocs;
6513 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6516 deferredModule.lexerCursor.restore(moduleBodyLexer);
6518 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6523 auto portList = moduleOp.getPorts();
6524 auto portArgs = body.getArguments();
6525 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6526 PortInfo &port = std::get<0>(tuple);
6527 llvm::SMLoc loc = std::get<1>(tuple);
6528 BlockArgument portArg = std::get<2>(tuple);
6530 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6534 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6537 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6550ParseResult FIRCircuitParser::parseCircuit(
6551 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6552 mlir::TimingScope &ts) {
6554 auto indent = getIndentation();
6555 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6557 if (!indent.has_value())
6558 return emitError(
"'FIRRTL' must be first token on its line");
6559 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6560 parseVersionLit(
"expected version literal"))
6562 indent = getIndentation();
6564 if (!indent.has_value())
6565 return emitError(
"'circuit' must be first token on its line");
6566 unsigned circuitIndent = *indent;
6570 SMLoc inlineAnnotationsLoc;
6571 StringRef inlineAnnotations;
6574 if (parseToken(FIRToken::kw_circuit,
6575 "expected a top-level 'circuit' definition") ||
6576 parseId(name,
"expected circuit name") ||
6577 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6578 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6579 info.parseOptionalInfo())
6583 OpBuilder
b(mlirModule.getBodyRegion());
6584 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6587 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6593 SmallVector<Attribute> annos;
6594 if (!inlineAnnotations.empty())
6595 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6599 for (
auto *annotationsBuf : annotationsBufs)
6600 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6604 parseAnnotationTimer.stop();
6612 auto parseTimer = ts.nest(
"Parse modules");
6613 deferredModules.reserve(16);
6617 switch (getToken().getKind()) {
6625 case FIRToken::error:
6629 emitError(
"unexpected token in circuit");
6632 case FIRToken::kw_class:
6633 case FIRToken::kw_declgroup:
6634 case FIRToken::kw_domain:
6635 case FIRToken::kw_extclass:
6636 case FIRToken::kw_extmodule:
6637 case FIRToken::kw_intmodule:
6638 case FIRToken::kw_layer:
6639 case FIRToken::kw_formal:
6640 case FIRToken::kw_module:
6641 case FIRToken::kw_option:
6642 case FIRToken::kw_public:
6643 case FIRToken::kw_simulation:
6644 case FIRToken::kw_type: {
6645 auto indent = getIndentation();
6646 if (!indent.has_value())
6647 return emitError(
"'module' must be first token on its line"), failure();
6648 unsigned definitionIndent = *indent;
6650 if (definitionIndent <= circuitIndent)
6651 return emitError(
"module should be indented more"), failure();
6653 if (parseToplevelDefinition(circuit, definitionIndent))
6667 (void)getLexer().translateLocation(
info.getFIRLoc());
6673 DenseMap<Attribute, Location> nameToOrigLoc;
6677 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6682 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6685 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6686 .attachNote(it.first->second)
6687 .append(
"see existing symbol definition here");
6693 SymbolTable circuitSymTbl(circuit);
6695 moduleFixups.resize(deferredModules.size());
6700 for (
auto &d : deferredModules)
6701 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6704 auto anyFailed = mlir::failableParallelForEachN(
6705 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6706 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6707 moduleFixups[index]))
6711 if (failed(anyFailed))
6716 for (
auto &fixups : moduleFixups) {
6717 if (failed(fixups.resolve(innerSymbolNamespaces)))
6723 auto parseLayerName = [&](StringRef name) -> Attribute {
6725 auto [head, rest] = name.split(
".");
6726 SmallVector<FlatSymbolRefAttr> nestedRefs;
6727 while (!rest.empty()) {
6729 std::tie(next, rest) = rest.split(
".");
6730 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6732 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6735 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6736 SmallVector<Attribute> attrArray;
6738 for (
const auto &str : strArray)
6739 attrArray.push_back(getAttr(str));
6740 if (attrArray.empty())
6742 return ArrayAttr::get(
context, attrArray);
6745 if (
auto enableLayers =
6746 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6747 circuit.setEnableLayersAttr(enableLayers);
6748 if (
auto disableLayers =
6749 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6750 circuit.setDisableLayersAttr(disableLayers);
6752 auto getStrAttr = [&](StringRef str) -> Attribute {
6753 return StringAttr::get(getContext(), str);
6756 if (
auto selectInstChoice =
6757 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6758 circuit.setSelectInstChoiceAttr(selectInstChoice);
6760 circuit.setDefaultLayerSpecialization(
6761 getConstants().options.defaultLayerSpecialization);
6774 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6775 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6776 unsigned fileID = 1;
6778 annotationsBufs.push_back(
6779 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6781 context->loadDialect<CHIRRTLDialect>();
6782 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6786 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6789 SharedParserConstants state(
context, options);
6792 .parseCircuit(annotationsBufs, ts))
6797 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6798 if (failed(verify(*module)))
6805 static mlir::TranslateToMLIRRegistration fromFIR(
6806 "import-firrtl",
"import .fir",
6807 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6808 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()
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.
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 nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
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.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
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