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/SourceMgr.h"
43 #include "llvm/Support/raw_ostream.h"
46 using namespace circt;
47 using namespace firrtl;
48 using namespace chirrtl;
51 using llvm::SourceMgr;
52 using mlir::LocationAttr;
65 struct SharedParserConstants {
67 : context(context), options(options),
68 emptyArrayAttr(ArrayAttr::
get(context, {})),
76 MLIRContext *
const context;
82 llvm::StringMap<FIRRTLType> aliasMap;
85 llvm::DenseMap<StringRef, ClassLike> classMap;
88 const ArrayAttr emptyArrayAttr;
91 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
92 const StringAttr fieldIndexIdentifier, indexIdentifier;
95 SharedParserConstants(
const SharedParserConstants &) =
delete;
96 void operator=(
const SharedParserConstants &) =
delete;
109 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
111 : version(version), constants(constants), lexer(lexer),
112 locatorFilenameCache(constants.loIdentifier ) {
116 SharedParserConstants &getConstants()
const {
return constants; }
117 MLIRContext *getContext()
const {
return constants.context; }
119 FIRLexer &getLexer() {
return lexer; }
122 std::optional<unsigned> getIndentation()
const {
127 const FIRToken &getToken()
const {
return lexer.getToken(); }
128 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
135 InFlightDiagnostic emitError(
const Twine &message = {}) {
136 return emitError(getToken().getLoc(), message);
138 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
141 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
142 return emitWarning(getToken().getLoc(), message);
145 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
155 Location translateLocation(llvm::SMLoc loc) {
156 return lexer.translateLocation(loc);
161 ParseResult parseOptionalInfoLocator(LocationAttr &result);
165 ParseResult parseOptionalName(StringAttr &name);
171 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
172 return requireFeature(minimum, feature, getToken().getLoc());
175 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
176 if (version < minimum)
177 return emitError(loc)
178 << feature <<
" are a FIRRTL " << minimum
179 <<
"+ feature, but the specified FIRRTL version was " << version;
183 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
184 return removedFeature(removedVersion, feature, getToken().getLoc());
187 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
189 if (version >= removedVersion)
190 return emitError(loc)
191 << feature <<
" were removed in FIRRTL " << removedVersion
192 <<
", but the specified FIRRTL version was " << version;
202 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
211 if (getToken().isNot(kind))
221 FIRToken consumedToken = getToken();
222 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
223 "shouldn't advance past EOF or errors");
225 return consumedToken;
234 FIRToken consumedToken = getToken();
235 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
237 return consumedToken;
242 ParseResult parseGetSpelling(StringRef &spelling) {
243 spelling = getTokenSpelling();
249 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
254 const std::function<ParseResult()> &parseElement);
261 ParseResult parseIntLit(APInt &result,
const Twine &message);
262 ParseResult parseIntLit(int64_t &result,
const Twine &message);
263 ParseResult parseIntLit(int32_t &result,
const Twine &message);
266 ParseResult parseVersionLit(
const Twine &message);
269 template <
typename T>
270 ParseResult parseOptionalWidth(T &result);
273 ParseResult parseId(StringRef &result,
const Twine &message);
274 ParseResult parseId(StringAttr &result,
const Twine &message);
275 ParseResult parseFieldId(StringRef &result,
const Twine &message);
276 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
277 const Twine &message);
278 ParseResult parseEnumType(
FIRRTLType &result);
279 ParseResult parseListType(
FIRRTLType &result);
282 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
284 ParseResult parseRUW(RUWAttr &result);
285 ParseResult parseOptionalRUW(RUWAttr &result);
287 ParseResult parseParameter(StringAttr &resultName, TypedAttr &resultValue,
294 FIRParser(
const FIRParser &) =
delete;
295 void operator=(
const FIRParser &) =
delete;
299 SharedParserConstants &constants;
303 StringAttr locatorFilenameCache;
305 FileLineColLoc fileLineColLocCache;
314 InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
315 auto diag = mlir::emitError(translateLocation(loc), message);
319 if (getToken().is(FIRToken::error))
324 InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
325 return mlir::emitWarning(translateLocation(loc), message);
335 const Twine &message) {
336 if (consumeIf(expectedToken))
338 return emitError(message);
345 const std::function<ParseResult()> &parseElement) {
346 if (consumeIf(rightToken))
352 while (consumeIf(FIRToken::comma)) {
357 if (parseToken(rightToken,
"expected ','"))
374 : parser(parser), firLoc(firLoc) {}
381 auto result = parser->translateLocation(firLoc);
389 if (failed(parser->parseOptionalInfoLocator(loc)))
393 switch (parser->constants.options.infoLocatorHandling) {
394 case ILH::IgnoreInfo:
395 assert(0 &&
"Should not return info locations if ignoring");
397 case ILH::PreferInfo:
402 {loc, parser->translateLocation(firLoc)});
429 ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
430 if (getToken().isNot(FIRToken::fileinfo))
433 auto loc = getToken().getLoc();
435 auto spelling = getTokenSpelling();
436 consumeToken(FIRToken::fileinfo);
440 constants.options.infoLocatorHandling ==
442 locatorFilenameCache, fileLineColLocCache, getContext());
445 if (!locationPair.first) {
446 mlir::emitWarning(translateLocation(loc),
447 "ignoring unknown @ info record format");
453 if (locationPair.first && constants.options.infoLocatorHandling ==
458 result = *locationPair.second;
466 ParseResult FIRParser::parseOptionalName(StringAttr &name) {
468 if (getToken().isNot(FIRToken::colon)) {
473 consumeToken(FIRToken::colon);
475 if (parseId(nameRef,
"expected result name"))
489 ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
491 if (getToken().isNot(FIRToken::inlineannotation))
494 loc = getToken().getLoc();
496 result = getTokenSpelling().drop_front(2).drop_back(1);
497 consumeToken(FIRToken::inlineannotation);
515 ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
516 auto spelling = getTokenSpelling();
517 bool isNegative =
false;
518 switch (getToken().getKind()) {
519 case FIRToken::signed_integer:
520 isNegative = spelling[0] ==
'-';
521 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
522 spelling = spelling.drop_front();
524 case FIRToken::integer:
525 if (spelling.getAsInteger(10, result))
526 return emitError(message), failure();
530 if (result.isNegative())
531 result = result.zext(result.getBitWidth() + 1);
540 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
541 result = result.trunc(32);
545 case FIRToken::radix_specified_integer: {
546 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
548 if (spelling[0] ==
'-') {
550 spelling = spelling.drop_front();
552 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
557 spelling = spelling.drop_front(2);
558 if (spelling.getAsInteger(base, result))
559 return emitError(
"invalid character in integer literal"), failure();
560 if (result.isNegative())
561 result = result.zext(result.getBitWidth() + 1);
567 case FIRToken::string: {
570 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
573 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
574 spelling = spelling.drop_back().drop_front();
578 switch (spelling.empty() ?
' ' : spelling.front()) {
589 return emitError(
"expected base specifier (h/o/b) in integer literal"),
592 spelling = spelling.drop_front();
595 bool isNegative =
false;
596 if (!spelling.empty() && spelling.front() ==
'+')
597 spelling = spelling.drop_front();
598 else if (!spelling.empty() && spelling.front() ==
'-') {
600 spelling = spelling.drop_front();
604 if (spelling.empty())
605 return emitError(
"expected digits in integer literal"), failure();
607 if (spelling.getAsInteger(base, result))
608 return emitError(
"invalid character in integer literal"), failure();
613 if (result.isNegative())
614 result = result.zext(result.getBitWidth() + 1);
619 consumeToken(FIRToken::string);
624 return emitError(
"expected integer literal"), failure();
628 ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
630 auto loc = getToken().getLoc();
631 if (parseIntLit(value, message))
634 result = (int64_t)value.getLimitedValue(INT64_MAX);
636 return emitError(loc,
"value is too big to handle"), failure();
640 ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
642 auto loc = getToken().getLoc();
643 if (parseIntLit(value, message))
646 result = (int32_t)value.getLimitedValue(INT32_MAX);
648 return emitError(loc,
"value is too big to handle"), failure();
654 ParseResult FIRParser::parseVersionLit(
const Twine &message) {
655 auto spelling = getTokenSpelling();
656 if (getToken().getKind() != FIRToken::version)
657 return emitError(message), failure();
659 auto [a, d] = spelling.split(
".");
660 auto [b, c] = d.split(
".");
661 APInt aInt, bInt, cInt;
662 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
663 c.getAsInteger(10, cInt))
664 return emitError(
"failed to parse version string"), failure();
665 version.major = aInt.getLimitedValue(UINT32_MAX);
666 version.minor = bInt.getLimitedValue(UINT32_MAX);
667 version.patch = cInt.getLimitedValue(UINT32_MAX);
668 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
669 return emitError(
"integers out of range"), failure();
673 consumeToken(FIRToken::version);
680 template <
typename T>
681 ParseResult FIRParser::parseOptionalWidth(T &result) {
682 if (!consumeIf(FIRToken::less))
683 return result = -1, success();
686 auto widthLoc = getToken().getLoc();
687 if (parseIntLit(result,
"expected width") ||
688 parseToken(FIRToken::greater,
"expected >"))
692 return emitError(widthLoc,
"invalid width specifier"), failure();
701 ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
702 switch (getToken().getKind()) {
704 case FIRToken::identifier:
705 case FIRToken::literal_identifier:
707 #define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
708 #include "FIRTokenKinds.def"
713 if (getToken().getKind() == FIRToken::literal_identifier)
714 result = getTokenSpelling().drop_front().drop_back();
716 result = getTokenSpelling();
726 ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
728 if (parseId(name, message))
740 ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
742 result = getTokenSpelling();
743 if (consumeIf(FIRToken::integer))
749 if (parseId(result, message))
761 ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
762 const Twine &message) {
764 StringRef tmp = getTokenSpelling();
766 if (consumeIf(FIRToken::integer)) {
767 result.push_back(tmp);
771 if (consumeIf(FIRToken::floatingpoint)) {
775 auto [a, b] = tmp.split(
".");
781 if (consumeIf(FIRToken::version)) {
783 auto [a, d] = tmp.split(
".");
784 auto [b, c] = d.split(
".");
792 if (parseId(tmp, message))
794 result.push_back(tmp);
800 ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
801 if (parseToken(FIRToken::l_brace_bar,
802 "expected leading '{|' in enumeration type"))
804 SmallVector<FEnumType::EnumElement> elements;
805 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
806 auto fieldLoc = getToken().getLoc();
810 if (parseId(name,
"expected valid identifier for enumeration tag"))
815 if (consumeIf(FIRToken::colon)) {
817 if (
parseType(parsedType,
"expected enumeration type"))
819 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
821 return emitError(fieldLoc,
"field must be a base type");
834 ParseResult FIRParser::parsePropertyType(
PropertyType &result,
835 const Twine &message) {
839 auto prop = type_dyn_cast<PropertyType>(type);
841 return emitError(
"expected property type");
847 ParseResult FIRParser::parseListType(
FIRRTLType &result) {
848 consumeToken(FIRToken::kw_List);
851 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
852 parsePropertyType(
elementType,
"expected List element type") ||
853 parseToken(FIRToken::greater,
"expected '>' in List type"))
879 switch (getToken().getKind()) {
881 return emitError(message), failure();
883 case FIRToken::kw_Clock:
884 consumeToken(FIRToken::kw_Clock);
888 case FIRToken::kw_Inst: {
892 consumeToken(FIRToken::kw_Inst);
893 if (parseToken(FIRToken::less,
"expected < in Inst type"))
896 auto loc = getToken().getLoc();
898 if (parseId(
id,
"expected class name in Inst type"))
902 const auto &classMap = getConstants().classMap;
903 auto lookup = classMap.find(
id);
904 if (lookup == classMap.end())
905 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
907 auto classOp = lookup->second;
909 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
912 result = classOp.getInstanceType();
916 case FIRToken::kw_AnyRef: {
920 consumeToken(FIRToken::kw_AnyRef);
925 case FIRToken::kw_Reset:
926 consumeToken(FIRToken::kw_Reset);
930 case FIRToken::kw_AsyncReset:
931 consumeToken(FIRToken::kw_AsyncReset);
935 case FIRToken::kw_UInt:
936 case FIRToken::kw_SInt:
937 case FIRToken::kw_Analog: {
938 auto kind = getToken().getKind();
943 if (parseOptionalWidth(
width))
946 if (kind == FIRToken::kw_SInt)
948 else if (kind == FIRToken::kw_UInt)
951 assert(kind == FIRToken::kw_Analog);
957 case FIRToken::kw_Probe:
958 case FIRToken::kw_RWProbe: {
959 auto kind = getToken().getKind();
960 auto loc = getToken().getLoc();
965 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
966 parseType(type,
"expected probe data type"))
969 SmallVector<StringRef> layers;
970 if (consumeIf(FIRToken::comma)) {
971 if (requireFeature({3, 2, 0},
"colored probes"))
976 loc = getToken().getLoc();
977 if (parseId(layer,
"expected layer name"))
979 layers.push_back(layer);
980 }
while (consumeIf(FIRToken::period));
983 if (!consumeIf(FIRToken::greater))
984 return emitError(loc,
"expected '>' to end reference type");
986 bool forceable = kind == FIRToken::kw_RWProbe;
988 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
990 return emitError(loc,
"invalid probe inner type, must be base-type");
993 return emitError(loc,
"probe inner type must be passive");
995 if (forceable &&
innerType.containsConst())
996 return emitError(loc,
"rwprobe cannot contain const");
999 if (!layers.empty()) {
1001 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1005 llvm::to_vector(nestedLayers));
1012 case FIRToken::l_brace: {
1013 consumeToken(FIRToken::l_brace);
1015 SmallVector<OpenBundleType::BundleElement, 4> elements;
1016 bool bundleCompatible =
true;
1017 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1018 bool isFlipped = consumeIf(FIRToken::kw_flip);
1020 StringRef fieldName;
1022 if (parseFieldId(fieldName,
"expected bundle field name") ||
1023 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1025 if (
parseType(type,
"expected bundle field type"))
1030 bundleCompatible &= isa<BundleType::ElementType>(type);
1037 if (bundleCompatible) {
1038 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1039 return BundleType::BundleElement{
1040 element.name, element.isFlip,
1041 cast<BundleType::ElementType>(element.type)};
1043 result =
BundleType::get(getContext(), llvm::to_vector(bundleElements));
1049 case FIRToken::l_brace_bar: {
1050 if (parseEnumType(result))
1055 case FIRToken::identifier: {
1057 auto loc = getToken().getLoc();
1058 if (parseId(
id,
"expected a type alias name"))
1060 auto it = constants.aliasMap.find(
id);
1061 if (it == constants.aliasMap.end()) {
1062 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1065 result = it->second;
1069 case FIRToken::kw_const: {
1070 consumeToken(FIRToken::kw_const);
1071 auto nextToken = getToken();
1072 auto loc = nextToken.getLoc();
1075 if (nextToken.is(FIRToken::kw_const))
1076 return emitError(loc,
"'const' can only be specified once on a type");
1081 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1083 return emitError(loc,
"only hardware types can be 'const'");
1085 result = baseType.getConstType(
true);
1089 case FIRToken::kw_String:
1090 if (requireFeature({3, 1, 0},
"Strings"))
1092 consumeToken(FIRToken::kw_String);
1095 case FIRToken::kw_Integer:
1096 if (requireFeature({3, 1, 0},
"Integers"))
1098 consumeToken(FIRToken::kw_Integer);
1101 case FIRToken::kw_Bool:
1104 consumeToken(FIRToken::kw_Bool);
1107 case FIRToken::kw_Double:
1110 consumeToken(FIRToken::kw_Double);
1113 case FIRToken::kw_Path:
1116 consumeToken(FIRToken::kw_Path);
1119 case FIRToken::kw_List:
1120 if (requireFeature(
nextFIRVersion,
"Lists") || parseListType(result))
1126 while (consumeIf(FIRToken::l_square)) {
1127 auto sizeLoc = getToken().getLoc();
1129 if (parseIntLit(size,
"expected width") ||
1130 parseToken(FIRToken::r_square,
"expected ]"))
1134 return emitError(sizeLoc,
"invalid size specifier"), failure();
1136 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1147 ParseResult FIRParser::parseRUW(RUWAttr &result) {
1148 switch (getToken().getKind()) {
1150 case FIRToken::kw_old:
1151 result = RUWAttr::Old;
1152 consumeToken(FIRToken::kw_old);
1154 case FIRToken::kw_new:
1155 result = RUWAttr::New;
1156 consumeToken(FIRToken::kw_new);
1158 case FIRToken::kw_undefined:
1159 result = RUWAttr::Undefined;
1160 consumeToken(FIRToken::kw_undefined);
1170 ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1171 switch (getToken().getKind()) {
1175 case FIRToken::kw_old:
1176 result = RUWAttr::Old;
1177 consumeToken(FIRToken::kw_old);
1179 case FIRToken::kw_new:
1180 result = RUWAttr::New;
1181 consumeToken(FIRToken::kw_new);
1183 case FIRToken::kw_undefined:
1184 result = RUWAttr::Undefined;
1185 consumeToken(FIRToken::kw_undefined);
1196 ParseResult FIRParser::parseParameter(StringAttr &resultName,
1197 TypedAttr &resultValue,
1199 mlir::Builder builder(getContext());
1201 auto loc = getToken().getLoc();
1204 if (parseId(name,
"expected parameter name") ||
1205 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1209 switch (getToken().getKind()) {
1211 return emitError(
"expected parameter value"), failure();
1212 case FIRToken::integer:
1213 case FIRToken::signed_integer: {
1215 if (parseIntLit(result,
"invalid integer parameter"))
1221 if (result.getBitWidth() < 32)
1222 result = result.sext(32);
1224 value = builder.getIntegerAttr(
1225 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1229 case FIRToken::string: {
1231 value = builder.getStringAttr(getToken().getStringValue());
1232 consumeToken(FIRToken::string);
1235 case FIRToken::verbatim_string: {
1237 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1239 consumeToken(FIRToken::verbatim_string);
1242 case FIRToken::floatingpoint:
1244 if (!llvm::to_float(getTokenSpelling(), v))
1245 return emitError(
"invalid float parameter syntax"), failure();
1247 value = builder.getF64FloatAttr(v);
1248 consumeToken(FIRToken::floatingpoint);
1252 resultName = builder.getStringAttr(name);
1253 resultValue = value;
1269 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1277 struct UnbundledValueRestorer {
1279 size_t startingSize;
1281 startingSize = list.size();
1283 ~UnbundledValueRestorer() { list.resize(startingSize); }
1292 struct FIRModuleContext :
public FIRParser {
1293 explicit FIRModuleContext(SharedParserConstants &constants,
FIRLexer &lexer,
1295 : FIRParser(constants, lexer, version) {}
1301 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1304 Value getCachedConstantInt(ImplicitLocOpBuilder &builder, Attribute attr,
1306 auto &result = constantCache[{attr, type}];
1312 OpBuilder::InsertPoint savedIP;
1314 auto *parentOp = builder.getInsertionBlock()->getParentOp();
1315 if (!isa<FModuleOp>(parentOp)) {
1316 savedIP = builder.saveInsertionPoint();
1317 while (!isa<FModuleOp>(parentOp)) {
1318 builder.setInsertionPoint(parentOp);
1319 parentOp = builder.getInsertionBlock()->getParentOp();
1323 result = builder.create<ConstantOp>(type, value);
1325 if (savedIP.isSet())
1326 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1337 Value &getCachedSubaccess(Value value,
unsigned index) {
1338 auto &result = subaccessCache[{value, index}];
1341 auto it = scopeMap.find(value.getParentBlock());
1342 if (it != scopeMap.end())
1343 it->second->scopedSubaccesses.push_back({result, index});
1353 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1354 bool insertNameIntoGlobalScope =
false);
1355 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1356 bool insertNameIntoGlobalScope =
false) {
1358 insertNameIntoGlobalScope);
1363 SMLoc loc,
bool fatal =
true);
1368 StringRef field, SMLoc loc);
1376 assert(index < unbundledValues.size());
1377 return unbundledValues[index];
1387 struct ContextScope {
1388 friend struct FIRModuleContext;
1389 ContextScope(FIRModuleContext &moduleContext, Block *block)
1390 : moduleContext(moduleContext), block(block),
1391 previousScope(moduleContext.currentScope) {
1392 moduleContext.currentScope =
this;
1393 moduleContext.scopeMap[block] =
this;
1398 for (
auto *entryPtr : scopedDecls)
1399 entryPtr->second.first = SMLoc();
1402 for (
auto subaccess : scopedSubaccesses)
1403 moduleContext.subaccessCache.erase(subaccess);
1405 moduleContext.scopeMap.erase(block);
1407 moduleContext.currentScope = previousScope;
1411 void operator=(
const ContextScope &) =
delete;
1412 ContextScope(
const ContextScope &) =
delete;
1414 FIRModuleContext &moduleContext;
1416 ContextScope *previousScope;
1417 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1418 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1432 DenseMap<Block *, ContextScope *> scopeMap;
1437 ContextScope *currentScope =
nullptr;
1448 ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1450 bool insertNameIntoGlobalScope) {
1455 if (entryIt->second.first.isValid()) {
1456 emitError(loc,
"redefinition of name '" + name +
"'")
1457 .attachNote(translateLocation(entryIt->second.first))
1458 <<
"previous definition here";
1464 entryIt->second = {loc, entry};
1465 if (currentScope && !insertNameIntoGlobalScope)
1466 currentScope->scopedDecls.push_back(&*entryIt);
1474 StringRef name, SMLoc loc) {
1475 auto &entry = symbolTable[name];
1476 if (!entry.first.isValid())
1477 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1478 result = entry.second;
1479 assert(result &&
"name in symbol table without definition");
1483 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1485 SMLoc loc,
bool fatal) {
1486 if (!entry.is<Value>()) {
1488 emitError(loc,
"bundle value should only be used from subfield");
1491 result = entry.get<Value>();
1495 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1497 StringRef fieldName,
1500 emitError(loc,
"value should not be used from subfield");
1506 unsigned unbundledId = entry.get<
UnbundledID>() - 1;
1507 assert(unbundledId < unbundledValues.size());
1509 for (
auto elt : ubEntry) {
1510 if (elt.first == fieldAttr) {
1511 result = elt.second;
1516 emitError(loc,
"use of invalid field name '")
1517 << fieldName <<
"' on bundle value";
1543 struct LazyLocationListener :
public OpBuilder::Listener {
1544 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1545 assert(builder.getListener() ==
nullptr);
1546 builder.setListener(
this);
1549 ~LazyLocationListener() {
1550 assert(subOps.empty() &&
"didn't process parsed operations");
1551 assert(builder.getListener() ==
this);
1552 builder.setListener(
nullptr);
1555 void startStatement() {
1556 assert(!isActive &&
"Already processing a statement");
1562 void endStatement(FIRParser &parser) {
1563 assert(isActive &&
"Not parsing a statement");
1567 for (
auto opAndSMLoc : subOps) {
1571 switch (parser.getConstants().options.infoLocatorHandling) {
1572 case ILH::IgnoreInfo:
1574 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1576 case ILH::PreferInfo:
1577 opAndSMLoc.first->setLoc(infoLoc);
1579 case ILH::FusedInfo:
1581 infoLoc.getContext(),
1582 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1589 for (
auto opAndSMLoc : subOps)
1590 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1595 infoLoc = LocationAttr();
1596 currentSMLoc = SMLoc();
1601 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1604 void setInfoLoc(LocationAttr loc) {
1605 assert(!infoLoc &&
"Info location multiply specified");
1611 void notifyOperationInserted(Operation *op,
1612 mlir::IRRewriter::InsertPoint)
override {
1613 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1614 assert(isActive &&
"Not parsing a statement");
1615 subOps.push_back({op, currentSMLoc});
1620 bool isActive =
false;
1628 LocationAttr infoLoc;
1635 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1637 void operator=(
const LazyLocationListener &) =
delete;
1638 LazyLocationListener(
const LazyLocationListener &) =
delete;
1645 struct FIRStmtParser :
public FIRParser {
1646 explicit FIRStmtParser(Block &blockToInsertInto,
1647 FIRModuleContext &moduleContext,
1648 hw::InnerSymbolNamespace &modNameSpace,
1649 const SymbolTable &circuitSymTbl,
FIRVersion version,
1650 SymbolRefAttr layerSym = {})
1651 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1654 locationProcessor(this->builder), moduleContext(moduleContext),
1655 modNameSpace(modNameSpace), layerSym(layerSym),
1656 circuitSymTbl(circuitSymTbl) {
1657 builder.setInsertionPointToEnd(&blockToInsertInto);
1660 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1661 ParseResult parseSimpleStmtBlock(
unsigned indent);
1664 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1667 void emitInvalidate(Value val,
Flow flow);
1673 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1676 ParseResult parseOptionalInfo() {
1678 if (failed(parseOptionalInfoLocator(loc)))
1680 locationProcessor.setInfoLoc(loc);
1685 ParseResult parseExpImpl(Value &result,
const Twine &message,
1686 bool isLeadingStmt);
1687 ParseResult parseExp(Value &result,
const Twine &message) {
1688 return parseExpImpl(result, message,
false);
1690 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1691 return parseExpImpl(result, message,
true);
1693 ParseResult parseEnumExp(Value &result);
1694 ParseResult parsePathExp(Value &result);
1695 ParseResult parseRefExp(Value &result,
const Twine &message);
1696 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1697 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1698 const Twine &message);
1701 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1702 ParseResult parseIntrinsicStmt() {
1704 return parseIntrinsic(unused,
true);
1706 ParseResult parseIntrinsicExp(Value &result) {
1707 return parseIntrinsic(result,
false);
1709 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1711 template <
typename subop>
1712 FailureOr<Value> emitCachedSubAccess(Value base,
1713 ArrayRef<NamedAttribute> attrs,
1714 unsigned indexNo, SMLoc loc);
1715 ParseResult parseOptionalExpPostscript(Value &result,
1716 bool allowDynamic =
true);
1717 ParseResult parsePostFixFieldId(Value &result);
1718 ParseResult parsePostFixIntSubscript(Value &result);
1719 ParseResult parsePostFixDynamicSubscript(Value &result);
1720 ParseResult parsePrimExp(Value &result);
1721 ParseResult parseIntegerLiteralExp(Value &result);
1722 ParseResult parseListExp(Value &result);
1724 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
1727 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
1728 SymbolRefAttr layerSym);
1729 ParseResult parseAttach();
1730 ParseResult parseMemPort(MemDirAttr direction);
1731 ParseResult parsePrintf();
1732 ParseResult parseSkip();
1733 ParseResult parseStop();
1734 ParseResult parseAssert();
1735 ParseResult parseAssume();
1736 ParseResult parseCover();
1737 ParseResult parseWhen(
unsigned whenIndent);
1738 ParseResult parseMatch(
unsigned matchIndent);
1739 ParseResult parseRefDefine();
1740 ParseResult parseRefForce();
1741 ParseResult parseRefForceInitial();
1742 ParseResult parseRefRelease();
1743 ParseResult parseRefReleaseInitial();
1744 ParseResult parseRefRead(Value &result);
1745 ParseResult parseProbe(Value &result);
1746 ParseResult parsePropAssign();
1747 ParseResult parseRWProbe(Value &result);
1748 ParseResult parseLeadingExpStmt(Value lhs);
1749 ParseResult parseConnect();
1750 ParseResult parseInvalidate();
1751 ParseResult parseLayerBlockOrGroup(
unsigned indent);
1754 ParseResult parseInstance();
1755 ParseResult parseInstanceChoice();
1756 ParseResult parseObject();
1757 ParseResult parseCombMem();
1758 ParseResult parseSeqMem();
1759 ParseResult parseMem(
unsigned memIndent);
1760 ParseResult parseNode();
1761 ParseResult parseWire();
1762 ParseResult parseRegister(
unsigned regIndent);
1763 ParseResult parseRegisterWithReset();
1766 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
1769 ImplicitLocOpBuilder builder;
1770 LazyLocationListener locationProcessor;
1773 FIRModuleContext &moduleContext;
1775 hw::InnerSymbolNamespace &modNameSpace;
1779 SymbolRefAttr layerSym;
1781 const SymbolTable &circuitSymTbl;
1788 void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
1789 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
1796 auto props = tpe.getRecursiveTypeProperties();
1797 if (props.isPassive && !props.containsAnalog) {
1800 emitConnect(builder, val, builder.create<InvalidValueOp>(tpe));
1811 TypeSwitch<FIRRTLType>(tpe)
1812 .Case<BundleType>([&](
auto tpe) {
1813 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
1814 auto &subfield = moduleContext.getCachedSubaccess(val, i);
1816 OpBuilder::InsertionGuard guard(builder);
1817 builder.setInsertionPointAfterValue(val);
1818 subfield = builder.create<SubfieldOp>(val, i);
1820 emitInvalidate(subfield,
1821 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
1824 .Case<FVectorType>([&](
auto tpe) {
1825 auto tpex = tpe.getElementType();
1826 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
1827 auto &subindex = moduleContext.getCachedSubaccess(val, i);
1829 OpBuilder::InsertionGuard guard(builder);
1830 builder.setInsertionPointAfterValue(val);
1831 subindex = builder.create<SubindexOp>(tpex, val, i);
1833 emitInvalidate(subindex, flow);
1861 ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
1862 bool isLeadingStmt) {
1863 switch (getToken().getKind()) {
1866 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
1867 case FIRToken::lp_##SPELLING:
1868 #include "FIRTokenKinds.def"
1869 if (parsePrimExp(result))
1873 case FIRToken::l_brace_bar:
1875 return emitError(
"unexpected enumeration as start of statement");
1876 if (parseEnumExp(result))
1879 case FIRToken::lp_read:
1881 return emitError(
"unexpected read() as start of statement");
1882 if (parseRefRead(result))
1885 case FIRToken::lp_probe:
1887 return emitError(
"unexpected probe() as start of statement");
1888 if (parseProbe(result))
1891 case FIRToken::lp_rwprobe:
1893 return emitError(
"unexpected rwprobe() as start of statement");
1894 if (parseRWProbe(result))
1898 case FIRToken::kw_UInt:
1899 case FIRToken::kw_SInt:
1900 if (parseIntegerLiteralExp(result))
1903 case FIRToken::kw_String: {
1904 if (requireFeature({3, 1, 0},
"Strings"))
1906 locationProcessor.setLoc(getToken().getLoc());
1907 consumeToken(FIRToken::kw_String);
1909 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
1910 parseGetSpelling(spelling) ||
1911 parseToken(FIRToken::string,
1912 "expected string literal in String expression") ||
1913 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
1915 result = builder.create<StringConstantOp>(
1919 case FIRToken::kw_Integer: {
1920 if (requireFeature({3, 1, 0},
"Integers"))
1922 locationProcessor.setLoc(getToken().getLoc());
1923 consumeToken(FIRToken::kw_Integer);
1925 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
1926 parseIntLit(value,
"expected integer literal in Integer expression") ||
1927 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
1930 builder.create<FIntegerConstantOp>(APSInt(value,
false));
1933 case FIRToken::kw_Bool: {
1936 locationProcessor.setLoc(getToken().getLoc());
1937 consumeToken(FIRToken::kw_Bool);
1938 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
1941 if (consumeIf(FIRToken::kw_true))
1943 else if (consumeIf(FIRToken::kw_false))
1946 return emitError(
"expected true or false in Bool expression");
1947 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
1949 result = builder.create<BoolConstantOp>(value);
1952 case FIRToken::kw_Double: {
1955 locationProcessor.setLoc(getToken().getLoc());
1956 consumeToken(FIRToken::kw_Double);
1957 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
1959 auto spelling = getTokenSpelling();
1960 if (parseToken(FIRToken::floatingpoint,
1961 "expected floating point in Double expression") ||
1962 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
1967 if (!llvm::to_float(spelling, d))
1968 return emitError(
"invalid double");
1969 result = builder.create<DoubleConstantOp>(builder.getF64FloatAttr(d));
1972 case FIRToken::kw_List: {
1976 return emitError(
"unexpected List<>() as start of statement");
1977 if (parseListExp(result))
1981 case FIRToken::lp_path:
1983 return emitError(
"unexpected path() as start of statement");
1984 if (requireFeature(
nextFIRVersion,
"paths") || parsePathExp(result))
1988 case FIRToken::lp_intrinsic:
1989 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
1990 parseIntrinsicExp(result))
1996 case FIRToken::identifier:
1997 case FIRToken::literal_identifier:
2000 auto loc = getToken().getLoc();
2002 if (parseId(name, message) ||
2003 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2007 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2015 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2016 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2017 parseOptionalInfo())
2020 locationProcessor.setLoc(loc);
2022 unsigned unbundledId = symtabEntry.get<
UnbundledID>() - 1;
2024 moduleContext.getUnbundledEntry(unbundledId);
2025 for (
auto elt : ubEntry)
2026 emitInvalidate(elt.second);
2034 StringRef fieldName;
2035 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2036 parseFieldId(fieldName,
"expected field name") ||
2037 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2043 return parseOptionalExpPostscript(result);
2053 ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2054 bool allowDynamic) {
2059 if (consumeIf(FIRToken::period)) {
2060 if (parsePostFixFieldId(result))
2067 if (consumeIf(FIRToken::l_square)) {
2068 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2069 if (parsePostFixIntSubscript(result))
2074 return emitError(
"subaccess not allowed here");
2075 if (parsePostFixDynamicSubscript(result))
2085 template <
typename subop>
2087 FIRStmtParser::emitCachedSubAccess(Value base, ArrayRef<NamedAttribute> attrs,
2088 unsigned indexNo, SMLoc loc) {
2091 auto resultType = subop::inferReturnType({base}, attrs, {});
2094 (void)subop::inferReturnType({base}, attrs, translateLocation(loc));
2099 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2105 locationProcessor.setLoc(loc);
2106 OpBuilder::InsertionGuard guard(builder);
2107 builder.setInsertionPointAfterValue(base);
2108 auto op = builder.create<subop>(resultType, base, attrs);
2111 return value = op.getResult();
2118 ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2119 auto loc = getToken().getLoc();
2120 SmallVector<StringRef, 3> fields;
2121 if (parseFieldIdSeq(fields,
"expected field name"))
2123 for (
auto fieldName : fields) {
2124 std::optional<unsigned> indexV;
2125 auto type = result.getType();
2126 if (
auto refTy = type_dyn_cast<RefType>(type))
2127 type = refTy.getType();
2128 if (
auto bundle = type_dyn_cast<BundleType>(type))
2129 indexV = bundle.getElementIndex(fieldName);
2130 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2131 indexV = bundle.getElementIndex(fieldName);
2132 else if (
auto klass = type_dyn_cast<ClassType>(type))
2133 indexV = klass.getElementIndex(fieldName);
2135 return emitError(loc,
"subfield requires bundle or object operand ");
2137 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2138 << result.getType();
2139 auto indexNo = *indexV;
2141 FailureOr<Value> subResult;
2142 if (type_isa<RefType>(result.getType())) {
2143 NamedAttribute attrs = {getConstants().indexIdentifier,
2144 builder.getI32IntegerAttr(indexNo)};
2145 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2146 }
else if (type_isa<ClassType>(type)) {
2147 NamedAttribute attrs = {getConstants().indexIdentifier,
2148 builder.getI32IntegerAttr(indexNo)};
2150 emitCachedSubAccess<ObjectSubfieldOp>(result, attrs, indexNo, loc);
2152 NamedAttribute attrs = {getConstants().fieldIndexIdentifier,
2153 builder.getI32IntegerAttr(indexNo)};
2154 if (type_isa<BundleType>(type))
2156 emitCachedSubAccess<SubfieldOp>(result, attrs, indexNo, loc);
2159 emitCachedSubAccess<OpenSubfieldOp>(result, attrs, indexNo, loc);
2162 if (failed(subResult))
2164 result = *subResult;
2173 ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2174 auto loc = getToken().getLoc();
2176 if (parseIntLit(indexNo,
"expected index") ||
2177 parseToken(FIRToken::r_square,
"expected ']'"))
2181 return emitError(loc,
"invalid index specifier"), failure();
2187 NamedAttribute attrs = {getConstants().indexIdentifier,
2188 builder.getI32IntegerAttr(indexNo)};
2190 FailureOr<Value> subResult;
2191 if (type_isa<RefType>(result.getType()))
2192 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2193 else if (type_isa<FVectorType>(result.getType()))
2194 subResult = emitCachedSubAccess<SubindexOp>(result, attrs, indexNo, loc);
2197 emitCachedSubAccess<OpenSubindexOp>(result, attrs, indexNo, loc);
2199 if (failed(subResult))
2201 result = *subResult;
2209 ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2210 auto loc = getToken().getLoc();
2212 if (parseExp(index,
"expected subscript index expression") ||
2213 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2217 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2219 return emitError(
"expected base type for index expression");
2220 indexType = indexType.getPassiveType();
2221 locationProcessor.setLoc(loc);
2225 auto resultType = SubaccessOp::inferReturnType({result, index}, {}, {});
2228 (void)SubaccessOp::inferReturnType({result, index}, {},
2229 translateLocation(loc));
2234 auto op = builder.create<SubaccessOp>(resultType, result, index);
2235 result = op.getResult();
2240 ParseResult FIRStmtParser::parsePrimExp(Value &result) {
2241 auto kind = getToken().getKind();
2242 auto loc = getToken().getLoc();
2246 SmallVector<Value, 3> operands;
2247 SmallVector<int64_t, 3> integers;
2249 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2251 if (getToken().isAny(FIRToken::integer, FIRToken::signed_integer,
2252 FIRToken::string)) {
2253 integers.push_back(0);
2254 return parseIntLit(integers.back(),
"expected integer");
2259 if (!integers.empty())
2260 return emitError(
"expected more integer constants"), failure();
2263 if (parseExp(operand,
"expected expression in primitive operand"))
2266 locationProcessor.setLoc(loc);
2268 operands.push_back(operand);
2274 locationProcessor.setLoc(loc);
2276 SmallVector<FIRRTLType, 3> opTypes;
2277 for (
auto v : operands)
2278 opTypes.push_back(type_cast<FIRRTLType>(v.getType()));
2280 unsigned numOperandsExpected;
2281 SmallVector<StringAttr, 2> attrNames;
2286 emitError(loc,
"primitive not supported yet");
2288 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2289 case FIRToken::lp_##SPELLING: \
2290 numOperandsExpected = NUMOPERANDS; \
2292 #include "FIRTokenKinds.def"
2299 case FIRToken::lp_bits:
2300 attrNames.push_back(getConstants().hiIdentifier);
2301 attrNames.push_back(getConstants().loIdentifier);
2303 case FIRToken::lp_head:
2304 case FIRToken::lp_pad:
2305 case FIRToken::lp_shl:
2306 case FIRToken::lp_shr:
2307 case FIRToken::lp_tail:
2308 attrNames.push_back(getConstants().amountIdentifier);
2310 case FIRToken::lp_integer_add:
2311 case FIRToken::lp_integer_mul:
2312 case FIRToken::lp_integer_shr:
2313 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions", loc))
2318 if (operands.size() != numOperandsExpected) {
2319 assert(numOperandsExpected <= 3);
2320 static const char *numberName[] = {
"zero",
"one",
"two",
"three"};
2321 const char *optionalS = &
"s"[numOperandsExpected == 1];
2322 return emitError(loc,
"operation requires ")
2323 << numberName[numOperandsExpected] <<
" operand" << optionalS;
2326 if (integers.size() != attrNames.size()) {
2327 emitError(loc,
"expected ") << attrNames.size() <<
" constant arguments";
2331 NamedAttrList attrs;
2332 for (
size_t i = 0, e = attrNames.size(); i != e; ++i)
2333 attrs.append(attrNames[i], builder.getI32IntegerAttr(integers[i]));
2337 emitError(loc,
"primitive not supported yet");
2340 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2341 case FIRToken::lp_##SPELLING: { \
2342 auto resultTy = CLASS::inferReturnType(operands, attrs, {}); \
2345 (void)CLASS::validateAndInferReturnType(operands, attrs, \
2346 translateLocation(loc)); \
2349 result = builder.create<CLASS>(resultTy, operands, attrs); \
2352 #include "FIRTokenKinds.def"
2359 case FIRToken::lp_shr:
2362 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2363 result = builder.create<PadPrimOp>(result, 1);
2371 ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2372 bool isSigned = getToken().is(FIRToken::kw_SInt);
2373 auto loc = getToken().getLoc();
2379 if (parseOptionalWidth(
width) ||
2380 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2381 parseIntLit(value,
"expected integer value") ||
2382 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2389 IntegerType::SignednessSemantics signedness =
2390 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2392 if (!value.isZero())
2393 return emitError(loc,
"zero bit constant must be zero");
2394 value = value.trunc(0);
2395 }
else if (
width != -1) {
2397 bool valueFits = isSigned ? value.isSignedIntN(
width) : value.isIntN(
width);
2399 return emitError(loc,
"initializer too wide for declared width");
2400 value = isSigned ? value.sextOrTrunc(
width) : value.zextOrTrunc(
width);
2405 auto attr = builder.getIntegerAttr(attrType, value);
2408 auto &entry = moduleContext.constantCache[{attr, type}];
2415 locationProcessor.setLoc(loc);
2416 result = moduleContext.getCachedConstantInt(builder, attr, type, value);
2421 ParseResult FIRStmtParser::parseListExp(Value &result) {
2422 auto loc = getToken().getLoc();
2424 if (parseListType(type))
2426 auto listType = type_cast<ListType>(type);
2429 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2432 SmallVector<Value, 3> operands;
2433 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2435 locationProcessor.setLoc(loc);
2436 if (parseExp(operand,
"expected expression in List expression"))
2440 if (!isa<AnyRefType>(elementType) ||
2441 !isa<ClassType>(operand.getType()))
2442 return emitError(loc,
"unexpected expression of type ")
2443 << operand.getType() <<
" in List expression of type "
2445 operand = builder.create<ObjectAnyRefCastOp>(operand);
2448 operands.push_back(operand);
2453 locationProcessor.setLoc(loc);
2454 result = builder.create<ListCreateOp>(listType, operands);
2475 std::optional<ParseResult>
2476 FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2477 switch (getToken().getKind()) {
2480 return std::nullopt;
2482 case FIRToken::period:
2483 case FIRToken::l_square:
2484 case FIRToken::kw_is:
2485 case FIRToken::less_equal:
2491 auto loc = keyword.
getLoc();
2493 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2494 return ParseResult(failure());
2500 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2503 if (!consumeIf(FIRToken::period))
2504 return ParseResult(failure());
2506 StringRef fieldName;
2507 if (parseFieldId(fieldName,
"expected field name") ||
2508 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2509 return ParseResult(failure());
2513 if (parseOptionalExpPostscript(lhs))
2514 return ParseResult(failure());
2516 return parseLeadingExpStmt(lhs);
2522 ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2525 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2528 auto subIndent = getIndentation();
2529 if (!subIndent.has_value())
2530 return emitError(
"expected statement to be on its own line"), failure();
2532 if (*subIndent <= indent)
2536 if (parseSimpleStmt(*subIndent))
2541 ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2542 locationProcessor.startStatement();
2543 auto result = parseSimpleStmtImpl(stmtIndent);
2544 locationProcessor.endStatement(*
this);
2565 ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2566 auto kind = getToken().getKind();
2569 case FIRToken::kw_invalidate:
2570 case FIRToken::kw_connect:
2571 case FIRToken::kw_regreset:
2575 kind = FIRToken::identifier;
2582 case FIRToken::kw_attach:
2583 return parseAttach();
2584 case FIRToken::kw_infer:
2585 return parseMemPort(MemDirAttr::Infer);
2586 case FIRToken::kw_read:
2587 return parseMemPort(MemDirAttr::Read);
2588 case FIRToken::kw_write:
2589 return parseMemPort(MemDirAttr::Write);
2590 case FIRToken::kw_rdwr:
2591 return parseMemPort(MemDirAttr::ReadWrite);
2592 case FIRToken::kw_connect:
2593 return parseConnect();
2594 case FIRToken::kw_propassign:
2595 if (requireFeature({3, 1, 0},
"properties"))
2597 return parsePropAssign();
2598 case FIRToken::kw_invalidate:
2599 return parseInvalidate();
2600 case FIRToken::lp_printf:
2601 return parsePrintf();
2602 case FIRToken::kw_skip:
2604 case FIRToken::lp_stop:
2606 case FIRToken::lp_assert:
2607 return parseAssert();
2608 case FIRToken::lp_assume:
2609 return parseAssume();
2610 case FIRToken::lp_cover:
2611 return parseCover();
2612 case FIRToken::kw_when:
2613 return parseWhen(stmtIndent);
2614 case FIRToken::kw_match:
2615 return parseMatch(stmtIndent);
2616 case FIRToken::kw_define:
2617 return parseRefDefine();
2618 case FIRToken::lp_force:
2619 return parseRefForce();
2620 case FIRToken::lp_force_initial:
2621 return parseRefForceInitial();
2622 case FIRToken::lp_release:
2623 return parseRefRelease();
2624 case FIRToken::lp_release_initial:
2625 return parseRefReleaseInitial();
2626 case FIRToken::kw_group:
2627 if (requireFeature({3, 2, 0},
"optional groups") ||
2628 removedFeature({4, 0, 0},
"optional groups"))
2630 return parseLayerBlockOrGroup(stmtIndent);
2631 case FIRToken::kw_layerblock:
2632 if (requireFeature({4, 0, 0},
"layers"))
2634 return parseLayerBlockOrGroup(stmtIndent);
2635 case FIRToken::lp_intrinsic:
2636 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2638 return parseIntrinsicStmt();
2642 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2649 return parseLeadingExpStmt(lhs);
2653 case FIRToken::kw_inst:
2654 return parseInstance();
2655 case FIRToken::kw_instchoice:
2656 return parseInstanceChoice();
2657 case FIRToken::kw_object:
2658 return parseObject();
2659 case FIRToken::kw_cmem:
2660 return parseCombMem();
2661 case FIRToken::kw_smem:
2662 return parseSeqMem();
2663 case FIRToken::kw_mem:
2664 return parseMem(stmtIndent);
2665 case FIRToken::kw_node:
2667 case FIRToken::kw_wire:
2669 case FIRToken::kw_reg:
2670 return parseRegister(stmtIndent);
2671 case FIRToken::kw_regreset:
2672 return parseRegisterWithReset();
2676 ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2678 SymbolRefAttr layerSym) {
2680 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2681 moduleContext, &blockToInsertInto);
2686 UnbundledValueRestorer x(moduleContext.unbundledValues);
2690 auto subParser = std::make_unique<FIRStmtParser>(
2691 blockToInsertInto, moduleContext, modNameSpace, circuitSymTbl, version,
2695 auto stmtIndent = getIndentation();
2698 if (!stmtIndent.has_value())
2699 return subParser->parseSimpleStmt(indent);
2701 if (*stmtIndent <= indent)
2702 return emitError(
"statement must be indented more than previous statement"),
2706 return subParser->parseSimpleStmtBlock(indent);
2710 ParseResult FIRStmtParser::parseAttach() {
2711 auto startTok = consumeToken(FIRToken::kw_attach);
2714 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2717 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
2720 SmallVector<Value, 4> operands;
2721 operands.push_back({});
2722 if (parseExp(operands.back(),
"expected operand in attach"))
2725 while (consumeIf(FIRToken::comma)) {
2726 operands.push_back({});
2727 if (parseExp(operands.back(),
"expected operand in attach"))
2730 if (parseToken(FIRToken::r_paren,
"expected close paren"))
2733 if (parseOptionalInfo())
2736 locationProcessor.setLoc(startTok.getLoc());
2737 builder.create<AttachOp>(operands);
2744 ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2745 auto startTok = consumeToken();
2746 auto startLoc = startTok.getLoc();
2750 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2756 Value memory, indexExp, clock;
2757 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
2758 parseId(
id,
"expected result name") ||
2759 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
2760 parseId(memName,
"expected memory name") ||
2761 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2762 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2763 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
2764 parseExp(indexExp,
"expected index expression") ||
2765 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
2766 parseToken(FIRToken::comma,
"expected ','") ||
2767 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
2770 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2772 return emitError(startLoc,
2773 "memory port should have behavioral memory type");
2774 auto resultType = memVType.getElementType();
2776 ArrayAttr annotations = getConstants().emptyArrayAttr;
2777 locationProcessor.setLoc(startLoc);
2780 Value memoryPort, memoryData;
2782 OpBuilder::InsertionGuard guard(builder);
2783 builder.setInsertionPointAfterValue(memory);
2784 auto memoryPortOp = builder.create<MemoryPortOp>(
2787 memoryData = memoryPortOp.getResult(0);
2788 memoryPort = memoryPortOp.getResult(1);
2792 builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2794 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
2798 ParseResult FIRStmtParser::parsePrintf() {
2799 auto startTok = consumeToken(FIRToken::lp_printf);
2801 Value clock, condition;
2802 StringRef formatString;
2803 if (parseExp(clock,
"expected clock expression in printf") ||
2804 parseToken(FIRToken::comma,
"expected ','") ||
2805 parseExp(condition,
"expected condition in printf") ||
2806 parseToken(FIRToken::comma,
"expected ','") ||
2807 parseGetSpelling(formatString) ||
2808 parseToken(FIRToken::string,
"expected format string in printf"))
2811 SmallVector<Value, 4> operands;
2812 while (consumeIf(FIRToken::comma)) {
2813 operands.push_back({});
2814 if (parseExp(operands.back(),
"expected operand in printf"))
2817 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2821 if (parseOptionalName(name))
2824 if (parseOptionalInfo())
2827 locationProcessor.setLoc(startTok.getLoc());
2830 builder.create<PrintFOp>(clock, condition,
2831 builder.getStringAttr(formatStrUnescaped), operands,
2837 ParseResult FIRStmtParser::parseSkip() {
2838 auto startTok = consumeToken(FIRToken::kw_skip);
2842 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2845 if (parseOptionalInfo())
2848 locationProcessor.setLoc(startTok.getLoc());
2849 builder.create<SkipOp>();
2854 ParseResult FIRStmtParser::parseStop() {
2855 auto startTok = consumeToken(FIRToken::lp_stop);
2857 Value clock, condition;
2860 if (parseExp(clock,
"expected clock expression in 'stop'") ||
2861 parseToken(FIRToken::comma,
"expected ','") ||
2862 parseExp(condition,
"expected condition in 'stop'") ||
2863 parseToken(FIRToken::comma,
"expected ','") ||
2864 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
2865 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
2866 parseOptionalName(name) || parseOptionalInfo())
2869 locationProcessor.setLoc(startTok.getLoc());
2870 builder.create<StopOp>(clock, condition, builder.getI32IntegerAttr(exitCode),
2876 ParseResult FIRStmtParser::parseAssert() {
2877 auto startTok = consumeToken(FIRToken::lp_assert);
2879 Value clock, predicate, enable;
2880 StringRef formatString;
2882 if (parseExp(clock,
"expected clock expression in 'assert'") ||
2883 parseToken(FIRToken::comma,
"expected ','") ||
2884 parseExp(predicate,
"expected predicate in 'assert'") ||
2885 parseToken(FIRToken::comma,
"expected ','") ||
2886 parseExp(enable,
"expected enable in 'assert'") ||
2887 parseToken(FIRToken::comma,
"expected ','") ||
2888 parseGetSpelling(formatString) ||
2889 parseToken(FIRToken::string,
"expected format string in 'assert'"))
2892 SmallVector<Value, 4> operands;
2893 while (!consumeIf(FIRToken::r_paren)) {
2894 operands.push_back({});
2895 if (parseToken(FIRToken::comma,
"expected ','") ||
2896 parseExp(operands.back(),
"expected operand in 'assert'"))
2900 if (parseOptionalName(name) || parseOptionalInfo())
2903 locationProcessor.setLoc(startTok.getLoc());
2905 builder.create<AssertOp>(clock, predicate, enable, formatStrUnescaped,
2906 operands, name.getValue());
2911 ParseResult FIRStmtParser::parseAssume() {
2912 auto startTok = consumeToken(FIRToken::lp_assume);
2914 Value clock, predicate, enable;
2915 StringRef formatString;
2917 if (parseExp(clock,
"expected clock expression in 'assume'") ||
2918 parseToken(FIRToken::comma,
"expected ','") ||
2919 parseExp(predicate,
"expected predicate in 'assume'") ||
2920 parseToken(FIRToken::comma,
"expected ','") ||
2921 parseExp(enable,
"expected enable in 'assume'") ||
2922 parseToken(FIRToken::comma,
"expected ','") ||
2923 parseGetSpelling(formatString) ||
2924 parseToken(FIRToken::string,
"expected format string in 'assume'"))
2927 SmallVector<Value, 4> operands;
2928 while (!consumeIf(FIRToken::r_paren)) {
2929 operands.push_back({});
2930 if (parseToken(FIRToken::comma,
"expected ','") ||
2931 parseExp(operands.back(),
"expected operand in 'assume'"))
2935 if (parseOptionalName(name) || parseOptionalInfo())
2938 locationProcessor.setLoc(startTok.getLoc());
2940 builder.create<AssumeOp>(clock, predicate, enable, formatStrUnescaped,
2941 operands, name.getValue());
2946 ParseResult FIRStmtParser::parseCover() {
2947 auto startTok = consumeToken(FIRToken::lp_cover);
2949 Value clock, predicate, enable;
2952 if (parseExp(clock,
"expected clock expression in 'cover'") ||
2953 parseToken(FIRToken::comma,
"expected ','") ||
2954 parseExp(predicate,
"expected predicate in 'cover'") ||
2955 parseToken(FIRToken::comma,
"expected ','") ||
2956 parseExp(enable,
"expected enable in 'cover'") ||
2957 parseToken(FIRToken::comma,
"expected ','") ||
2958 parseGetSpelling(message) ||
2959 parseToken(FIRToken::string,
"expected message in 'cover'") ||
2960 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
2961 parseOptionalName(name) || parseOptionalInfo())
2964 locationProcessor.setLoc(startTok.getLoc());
2966 builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
2967 ValueRange{}, name.getValue());
2973 ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
2974 auto startTok = consumeToken(FIRToken::kw_when);
2978 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2982 if (parseExp(condition,
"expected condition in 'when'") ||
2983 parseToken(FIRToken::colon,
"expected ':' in when") ||
2984 parseOptionalInfo())
2987 locationProcessor.setLoc(startTok.getLoc());
2989 auto whenStmt = builder.create<WhenOp>(condition,
false);
2992 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
2996 if (getToken().isNot(FIRToken::kw_else))
3001 auto elseIndent = getIndentation();
3002 if (elseIndent && *elseIndent < whenIndent)
3005 consumeToken(FIRToken::kw_else);
3008 whenStmt.createElseRegion();
3014 if (getToken().is(FIRToken::kw_when)) {
3016 auto subParser = std::make_unique<FIRStmtParser>(
3017 whenStmt.getElseBlock(), moduleContext, modNameSpace, circuitSymTbl,
3020 return subParser->parseSimpleStmt(whenIndent);
3024 LocationAttr elseLoc;
3025 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3026 parseOptionalInfoLocator(elseLoc) ||
3027 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3036 ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3037 auto startLoc = getToken().getLoc();
3038 locationProcessor.setLoc(startLoc);
3040 if (parseEnumType(type))
3044 auto enumType = type_dyn_cast<FEnumType>(type);
3046 return emitError(startLoc,
3047 "expected enumeration type in enumeration expression");
3050 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3051 parseId(tag,
"expected enumeration tag"))
3055 if (consumeIf(FIRToken::r_paren)) {
3058 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3060 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3061 input = builder.create<ConstantOp>(type, attr);
3064 if (parseToken(FIRToken::comma,
"expected ','") ||
3065 parseExp(input,
"expected expression in enumeration value") ||
3066 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3070 value = builder.create<FEnumCreateOp>(enumType, tag, input);
3078 ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3079 auto startTok = consumeToken(FIRToken::kw_match);
3081 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3085 if (parseExp(input,
"expected expression in 'match'") ||
3086 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3087 parseOptionalInfo())
3090 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3092 return mlir::emitError(
3094 "expected enumeration type for 'match' statement, but got ")
3097 locationProcessor.setLoc(startTok.getLoc());
3099 SmallVector<Attribute> tags;
3100 SmallVector<std::unique_ptr<Region>> regions;
3102 auto tagLoc = getToken().getLoc();
3105 auto caseIndent = getIndentation();
3106 if (!caseIndent || *caseIndent <= matchIndent)
3110 StringRef tagSpelling;
3111 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3113 auto tagIndex = enumType.getElementIndex(tagSpelling);
3115 return emitError(tagLoc,
"tag ")
3116 << tagSpelling <<
" not a member of enumeration " << enumType;
3118 tags.push_back(tag);
3121 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3124 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3129 UnbundledValueRestorer x(moduleContext.unbundledValues);
3132 if (consumeIf(FIRToken::l_paren)) {
3133 StringAttr identifier;
3134 if (parseId(identifier,
"expected identifier for 'case' binding"))
3138 auto dataType = enumType.getElementType(*tagIndex);
3139 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3141 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3145 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3149 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3150 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3153 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3158 std::make_unique<FIRStmtParser>(*caseBlock, moduleContext, modNameSpace,
3159 circuitSymTbl, version, layerSym);
3160 if (subParser->parseSimpleStmtBlock(*caseIndent))
3164 builder.create<MatchOp>(input,
ArrayAttr::get(getContext(), tags), regions);
3170 ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3171 auto token = getToken().getKind();
3172 if (token == FIRToken::lp_probe)
3173 return parseProbe(result);
3174 if (token == FIRToken::lp_rwprobe)
3175 return parseRWProbe(result);
3180 return parseStaticRefExp(result, message);
3187 ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3188 const Twine &message) {
3189 auto parseIdOrInstance = [&]() -> ParseResult {
3191 auto loc = getToken().getLoc();
3193 if (parseId(
id, message) ||
3194 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3198 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3204 StringRef fieldName;
3206 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3207 parseFieldId(fieldName,
"expected field name") ||
3208 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3210 return failure(parseIdOrInstance() ||
3211 parseOptionalExpPostscript(result,
false));
3222 ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3224 const Twine &message) {
3225 auto loc = getToken().getLoc();
3229 if (parseId(
id, message) ||
3230 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3242 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3244 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3246 StringRef fieldName;
3247 auto loc = getToken().getLoc();
3248 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3249 parseFieldId(fieldName,
"expected field name"))
3255 for (
auto &elt : ubEntry) {
3256 if (elt.first == fieldAttr) {
3259 auto &instResult = elt.second;
3262 auto *defining = instResult.getDefiningOp();
3264 if (isa<WireOp>(defining)) {
3265 result = instResult;
3270 auto type = instResult.getType();
3274 bool forceable =
static_cast<bool>(
3277 return emitError(loc,
"unable to force instance result of type ")
3281 auto annotations = getConstants().emptyArrayAttr;
3282 StringAttr sym = {};
3283 SmallString<64> name;
3284 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3285 locationProcessor.setLoc(loc);
3286 OpBuilder::InsertionGuard guard(builder);
3287 builder.setInsertionPoint(defining);
3288 auto bounce = builder.create<WireOp>(
3289 type, name, NameKindEnum::InterestingName, annotations, sym);
3290 auto bounceVal = bounce.getData();
3293 instResult.replaceAllUsesWith(bounceVal);
3296 builder.setInsertionPointAfter(defining);
3304 result = instResult = bounce.getDataRaw();
3310 emitError(loc,
"use of invalid field name '")
3311 << fieldName <<
"' on bundle value";
3316 result = symtabEntry.get<Value>();
3320 assert(isa<BlockArgument>(result) ||
3321 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3327 type = result.getType();
3329 if (consumeIf(FIRToken::period)) {
3330 SmallVector<StringRef, 3> fields;
3331 if (parseFieldIdSeq(fields,
"expected field name"))
3333 for (
auto fieldName : fields) {
3334 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3335 if (
auto index = bundle.getElementIndex(fieldName)) {
3336 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3337 type = bundle.getElementTypePreservingConst(*index);
3340 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3341 if (
auto index = bundle.getElementIndex(fieldName)) {
3342 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3343 type = bundle.getElementTypePreservingConst(*index);
3347 return emitError(loc,
"subfield requires bundle operand")
3348 <<
"got " << type <<
"\n";
3350 return emitError(loc,
3351 "unknown field '" + fieldName +
"' in bundle type ")
3356 if (consumeIf(FIRToken::l_square)) {
3357 auto loc = getToken().
getLoc();
3359 if (parseIntLit(index,
"expected index") ||
3360 parseToken(FIRToken::r_square,
"expected ']'"))
3364 return emitError(loc,
"invalid index specifier");
3366 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3367 if ((
unsigned)index < vector.getNumElements()) {
3368 refResult = refResult.
getSubField(vector.getFieldID(index));
3369 type = vector.getElementTypePreservingConst();
3372 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3373 if ((
unsigned)index < vector.getNumElements()) {
3374 refResult = refResult.
getSubField(vector.getFieldID(index));
3375 type = vector.getElementTypePreservingConst();
3379 return emitError(loc,
"subindex requires vector operand");
3381 return emitError(loc,
"out of range index '")
3382 << index <<
"' for vector type " << type;
3390 ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3391 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3392 StringRef intrinsic;
3393 ArrayAttr parameters;
3396 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3397 parseOptionalParams(parameters))
3400 if (consumeIf(FIRToken::colon)) {
3401 if (
parseType(type,
"expected intrinsic return type"))
3403 }
else if (!isStatement)
3404 return emitError(
"expected ':' in intrinsic expression");
3406 SmallVector<Value> operands;
3407 auto loc = startTok.getLoc();
3408 if (consumeIf(FIRToken::comma)) {
3409 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3411 if (parseExp(operand,
"expected operand in intrinsic"))
3413 operands.push_back(operand);
3414 locationProcessor.setLoc(loc);
3419 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3424 if (parseOptionalInfo())
3427 locationProcessor.setLoc(loc);
3429 auto op = builder.create<GenericIntrinsicOp>(
3430 type, builder.getStringAttr(intrinsic), operands, parameters);
3432 result = op.getResult();
3437 ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3438 if (!consumeIf(FIRToken::less))
3441 SmallVector<Attribute, 8> parameters;
3442 SmallPtrSet<StringAttr, 8> seen;
3443 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3447 if (parseParameter(name, value, loc))
3449 if (!seen.insert(name).second)
3450 return emitError(loc,
"redefinition of parameter '" +
3451 name.getValue() +
"'");
3463 ParseResult FIRStmtParser::parsePathExp(Value &result) {
3464 auto startTok = consumeToken(FIRToken::lp_path);
3465 locationProcessor.setLoc(startTok.getLoc());
3467 if (parseGetSpelling(target) ||
3468 parseToken(FIRToken::string,
3469 "expected target string in path expression") ||
3470 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3472 result = builder.create<UnresolvedPathOp>(
3478 ParseResult FIRStmtParser::parseRefDefine() {
3479 auto startTok = consumeToken(FIRToken::kw_define);
3482 if (parseStaticRefExp(target,
3483 "expected static reference expression in 'define'") ||
3484 parseToken(FIRToken::equal,
3485 "expected '=' after define reference expression") ||
3486 parseRefExp(src,
"expected reference expression in 'define'") ||
3487 parseOptionalInfo())
3491 if (!type_isa<RefType>(target.getType()))
3492 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3493 "'define' target (LHS), got ")
3494 << target.getType();
3495 if (!type_isa<RefType>(src.getType()))
3496 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3497 "'define' source (RHS), got ")
3502 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3503 return emitError(startTok.getLoc(),
3504 "cannot define into a sub-element of a reference");
3506 locationProcessor.setLoc(startTok.getLoc());
3509 return emitError(startTok.getLoc(),
"cannot define reference of type ")
3510 << target.getType() <<
" with incompatible reference of type "
3520 ParseResult FIRStmtParser::parseRefRead(Value &result) {
3521 auto startTok = consumeToken(FIRToken::lp_read);
3524 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
3525 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
3528 locationProcessor.setLoc(startTok.getLoc());
3531 if (!type_isa<RefType>(ref.getType()))
3532 return emitError(startTok.getLoc(),
3533 "expected reference-type expression in 'read', got ")
3536 result = builder.create<RefResolveOp>(ref);
3542 ParseResult FIRStmtParser::parseProbe(Value &result) {
3543 auto startTok = consumeToken(FIRToken::lp_probe);
3546 if (parseStaticRefExp(staticRef,
3547 "expected static reference expression in 'probe'") ||
3548 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
3551 locationProcessor.setLoc(startTok.getLoc());
3554 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3555 return emitError(startTok.getLoc(),
3556 "expected base-type expression in 'probe', got ")
3557 << staticRef.getType();
3561 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3562 MemoryDebugPortOp, MemoryPortAccessOp>(
3563 staticRef.getDefiningOp()))
3564 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3566 result = builder.create<RefSendOp>(staticRef);
3572 ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3573 auto startTok = consumeToken(FIRToken::lp_rwprobe);
3576 Type parsedTargetType;
3577 if (parseRWProbeStaticRefExp(
3578 staticRef, parsedTargetType,
3579 "expected static reference expression in 'rwprobe'") ||
3580 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
3583 locationProcessor.setLoc(startTok.getLoc());
3589 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
3591 return emitError(startTok.getLoc(),
3592 "expected base-type expression in 'rwprobe', got ")
3593 << parsedTargetType;
3596 auto *definingOp = root.getDefiningOp();
3598 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3599 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
3600 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3604 return emitError(startTok.getLoc(),
"cannot force target of type ")
3610 [&](
auto _) -> hw::InnerSymbolNamespace & {
return modNameSpace; });
3611 result = builder.create<RWProbeOp>(forceableType, sym);
3616 ParseResult FIRStmtParser::parseRefForce() {
3617 auto startTok = consumeToken(FIRToken::lp_force);
3619 Value clock, pred, dest, src;
3620 if (parseExp(clock,
"expected clock expression in force") ||
3621 parseToken(FIRToken::comma,
"expected ','") ||
3622 parseExp(pred,
"expected predicate expression in force") ||
3623 parseToken(FIRToken::comma,
"expected ','") ||
3624 parseRefExp(dest,
"expected destination reference expression in force") ||
3625 parseToken(FIRToken::comma,
"expected ','") ||
3626 parseExp(src,
"expected source expression in force") ||
3627 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
3628 parseOptionalInfo())
3632 auto ref = type_dyn_cast<RefType>(dest.getType());
3633 if (!ref || !ref.getForceable())
3636 "expected rwprobe-type expression for force destination, got ")
3638 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3640 return emitError(startTok.getLoc(),
3641 "expected base-type for force source, got ")
3644 locationProcessor.setLoc(startTok.getLoc());
3647 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3648 if (noConstSrcType != ref.getType()) {
3650 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3652 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3655 builder.create<RefForceOp>(clock, pred, dest, src);
3661 ParseResult FIRStmtParser::parseRefForceInitial() {
3662 auto startTok = consumeToken(FIRToken::lp_force_initial);
3666 dest,
"expected destination reference expression in force_initial") ||
3667 parseToken(FIRToken::comma,
"expected ','") ||
3668 parseExp(src,
"expected source expression in force_initial") ||
3669 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
3670 parseOptionalInfo())
3674 auto ref = type_dyn_cast<RefType>(dest.getType());
3675 if (!ref || !ref.getForceable())
3676 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3677 "force_initial destination, got ")
3679 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3681 return emitError(startTok.getLoc(),
3682 "expected base-type expression for force_initial "
3686 locationProcessor.setLoc(startTok.getLoc());
3689 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3690 if (noConstSrcType != ref.getType()) {
3692 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3694 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3697 auto value = APInt::getAllOnes(1);
3700 value.getBitWidth(),
3701 IntegerType::Unsigned),
3703 auto pred = moduleContext.getCachedConstantInt(builder, attr, type, value);
3704 builder.create<RefForceInitialOp>(pred, dest, src);
3710 ParseResult FIRStmtParser::parseRefRelease() {
3711 auto startTok = consumeToken(FIRToken::lp_release);
3713 Value clock, pred, dest;
3714 if (parseExp(clock,
"expected clock expression in release") ||
3715 parseToken(FIRToken::comma,
"expected ','") ||
3716 parseExp(pred,
"expected predicate expression in release") ||
3717 parseToken(FIRToken::comma,
"expected ','") ||
3719 "expected destination reference expression in release") ||
3720 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
3721 parseOptionalInfo())
3725 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3726 !ref || !ref.getForceable())
3729 "expected rwprobe-type expression for release destination, got ")
3732 locationProcessor.setLoc(startTok.getLoc());
3734 builder.create<RefReleaseOp>(clock, pred, dest);
3740 ParseResult FIRStmtParser::parseRefReleaseInitial() {
3741 auto startTok = consumeToken(FIRToken::lp_release_initial);
3746 "expected destination reference expression in release_initial") ||
3747 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
3748 parseOptionalInfo())
3752 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3753 !ref || !ref.getForceable())
3754 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3755 "release_initial destination, got ")
3758 locationProcessor.setLoc(startTok.getLoc());
3760 auto value = APInt::getAllOnes(1);
3763 value.getBitWidth(),
3764 IntegerType::Unsigned),
3766 auto pred = moduleContext.getCachedConstantInt(builder, attr, type, value);
3767 builder.create<RefReleaseInitialOp>(pred, dest);
3773 ParseResult FIRStmtParser::parseConnect() {
3774 auto startTok = consumeToken(FIRToken::kw_connect);
3775 auto loc = startTok.getLoc();
3778 if (parseExp(lhs,
"expected connect expression") ||
3779 parseToken(FIRToken::comma,
"expected ','") ||
3780 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
3783 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3784 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3785 if (!lhsType || !rhsType)
3786 return emitError(loc,
"cannot connect reference or property types");
3788 if (lhsType.containsReference() || rhsType.containsReference())
3789 return emitError(loc,
"cannot connect types containing references");
3792 return emitError(loc,
"cannot connect non-equivalent type ")
3793 << rhsType <<
" to " << lhsType;
3795 locationProcessor.setLoc(loc);
3801 ParseResult FIRStmtParser::parsePropAssign() {
3802 auto startTok = consumeToken(FIRToken::kw_propassign);
3803 auto loc = startTok.getLoc();
3806 if (parseExp(lhs,
"expected propassign expression") ||
3807 parseToken(FIRToken::comma,
"expected ','") ||
3808 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
3811 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
3812 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
3813 if (!lhsType || !rhsType)
3814 return emitError(loc,
"can only propassign property types");
3815 locationProcessor.setLoc(loc);
3816 if (lhsType != rhsType) {
3818 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
3819 rhs = builder.create<ObjectAnyRefCastOp>(rhs);
3821 return emitError(loc,
"cannot propassign non-equivalent type ")
3822 << rhsType <<
" to " << lhsType;
3824 builder.create<PropAssignOp>(lhs, rhs);
3829 ParseResult FIRStmtParser::parseInvalidate() {
3830 auto startTok = consumeToken(FIRToken::kw_invalidate);
3833 if (parseExp(lhs,
"expected connect expression") || parseOptionalInfo())
3836 locationProcessor.setLoc(startTok.getLoc());
3837 emitInvalidate(lhs);
3841 ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
3843 auto startTok = consumeToken();
3844 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
3845 "consumed an unexpected token");
3846 auto loc = startTok.getLoc();
3849 if (parseId(
id,
"expected layer identifer") ||
3850 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
3851 parseOptionalInfo())
3854 locationProcessor.setLoc(loc);
3856 StringRef rootLayer;
3857 SmallVector<FlatSymbolRefAttr> nestedLayers;
3861 rootLayer = layerSym.getRootReference();
3862 auto nestedRefs = layerSym.getNestedReferences();
3863 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
3867 auto layerBlockOp = builder.create<LayerBlockOp>(
3869 layerBlockOp->getRegion(0).push_back(
new Block());
3871 if (getIndentation() > indent)
3872 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
3873 layerBlockOp.getLayerName()))
3881 ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
3882 auto loc = getToken().getLoc();
3885 if (consumeIf(FIRToken::kw_is)) {
3886 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
3887 parseOptionalInfo())
3890 locationProcessor.setLoc(loc);
3891 emitInvalidate(lhs);
3895 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
3899 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
3902 locationProcessor.setLoc(loc);
3904 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3905 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3906 if (!lhsType || !rhsType)
3907 return emitError(loc,
"cannot connect reference or property types");
3909 if (lhsType.containsReference() || rhsType.containsReference())
3910 return emitError(loc,
"cannot connect types containing references");
3913 return emitError(loc,
"cannot connect non-equivalent type ")
3914 << rhsType <<
" to " << lhsType;
3923 ParseResult FIRStmtParser::parseInstance() {
3924 auto startTok = consumeToken(FIRToken::kw_inst);
3928 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3932 StringRef moduleName;
3933 if (parseId(
id,
"expected instance name") ||
3934 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
3935 parseId(moduleName,
"expected module name") || parseOptionalInfo())
3938 locationProcessor.setLoc(startTok.getLoc());
3941 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
3942 if (!referencedModule)
3945 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
3947 auto annotations = getConstants().emptyArrayAttr;
3948 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
3950 hw::InnerSymAttr sym = {};
3951 auto result = builder.create<InstanceOp>(
3952 referencedModule, id, NameKindEnum::InterestingName,
3953 annotations.getValue(), portAnnotations,
false, sym);
3959 unbundledValueEntry.reserve(modulePorts.size());
3960 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
3961 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
3965 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
3966 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
3967 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
3972 ParseResult FIRStmtParser::parseInstanceChoice() {
3973 auto startTok = consumeToken(FIRToken::kw_instchoice);
3974 SMLoc loc = startTok.getLoc();
3977 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3980 if (requireFeature({4, 0, 0},
"option groups/instance choices"))
3984 StringRef defaultModuleName;
3985 StringRef optionGroupName;
3986 if (parseId(
id,
"expected instance name") ||
3987 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
3988 parseId(defaultModuleName,
"expected module name") ||
3989 parseToken(FIRToken::comma,
"expected ','") ||
3990 parseId(optionGroupName,
"expected option group name") ||
3991 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
3992 parseOptionalInfo())
3995 locationProcessor.setLoc(startTok.getLoc());
3999 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4003 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4006 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4008 return emitError(loc,
4009 "use of undefined option group '" + optionGroupName +
"'");
4011 auto baseIndent = getIndentation();
4012 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4013 while (getIndentation() == baseIndent) {
4015 StringRef caseModuleName;
4016 if (parseId(caseId,
"expected a case identifier") ||
4017 parseToken(FIRToken::equal_greater,
4018 "expected '=> in instance choice definition") ||
4019 parseId(caseModuleName,
"expected module name"))
4022 auto caseModule = getReferencedModule(loc, caseModuleName);
4026 for (
const auto &[defaultPort, casePort] :
4027 llvm::zip(modulePorts, caseModule.getPorts())) {
4028 if (defaultPort.name != casePort.name)
4029 return emitError(loc,
"instance case module port '")
4030 << casePort.name.getValue()
4031 <<
"' does not match the default module port '"
4032 << defaultPort.name.getValue() <<
"'";
4033 if (defaultPort.type != casePort.type)
4034 return emitError(loc,
"instance case port '")
4035 << casePort.name.getValue()
4036 <<
"' type does not match the default module port";
4040 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4042 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4043 caseModules.emplace_back(optionCase, caseModule);
4046 auto annotations = getConstants().emptyArrayAttr;
4047 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4051 auto result = builder.create<InstanceChoiceOp>(
4052 defaultModule, caseModules, id, NameKindEnum::InterestingName,
4053 annotations.getValue(), portAnnotations, sym);
4057 unbundledValueEntry.reserve(modulePorts.size());
4058 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4059 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4061 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4062 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4063 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4066 FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4067 StringRef moduleName) {
4068 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4069 if (!referencedModule) {
4071 "use of undefined module name '" + moduleName +
"' in instance");
4074 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4075 emitError(loc,
"cannot create instance of class '" + moduleName +
4076 "', did you mean object?");
4079 return referencedModule;
4083 ParseResult FIRStmtParser::parseObject() {
4084 auto startTok = consumeToken(FIRToken::kw_object);
4088 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4095 StringRef className;
4096 if (parseId(
id,
"expected object name") ||
4097 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4098 parseId(className,
"expected class name") || parseOptionalInfo())
4101 locationProcessor.setLoc(startTok.getLoc());
4104 const auto &classMap = getConstants().classMap;
4105 auto lookup = classMap.find(className);
4106 if (lookup == classMap.end())
4107 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4108 className +
"' in object");
4109 auto referencedClass = lookup->getSecond();
4110 auto result = builder.create<ObjectOp>(referencedClass, id);
4111 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4115 ParseResult FIRStmtParser::parseCombMem() {
4117 auto startTok = consumeToken(FIRToken::kw_cmem);
4121 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4126 if (parseId(
id,
"expected cmem name") ||
4127 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4128 parseType(type,
"expected cmem type") || parseOptionalInfo())
4131 locationProcessor.setLoc(startTok.getLoc());
4134 auto vectorType = type_dyn_cast<FVectorType>(type);
4136 return emitError(
"cmem requires vector type");
4138 auto annotations = getConstants().emptyArrayAttr;
4139 StringAttr sym = {};
4140 auto result = builder.create<CombMemOp>(
4141 vectorType.getElementType(), vectorType.getNumElements(), id,
4142 NameKindEnum::InterestingName, annotations, sym);
4143 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4147 ParseResult FIRStmtParser::parseSeqMem() {
4149 auto startTok = consumeToken(FIRToken::kw_smem);
4153 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4158 RUWAttr ruw = RUWAttr::Undefined;
4160 if (parseId(
id,
"expected smem name") ||
4161 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4165 if (consumeIf(FIRToken::comma)) {
4170 if (parseOptionalInfo()) {
4174 locationProcessor.setLoc(startTok.getLoc());
4177 auto vectorType = type_dyn_cast<FVectorType>(type);
4179 return emitError(
"smem requires vector type");
4181 auto annotations = getConstants().emptyArrayAttr;
4182 StringAttr sym = {};
4183 auto result = builder.create<SeqMemOp>(
4184 vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
4185 NameKindEnum::InterestingName, annotations, sym);
4186 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4198 ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4199 auto startTok = consumeToken(FIRToken::kw_mem);
4203 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4207 if (parseId(
id,
"expected mem name") ||
4208 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4212 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4213 RUWAttr ruw = RUWAttr::Undefined;
4215 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4219 auto nextIndent = getIndentation();
4220 if (!nextIndent || *nextIndent <= memIndent)
4223 auto spelling = getTokenSpelling();
4224 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4225 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4228 if (spelling ==
"data-type") {
4230 return emitError(
"'mem' type specified multiple times"), failure();
4232 if (
parseType(type,
"expected type in data-type declaration"))
4236 if (spelling ==
"depth") {
4237 if (parseIntLit(depth,
"expected integer in depth specification"))
4241 if (spelling ==
"read-latency") {
4242 if (parseIntLit(readLatency,
"expected integer latency"))
4246 if (spelling ==
"write-latency") {
4247 if (parseIntLit(writeLatency,
"expected integer latency"))
4251 if (spelling ==
"read-under-write") {
4252 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4253 FIRToken::kw_undefined))
4254 return emitError(
"expected specifier"), failure();
4256 if (parseOptionalRUW(ruw))
4261 MemOp::PortKind portKind;
4262 if (spelling ==
"reader")
4263 portKind = MemOp::PortKind::Read;
4264 else if (spelling ==
"writer")
4265 portKind = MemOp::PortKind::Write;
4266 else if (spelling ==
"readwriter")
4267 portKind = MemOp::PortKind::ReadWrite;
4269 return emitError(
"unexpected field in 'mem' declaration"), failure();
4272 if (parseId(portName,
"expected port name"))
4274 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4276 return emitError(
"unexpected type, must be base type");
4277 ports.push_back({builder.getStringAttr(portName),
4278 MemOp::getTypeForPort(depth, baseType, portKind)});
4280 while (!getIndentation().has_value()) {
4281 if (parseId(portName,
"expected port name"))
4283 ports.push_back({builder.getStringAttr(portName),
4284 MemOp::getTypeForPort(depth, baseType, portKind)});
4295 llvm::array_pod_sort(ports.begin(), ports.end(),
4296 [](
const std::pair<StringAttr, Type> *lhs,
4297 const std::pair<StringAttr, Type> *rhs) ->
int {
4298 return lhs->first.getValue().compare(
4299 rhs->first.getValue());
4302 auto annotations = getConstants().emptyArrayAttr;
4303 SmallVector<Attribute, 4> resultNames;
4304 SmallVector<Type, 4> resultTypes;
4305 SmallVector<Attribute, 4> resultAnnotations;
4306 for (
auto p : ports) {
4307 resultNames.push_back(p.first);
4308 resultTypes.push_back(p.second);
4309 resultAnnotations.push_back(annotations);
4312 locationProcessor.setLoc(startTok.getLoc());
4314 auto result = builder.create<MemOp>(
4315 resultTypes, readLatency, writeLatency, depth, ruw,
4316 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
4317 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4318 MemoryInitAttr(), StringAttr());
4321 unbundledValueEntry.reserve(result.getNumResults());
4322 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4323 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4325 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4326 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4327 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4331 ParseResult FIRStmtParser::parseNode() {
4332 auto startTok = consumeToken(FIRToken::kw_node);
4336 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4341 if (parseId(
id,
"expected node name") ||
4342 parseToken(FIRToken::equal,
"expected '=' in node") ||
4343 parseExp(initializer,
"expected expression for node") ||
4344 parseOptionalInfo())
4347 locationProcessor.setLoc(startTok.getLoc());
4359 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4360 auto initializerBaseType =
4361 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4362 if (type_isa<AnalogType>(initializerType) ||
4363 !(initializerBaseType && initializerBaseType.isPassive())) {
4364 emitError(startTok.getLoc())
4365 <<
"Node cannot be analog and must be passive or passive under a flip "
4366 << initializer.getType();
4370 auto annotations = getConstants().emptyArrayAttr;
4371 StringAttr sym = {};
4373 auto result = builder.create<NodeOp>(
4374 initializer, id, NameKindEnum::InterestingName, annotations, sym);
4375 return moduleContext.addSymbolEntry(
id, result.getResult(),
4380 ParseResult FIRStmtParser::parseWire() {
4381 auto startTok = consumeToken(FIRToken::kw_wire);
4385 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4390 if (parseId(
id,
"expected wire name") ||
4391 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4392 parseType(type,
"expected wire type") || parseOptionalInfo())
4395 locationProcessor.setLoc(startTok.getLoc());
4397 auto annotations = getConstants().emptyArrayAttr;
4398 StringAttr sym = {};
4401 auto namekind = isa<PropertyType, RefType>(type)
4402 ? NameKindEnum::DroppableName
4403 : NameKindEnum::InterestingName;
4405 auto result = builder.create<WireOp>(type, id, namekind, annotations, sym);
4406 return moduleContext.addSymbolEntry(
id, result.getResult(),
4420 ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4421 auto startTok = consumeToken(FIRToken::kw_reg);
4425 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4434 if (parseId(
id,
"expected reg name") ||
4435 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4437 parseToken(FIRToken::comma,
"expected ','") ||
4438 parseExp(clock,
"expected expression for register clock"))
4441 if (!type_isa<FIRRTLBaseType>(type))
4442 return emitError(startTok.getLoc(),
"register must have base type");
4445 Value resetSignal, resetValue;
4446 if (consumeIf(FIRToken::kw_with)) {
4447 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
4455 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4457 auto indent = getIndentation();
4458 if (!indent || *indent <= regIndent)
4459 if (!hasExtraLParen)
4460 return emitError(
"expected indented reset specifier in reg"), failure();
4462 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
4463 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
4464 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
4465 parseExp(resetSignal,
"expected expression for reset signal") ||
4466 parseToken(FIRToken::comma,
"expected ','"))
4474 if (getTokenSpelling() ==
id) {
4476 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4478 resetSignal = Value();
4480 if (parseExp(resetValue,
"expected expression for reset value") ||
4481 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4485 if (hasExtraLParen &&
4486 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4492 if (parseOptionalInfo())
4495 locationProcessor.setLoc(startTok.getLoc());
4497 ArrayAttr annotations = getConstants().emptyArrayAttr;
4499 StringAttr sym = {};
4503 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4504 NameKindEnum::InterestingName, annotations, sym)
4508 .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4511 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4519 ParseResult FIRStmtParser::parseRegisterWithReset() {
4520 auto startTok = consumeToken(FIRToken::kw_regreset);
4524 Value clock, resetSignal, resetValue;
4526 if (parseId(
id,
"expected reg name") ||
4527 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4529 parseToken(FIRToken::comma,
"expected ','") ||
4530 parseExp(clock,
"expected expression for register clock") ||
4531 parseToken(FIRToken::comma,
"expected ','") ||
4532 parseExp(resetSignal,
"expected expression for register reset") ||
4533 parseToken(FIRToken::comma,
"expected ','") ||
4534 parseExp(resetValue,
"expected expression for register reset value") ||
4535 parseOptionalInfo())
4538 if (!type_isa<FIRRTLBaseType>(type))
4539 return emitError(startTok.getLoc(),
"register must have base type");
4541 locationProcessor.setLoc(startTok.getLoc());
4545 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4546 NameKindEnum::InterestingName,
4547 getConstants().emptyArrayAttr, StringAttr{})
4550 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4560 struct FIRCircuitParser :
public FIRParser {
4561 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
4563 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
4566 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
4567 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBuf,
4568 mlir::TimingScope &ts);
4573 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4574 SmallVectorImpl<Attribute> &attrs);
4578 ParseResult importOMIR(CircuitOp circuit, SMLoc loc, StringRef annotationStr,
4579 SmallVectorImpl<Attribute> &attrs);
4581 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
4583 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
4584 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
4585 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
4586 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
4587 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
4589 ParseResult parseLayerName(SymbolRefAttr &result);
4590 ParseResult parseOptionalEnabledLayers(ArrayAttr &result);
4591 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4592 SmallVectorImpl<SMLoc> &resultPortLocs,
4595 ParseResult parseRefList(ArrayRef<PortInfo> portList,
4596 ArrayAttr &internalPathsResult);
4598 ParseResult skipToModuleEnd(
unsigned indent);
4600 ParseResult parseTypeDecl();
4602 ParseResult parseOptionDecl(CircuitOp circuit);
4604 ParseResult parseLayer(CircuitOp circuit);
4606 struct DeferredModuleToParse {
4607 FModuleLike moduleOp;
4608 SmallVector<SMLoc> portLocs;
4613 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
4614 DeferredModuleToParse &deferredModule);
4616 SmallVector<DeferredModuleToParse, 0> deferredModules;
4617 ModuleOp mlirModule;
4622 FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4623 SmallVectorImpl<Attribute> &attrs) {
4625 auto annotations = json::parse(annotationsStr);
4626 if (
auto err = annotations.takeError()) {
4627 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4628 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
4629 diag.attachNote() << a.message();
4634 json::Path::Root root;
4635 llvm::StringMap<ArrayAttr> thisAnnotationMap;
4638 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
4639 std::string jsonErrorMessage =
4640 "See inline comments for problem area in JSON:\n";
4641 llvm::raw_string_ostream s(jsonErrorMessage);
4642 root.printErrorContext(annotations.get(), s);
4643 diag.attachNote() << jsonErrorMessage;
4650 ParseResult FIRCircuitParser::importOMIR(CircuitOp circuit, SMLoc loc,
4651 StringRef annotationsStr,
4652 SmallVectorImpl<Attribute> &annos) {
4654 auto annotations = json::parse(annotationsStr);
4655 if (
auto err = annotations.takeError()) {
4656 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4657 auto diag = emitError(loc,
"Failed to parse OMIR file");
4658 diag.attachNote() << a.message();
4663 json::Path::Root root;
4664 if (!
fromOMIRJSON(annotations.get(), annos, root, circuit.getContext())) {
4665 auto diag = emitError(loc,
"Invalid/unsupported OMIR format");
4666 std::string jsonErrorMessage =
4667 "See inline comments for problem area in JSON:\n";
4668 llvm::raw_string_ostream s(jsonErrorMessage);
4669 root.printErrorContext(annotations.get(), s);
4670 diag.attachNote() << jsonErrorMessage;
4677 ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
4678 auto *context = getContext();
4679 SmallVector<StringRef> strings;
4682 if (parseId(name,
"expected layer name"))
4684 strings.push_back(name);
4685 }
while (consumeIf(FIRToken::period));
4687 SmallVector<FlatSymbolRefAttr> nested;
4688 nested.reserve(strings.size() - 1);
4689 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
4696 ParseResult FIRCircuitParser::parseOptionalEnabledLayers(ArrayAttr &result) {
4697 if (getToken().getKind() != FIRToken::kw_enablelayer) {
4702 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
4705 SmallVector<Attribute> layers;
4707 SymbolRefAttr layer;
4709 if (parseLayerName(layer))
4711 layers.push_back(layer);
4712 }
while (getToken().getKind() == FIRToken::kw_enablelayer);
4723 SmallVectorImpl<SMLoc> &resultPortLocs,
4726 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
4728 getIndentation() > indent) {
4734 auto backtrackState = getLexer().getCursor();
4736 bool isOutput = getToken().is(FIRToken::kw_output);
4741 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
4742 !getToken().isKeyword()) {
4743 backtrackState.restore(getLexer());
4749 LocWithInfo info(getToken().getLoc(),
this);
4750 if (parseId(name,
"expected port name") ||
4751 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
4752 parseType(type,
"expected a type in port declaration") ||
4753 info.parseOptionalInfo())
4756 StringAttr innerSym = {};
4757 resultPorts.push_back(
4758 {name, type,
direction::get(isOutput), innerSym, info.getLoc()});
4759 resultPortLocs.push_back(info.getFIRLoc());
4764 for (
auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
4765 PortInfo &port = std::get<0>(portAndLoc);
4766 auto &entry = portIds[port.
name];
4767 if (!entry.isValid()) {
4768 entry = std::get<1>(portAndLoc);
4772 emitError(std::get<1>(portAndLoc),
4773 "redefinition of name '" + port.
getName() +
"'")
4774 .attachNote(translateLocation(entry))
4775 <<
"previous definition here";
4784 ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
4785 ArrayAttr &internalPathsResult) {
4786 struct RefStatementInfo {
4788 InternalPathAttr resolvedPath;
4792 SmallVector<RefStatementInfo> refStatements;
4793 SmallPtrSet<StringAttr, 8> seenNames;
4794 SmallPtrSet<StringAttr, 8> seenRefs;
4797 if (getToken().is(FIRToken::kw_ref) &&
4798 removedFeature({4, 0, 0},
"ref statements"))
4802 while (consumeIf(FIRToken::kw_ref)) {
4803 auto loc = getToken().getLoc();
4807 if (parseId(refName,
"expected ref name"))
4809 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
4811 loc,
"ref statements for aggregate elements not yet supported");
4812 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
4815 if (!seenRefs.insert(refName).second)
4816 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
4819 auto kind = getToken().getKind();
4820 if (kind != FIRToken::string)
4821 return emitError(loc,
"expected string in ref statement");
4825 consumeToken(FIRToken::string);
4827 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
4831 SmallVector<Attribute> internalPaths(portList.size(),
4834 llvm::SmallBitVector usedRefs(refStatements.size());
4835 size_t matchedPaths = 0;
4836 for (
auto [idx, port] : llvm::enumerate(portList)) {
4837 if (!type_isa<RefType>(port.
type))
4843 return mlir::emitError(
4845 "references in ports must be output on extmodule and intmodule");
4847 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
4848 return r.refName == pname;
4851 if (refStmtIt == refStatements.end()) {
4852 if (!refStatements.empty())
4853 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
4858 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
4859 internalPaths[idx] = refStmtIt->resolvedPath;
4863 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
4864 assert(matchedPaths < refStatements.size());
4866 auto idx = usedRefs.find_first_unset();
4868 return emitError(refStatements[idx].loc,
"unused ref statement");
4872 internalPathsResult =
ArrayAttr::get(getContext(), internalPaths);
4878 ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
4880 switch (getToken().getKind()) {
4884 case FIRToken::error:
4888 case FIRToken::kw_class:
4889 case FIRToken::kw_declgroup:
4890 case FIRToken::kw_extclass:
4891 case FIRToken::kw_extmodule:
4892 case FIRToken::kw_intmodule:
4893 case FIRToken::kw_module:
4894 case FIRToken::kw_public:
4895 case FIRToken::kw_layer:
4896 case FIRToken::kw_option:
4897 case FIRToken::kw_type:
4901 if (getIndentation() == indent)
4914 SmallVector<Attribute, 8> parameters;
4915 SmallPtrSet<StringAttr, 8> seen;
4916 while (consumeIf(FIRToken::kw_parameter)) {
4920 if (parseParameter(name, value, loc))
4922 if (!seen.insert(name).second)
4923 return emitError(loc,
4924 "redefinition of parameter '" + name.getValue() +
"'");
4932 ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
4934 SmallVector<PortInfo, 8> portList;
4935 SmallVector<SMLoc> portLocs;
4936 LocWithInfo info(getToken().getLoc(),
this);
4941 consumeToken(FIRToken::kw_class);
4942 if (parseId(name,
"expected class name") ||
4943 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
4944 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4947 if (name == circuit.getName())
4948 return mlir::emitError(info.getLoc(),
4949 "class cannot be the top of a circuit");
4951 for (
auto &portInfo : portList)
4952 if (!isa<PropertyType>(portInfo.type))
4953 return mlir::emitError(portInfo.loc,
4954 "ports on classes must be properties");
4957 auto builder = circuit.getBodyBuilder();
4958 auto classOp = builder.create<ClassOp>(info.getLoc(), name, portList);
4959 classOp.setPrivate();
4960 deferredModules.emplace_back(
4961 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
4964 getConstants().classMap[name.getValue()] = classOp;
4965 return skipToModuleEnd(indent);
4969 ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
4972 SmallVector<PortInfo, 8> portList;
4973 SmallVector<SMLoc> portLocs;
4974 LocWithInfo info(getToken().getLoc(),
this);
4979 consumeToken(FIRToken::kw_extclass);
4980 if (parseId(name,
"expected extclass name") ||
4981 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
4982 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4985 if (name == circuit.getName())
4986 return mlir::emitError(info.getLoc(),
4987 "extclass cannot be the top of a circuit");
4989 for (
auto &portInfo : portList)
4990 if (!isa<PropertyType>(portInfo.type))
4991 return mlir::emitError(portInfo.loc,
4992 "ports on extclasses must be properties");
4995 auto builder = circuit.getBodyBuilder();
4996 auto extClassOp = builder.create<ExtClassOp>(info.getLoc(), name, portList);
4999 getConstants().classMap[name.getValue()] = extClassOp;
5000 return skipToModuleEnd(indent);
5007 ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5011 SmallVector<PortInfo, 8> portList;
5012 SmallVector<SMLoc> portLocs;
5013 LocWithInfo info(getToken().getLoc(),
this);
5014 consumeToken(FIRToken::kw_extmodule);
5015 if (parseId(name,
"expected extmodule name") ||
5016 parseOptionalEnabledLayers(layers) ||
5017 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5018 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5022 if (consumeIf(FIRToken::kw_defname)) {
5023 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5024 parseId(defName,
"expected defname name"))
5028 ArrayAttr parameters;
5029 ArrayAttr internalPaths;
5034 for (
auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5035 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5036 if (ftype.hasUninferredWidth())
5037 return emitError(loc,
"extmodule port must have known width");
5042 auto builder = circuit.getBodyBuilder();
5043 auto isMainModule = (name == circuit.getName());
5045 (isMainModule && getConstants().options.scalarizePublicModules) ||
5046 getConstants().options.scalarizeExtModules
5047 ? Convention::Scalarized
5048 : Convention::Internal;
5051 auto extModuleOp = builder.create<FExtModuleOp>(
5052 info.getLoc(), name, conventionAttr, portList, defName, annotations,
5053 parameters, internalPaths, layers);
5054 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5055 : SymbolTable::Visibility::Private;
5056 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5064 ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5069 SmallVector<PortInfo, 8> portList;
5070 SmallVector<SMLoc> portLocs;
5071 LocWithInfo info(getToken().getLoc(),
this);
5072 consumeToken(FIRToken::kw_intmodule);
5073 if (parseId(name,
"expected intmodule name") ||
5074 parseOptionalEnabledLayers(layers) ||
5075 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5076 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent) ||
5077 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5078 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5079 parseId(intName,
"expected intrinsic name"))
5082 ArrayAttr parameters;
5083 ArrayAttr internalPaths;
5087 ArrayAttr annotations = getConstants().emptyArrayAttr;
5088 auto builder = circuit.getBodyBuilder();
5090 .create<FIntModuleOp>(info.getLoc(), name, portList, intName, annotations,
5091 parameters, internalPaths, layers)
5097 ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5100 SmallVector<PortInfo, 8> portList;
5101 SmallVector<SMLoc> portLocs;
5103 auto modLoc = getToken().getLoc();
5104 LocWithInfo info(modLoc,
this);
5105 consumeToken(FIRToken::kw_module);
5106 if (parseId(name,
"expected module name") ||
5107 parseOptionalEnabledLayers(layers) ||
5108 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5109 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5113 if (name == circuit.getName()) {
5114 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5119 if (isPublic && version >=
FIRVersion{4, 0, 0}) {
5120 for (
auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5121 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5122 if (ftype.hasUninferredWidth())
5123 return emitError(loc,
"public module port must have known width");
5124 if (ftype.hasUninferredReset())
5125 return emitError(loc,
5126 "public module port must have concrete reset type");
5131 ArrayAttr annotations = getConstants().emptyArrayAttr;
5132 auto convention = Convention::Internal;
5133 if (isPublic && getConstants().options.scalarizePublicModules)
5134 convention = Convention::Scalarized;
5135 if (!isPublic && getConstants().options.scalarizeInternalModules)
5136 convention = Convention::Scalarized;
5138 auto builder = circuit.getBodyBuilder();
5139 auto moduleOp = builder.create<FModuleOp>(info.getLoc(), name, conventionAttr,
5140 portList, annotations, layers);
5142 auto visibility = isPublic ? SymbolTable::Visibility::Public
5143 : SymbolTable::Visibility::Private;
5144 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5148 deferredModules.emplace_back(DeferredModuleToParse{
5149 moduleOp, portLocs, getLexer().getCursor(), indent});
5151 if (skipToModuleEnd(indent))
5156 ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5158 switch (getToken().getKind()) {
5159 case FIRToken::kw_class:
5160 return parseClass(circuit, indent);
5161 case FIRToken::kw_declgroup:
5162 if (requireFeature({3, 2, 0},
"optional groups") ||
5163 removedFeature({4, 0, 0},
"optional groups"))
5165 return parseLayer(circuit);
5166 case FIRToken::kw_extclass:
5167 return parseExtClass(circuit, indent);
5168 case FIRToken::kw_extmodule:
5169 return parseExtModule(circuit, indent);
5170 case FIRToken::kw_intmodule:
5171 if (removedFeature({4, 0, 0},
"intrinsic modules"))
5173 return parseIntModule(circuit, indent);
5174 case FIRToken::kw_layer:
5175 if (requireFeature({4, 0, 0},
"layers"))
5177 return parseLayer(circuit);
5178 case FIRToken::kw_module:
5179 return parseModule(circuit,
false, indent);
5180 case FIRToken::kw_public:
5181 if (requireFeature({4, 0, 0},
"public modules"))
5184 if (getToken().getKind() == FIRToken::kw_module)
5185 return parseModule(circuit,
true, indent);
5186 return emitError(getToken().getLoc(),
"only modules may be public");
5187 case FIRToken::kw_type:
5188 return parseTypeDecl();
5189 case FIRToken::kw_option:
5190 if (requireFeature({4, 0, 0},
"option groups/instance choices"))
5192 return parseOptionDecl(circuit);
5194 return emitError(getToken().getLoc(),
"unknown toplevel definition");
5199 ParseResult FIRCircuitParser::parseTypeDecl() {
5203 auto loc = getToken().getLoc();
5205 if (getToken().isKeyword())
5206 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5207 <<
"' for type alias name";
5209 if (parseId(
id,
"expected type name") ||
5210 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5216 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5220 <<
"type alias for non-base type " << type
5221 <<
" is currently not supported. Type alias is stripped immediately";
5223 if (!getConstants().aliasMap.insert({id, type}).second)
5224 return emitError(loc) <<
"type alias `" << name.getValue()
5225 <<
"` is already defined";
5230 ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
5233 auto loc = getToken().getLoc();
5235 LocWithInfo info(getToken().getLoc(),
this);
5236 if (parseId(
id,
"expected an option group name") ||
5237 parseToken(FIRToken::colon,
5238 "expected ':' after option group definition") ||
5239 info.parseOptionalInfo())
5242 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
5243 auto optionOp = builder.create<OptionOp>(info.getLoc(), id);
5244 auto *block =
new Block;
5245 optionOp.getBody().push_back(block);
5246 builder.setInsertionPointToEnd(block);
5248 auto baseIndent = getIndentation();
5250 while (getIndentation() == baseIndent) {
5252 LocWithInfo caseInfo(getToken().getLoc(),
this);
5253 if (parseId(
id,
"expected an option case ID") ||
5254 caseInfo.parseOptionalInfo())
5257 if (!cases.insert(
id).second)
5258 return emitError(loc)
5259 <<
"duplicate option case definition '" <<
id <<
"'";
5261 builder.create<OptionCaseOp>(caseInfo.getLoc(), id);
5268 ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
5269 auto baseIndent = getIndentation();
5272 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
5275 auto parseOne = [&](
Block *block) -> ParseResult {
5276 auto indent = getIndentation();
5277 StringRef id, convention;
5278 LocWithInfo info(getToken().getLoc(),
this);
5280 if (parseId(
id,
"expected layer name") ||
5281 parseToken(FIRToken::comma,
"expected ','") ||
5282 parseGetSpelling(convention))
5285 auto layerConvention = symbolizeLayerConvention(convention);
5286 if (!layerConvention) {
5287 emitError() <<
"unknown convention '" << convention
5288 <<
"' (did you misspell it?)";
5293 hw::OutputFileAttr outputDir;
5294 if (consumeIf(FIRToken::comma)) {
5295 if (getToken().getKind() == FIRToken::string) {
5296 auto text = getToken().getStringValue();
5298 return emitError() <<
"output directory must not be blank";
5299 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
5300 consumeToken(FIRToken::string);
5304 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
5305 info.parseOptionalInfo())
5307 auto builder = OpBuilder::atBlockEnd(block);
5309 auto layerOp = builder.create<LayerOp>(info.getLoc(), id, *layerConvention);
5310 layerOp->getRegion(0).push_back(
new Block());
5312 layerOp->setAttr(
"output_file", outputDir);
5313 layerStack.push_back({indent, layerOp});
5317 if (parseOne(circuit.getBodyBlock()))
5321 while (getIndentation() > baseIndent) {
5322 switch (getToken().getKind()) {
5323 case FIRToken::kw_declgroup:
5324 case FIRToken::kw_layer: {
5327 while (layerStack.back().first >= getIndentation())
5328 layerStack.pop_back();
5329 auto parentLayer = layerStack.back().second;
5330 if (parseOne(&parentLayer.getBody().front()))
5335 return emitError(
"expected 'layer'"), failure();
5344 FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
5345 DeferredModuleToParse &deferredModule) {
5346 FModuleLike moduleOp = deferredModule.moduleOp;
5347 auto &body = moduleOp->getRegion(0).front();
5348 auto &portLocs = deferredModule.portLocs;
5352 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
5355 deferredModule.lexerCursor.restore(moduleBodyLexer);
5357 FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
5361 auto portList = moduleOp.getPorts();
5362 auto portArgs = body.getArguments();
5363 for (
auto tuple : llvm::zip(portList, portLocs, portArgs)) {
5364 PortInfo &port = std::get<0>(tuple);
5365 llvm::SMLoc loc = std::get<1>(tuple);
5366 BlockArgument portArg = std::get<2>(tuple);
5368 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
5372 hw::InnerSymbolNamespace modNameSpace(moduleOp);
5373 FIRStmtParser stmtParser(body, moduleContext, modNameSpace, circuitSymTbl,
5377 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
5383 size_t numVerifPrintfs = 0;
5384 std::optional<Location> printfLoc;
5386 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
5391 printfLoc = printFOp.getLoc();
5394 if (numVerifPrintfs > 0) {
5396 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
5398 <<
" printf-encoded verification operation(s), which are no longer "
5400 diag.attachNote(*printfLoc)
5401 <<
"example printf here, this is now just a printf and nothing more";
5402 diag.attachNote() <<
"For more information, see "
5403 "https://github.com/llvm/circt/issues/6970";
5419 ParseResult FIRCircuitParser::parseCircuit(
5420 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
5421 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBufs,
5422 mlir::TimingScope &ts) {
5424 auto indent = getIndentation();
5425 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
5427 if (!indent.has_value())
5428 return emitError(
"'FIRRTL' must be first token on its line");
5429 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
5430 parseVersionLit(
"expected version literal"))
5432 indent = getIndentation();
5434 if (!indent.has_value())
5435 return emitError(
"'circuit' must be first token on its line");
5436 unsigned circuitIndent = *indent;
5438 LocWithInfo info(getToken().getLoc(),
this);
5440 SMLoc inlineAnnotationsLoc;
5441 StringRef inlineAnnotations;
5444 if (parseToken(FIRToken::kw_circuit,
5445 "expected a top-level 'circuit' definition") ||
5446 parseId(name,
"expected circuit name") ||
5447 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
5448 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
5449 info.parseOptionalInfo())
5453 OpBuilder b(mlirModule.getBodyRegion());
5454 auto circuit = b.create<CircuitOp>(info.getLoc(), name);
5457 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
5463 SmallVector<Attribute> annos;
5464 if (!inlineAnnotations.empty())
5465 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
5469 for (
auto *annotationsBuf : annotationsBufs)
5470 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
5474 parseAnnotationTimer.stop();
5475 auto parseOMIRTimer = ts.nest(
"Parse OMIR");
5479 for (
auto *omirBuf : omirBufs)
5480 if (importOMIR(circuit, info.getFIRLoc(), omirBuf->getBuffer(), annos))
5483 parseOMIRTimer.stop();
5491 auto parseTimer = ts.nest(
"Parse modules");
5492 deferredModules.reserve(16);
5496 switch (getToken().getKind()) {
5504 case FIRToken::error:
5508 emitError(
"unexpected token in circuit");
5511 case FIRToken::kw_class:
5512 case FIRToken::kw_declgroup:
5513 case FIRToken::kw_extclass:
5514 case FIRToken::kw_extmodule:
5515 case FIRToken::kw_intmodule:
5516 case FIRToken::kw_layer:
5517 case FIRToken::kw_module:
5518 case FIRToken::kw_option:
5519 case FIRToken::kw_public:
5520 case FIRToken::kw_type: {
5521 auto indent = getIndentation();
5522 if (!indent.has_value())
5523 return emitError(
"'module' must be first token on its line"), failure();
5524 unsigned definitionIndent = *indent;
5526 if (definitionIndent <= circuitIndent)
5527 return emitError(
"module should be indented more"), failure();
5529 if (parseToplevelDefinition(circuit, definitionIndent))
5543 (void)getLexer().translateLocation(info.getFIRLoc());
5549 DenseMap<Attribute, Location> nameToOrigLoc;
5550 for (
auto &op : *circuit.getBodyBlock()) {
5553 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
5558 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
5561 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
5562 .attachNote(it.first->second)
5563 .append(
"see existing symbol definition here");
5569 SymbolTable circuitSymTbl(circuit);
5572 auto anyFailed = mlir::failableParallelForEachN(
5573 getContext(), 0, deferredModules.size(), [&](
size_t index) {
5574 if (parseModuleBody(circuitSymTbl, deferredModules[index]))
5578 if (failed(anyFailed))
5583 auto parseLayerName = [&](StringRef name) {
5585 auto [head, rest] = name.split(
"::");
5586 SmallVector<FlatSymbolRefAttr> nestedRefs;
5587 while (!rest.empty()) {
5589 std::tie(next, rest) = rest.split(
"::");
5595 auto parseLayers = [&](
const auto &layers) {
5596 SmallVector<Attribute> layersAttr;
5597 for (
const auto &layer : layers)
5598 layersAttr.push_back(parseLayerName(layer));
5599 if (layersAttr.empty())
5604 if (
auto enableLayers = parseLayers(getConstants().options.enableLayers))
5605 circuit.setEnableLayersAttr(enableLayers);
5606 if (
auto disableLayers = parseLayers(getConstants().options.disableLayers))
5607 circuit.setDisableLayersAttr(disableLayers);
5620 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
5621 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
5622 unsigned fileID = 1;
5624 annotationsBufs.push_back(
5625 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5627 SmallVector<const llvm::MemoryBuffer *> omirBufs;
5628 for (
unsigned e = sourceMgr.getNumBuffers(); fileID < e; ++fileID)
5630 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5632 context->loadDialect<CHIRRTLDialect>();
5633 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
5640 SharedParserConstants state(context, options);
5641 FIRLexer lexer(sourceMgr, context);
5643 .parseCircuit(annotationsBufs, omirBufs, ts))
5648 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
5649 if (failed(
verify(*module)))
5656 static mlir::TranslateToMLIRRegistration fromFIR(
5657 "import-firrtl",
"import .fir",
5658 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
5659 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
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 ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
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
This is the common base class between SIntType and UIntType.
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.
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
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.
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
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
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.
bool isRecognizedPrintfEncodedVerif(PrintFOp printOp)
Classifier for legacy verif intent captured in printf + when's.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
bool fromOMIRJSON(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Convert a JSON value containing OMIR JSON (an array of OMNodes), convert this to an OMIRAnnotation,...
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
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.
constexpr FIRVersion nextFIRVersion(3, 3, 0)
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.
@ IgnoreInfo
If this is set to true, the @info locators are ignored, and the locations are set to the location in ...
The FIRRTL specification version.
This holds the name and type that describes the module's ports.
bool isOutput() const
Return true if this is a simple output-only port.
StringRef getName() const