24 #include "mlir/IR/BuiltinOps.h"
25 #include "mlir/IR/BuiltinTypes.h"
26 #include "mlir/IR/Diagnostics.h"
27 #include "mlir/IR/ImplicitLocOpBuilder.h"
28 #include "mlir/IR/Threading.h"
29 #include "mlir/IR/Verifier.h"
30 #include "mlir/Support/Timing.h"
31 #include "mlir/Tools/mlir-translate/Translation.h"
32 #include "llvm/ADT/PointerEmbeddedInt.h"
33 #include "llvm/ADT/STLExtras.h"
34 #include "llvm/ADT/SmallPtrSet.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/StringSet.h"
37 #include "llvm/ADT/StringSwitch.h"
38 #include "llvm/ADT/TypeSwitch.h"
39 #include "llvm/Support/JSON.h"
40 #include "llvm/Support/SourceMgr.h"
41 #include "llvm/Support/raw_ostream.h"
44 using namespace circt;
45 using namespace firrtl;
46 using namespace chirrtl;
49 using llvm::SourceMgr;
50 using mlir::LocationAttr;
63 struct SharedParserConstants {
65 : context(context), options(options),
66 emptyArrayAttr(ArrayAttr::
get(context, {})),
74 MLIRContext *
const context;
80 llvm::StringMap<FIRRTLType> aliasMap;
83 llvm::DenseMap<StringRef, ClassLike> classMap;
86 const ArrayAttr emptyArrayAttr;
89 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
90 const StringAttr fieldIndexIdentifier, indexIdentifier;
93 SharedParserConstants(
const SharedParserConstants &) =
delete;
94 void operator=(
const SharedParserConstants &) =
delete;
107 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
109 : version(version), constants(constants), lexer(lexer),
110 locatorFilenameCache(constants.loIdentifier ) {
114 SharedParserConstants &getConstants()
const {
return constants; }
115 MLIRContext *getContext()
const {
return constants.context; }
117 FIRLexer &getLexer() {
return lexer; }
120 std::optional<unsigned> getIndentation()
const {
125 const FIRToken &getToken()
const {
return lexer.getToken(); }
126 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
133 InFlightDiagnostic emitError(
const Twine &message = {}) {
134 return emitError(getToken().getLoc(), message);
136 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
139 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
140 return emitWarning(getToken().getLoc(), message);
143 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
153 Location translateLocation(llvm::SMLoc loc) {
154 return lexer.translateLocation(loc);
159 ParseResult parseOptionalInfoLocator(LocationAttr &result);
163 ParseResult parseOptionalName(StringAttr &name);
169 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
170 if (version < minimum)
171 return emitError() << feature <<
" are a FIRRTL " << minimum
172 <<
"+ feature, but the specified FIRRTL version was "
183 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
192 if (getToken().isNot(kind))
202 FIRToken consumedToken = getToken();
203 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
204 "shouldn't advance past EOF or errors");
206 return consumedToken;
215 FIRToken consumedToken = getToken();
216 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
218 return consumedToken;
223 ParseResult parseGetSpelling(StringRef &spelling) {
224 spelling = getTokenSpelling();
230 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
234 const std::function<ParseResult()> &parseElement);
241 ParseResult parseIntLit(APInt &result,
const Twine &message);
242 ParseResult parseIntLit(int64_t &result,
const Twine &message);
243 ParseResult parseIntLit(int32_t &result,
const Twine &message);
246 ParseResult parseVersionLit(
const Twine &message);
249 template <
typename T>
250 ParseResult parseOptionalWidth(T &result);
253 ParseResult parseId(StringRef &result,
const Twine &message);
254 ParseResult parseId(StringAttr &result,
const Twine &message);
255 ParseResult parseFieldId(StringRef &result,
const Twine &message);
256 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
257 const Twine &message);
258 ParseResult parseEnumType(
FIRRTLType &result);
259 ParseResult parseListType(
FIRRTLType &result);
263 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
265 ParseResult parseOptionalRUW(RUWAttr &result);
271 FIRParser(
const FIRParser &) =
delete;
272 void operator=(
const FIRParser &) =
delete;
276 SharedParserConstants &constants;
280 StringAttr locatorFilenameCache;
282 FileLineColLoc fileLineColLocCache;
291 InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
292 auto diag = mlir::emitError(translateLocation(loc), message);
296 if (getToken().is(FIRToken::error))
301 InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
302 return mlir::emitWarning(translateLocation(loc), message);
312 const Twine &message) {
313 if (consumeIf(expectedToken))
315 return emitError(message);
321 const std::function<ParseResult()> &parseElement) {
323 while (!consumeIf(rightToken)) {
341 : parser(parser), firLoc(firLoc) {}
348 auto result = parser->translateLocation(firLoc);
356 if (failed(parser->parseOptionalInfoLocator(loc)))
360 switch (parser->constants.options.infoLocatorHandling) {
361 case ILH::IgnoreInfo:
362 assert(0 &&
"Should not return info locations if ignoring");
364 case ILH::PreferInfo:
369 {loc, parser->translateLocation(firLoc)});
396 ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
397 if (getToken().isNot(FIRToken::fileinfo))
400 auto loc = getToken().getLoc();
402 auto spelling = getTokenSpelling();
403 consumeToken(FIRToken::fileinfo);
407 constants.options.infoLocatorHandling ==
409 locatorFilenameCache, fileLineColLocCache, getContext());
412 if (!locationPair.first) {
413 mlir::emitWarning(translateLocation(loc),
414 "ignoring unknown @ info record format");
420 if (locationPair.first && constants.options.infoLocatorHandling ==
425 result = *locationPair.second;
433 ParseResult FIRParser::parseOptionalName(StringAttr &name) {
435 if (getToken().isNot(FIRToken::colon)) {
440 consumeToken(FIRToken::colon);
442 if (parseId(nameRef,
"expected result name"))
456 ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
458 if (getToken().isNot(FIRToken::inlineannotation))
461 loc = getToken().getLoc();
463 result = getTokenSpelling().drop_front(2).drop_back(1);
464 consumeToken(FIRToken::inlineannotation);
482 ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
483 auto spelling = getTokenSpelling();
484 bool isNegative =
false;
485 switch (getToken().getKind()) {
486 case FIRToken::signed_integer:
487 isNegative = spelling[0] ==
'-';
488 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
489 spelling = spelling.drop_front();
491 case FIRToken::integer:
492 if (spelling.getAsInteger(10, result))
493 return emitError(message), failure();
497 if (result.isNegative())
498 result = result.zext(result.getBitWidth() + 1);
507 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
508 result = result.trunc(32);
512 case FIRToken::radix_specified_integer: {
513 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
515 if (spelling[0] ==
'-') {
517 spelling = spelling.drop_front();
519 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
524 spelling = spelling.drop_front(2);
525 if (spelling.getAsInteger(base, result))
526 return emitError(
"invalid character in integer literal"), failure();
527 if (result.isNegative())
528 result = result.zext(result.getBitWidth() + 1);
534 case FIRToken::string: {
537 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
540 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
541 spelling = spelling.drop_back().drop_front();
545 switch (spelling.empty() ?
' ' : spelling.front()) {
556 return emitError(
"expected base specifier (h/o/b) in integer literal"),
559 spelling = spelling.drop_front();
562 bool isNegative =
false;
563 if (!spelling.empty() && spelling.front() ==
'+')
564 spelling = spelling.drop_front();
565 else if (!spelling.empty() && spelling.front() ==
'-') {
567 spelling = spelling.drop_front();
571 if (spelling.empty())
572 return emitError(
"expected digits in integer literal"), failure();
574 if (spelling.getAsInteger(base, result))
575 return emitError(
"invalid character in integer literal"), failure();
580 if (result.isNegative())
581 result = result.zext(result.getBitWidth() + 1);
586 consumeToken(FIRToken::string);
591 return emitError(
"expected integer literal"), failure();
595 ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
597 auto loc = getToken().getLoc();
598 if (parseIntLit(value, message))
601 result = (int64_t)value.getLimitedValue(INT64_MAX);
603 return emitError(loc,
"value is too big to handle"), failure();
607 ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
609 auto loc = getToken().getLoc();
610 if (parseIntLit(value, message))
613 result = (int32_t)value.getLimitedValue(INT32_MAX);
615 return emitError(loc,
"value is too big to handle"), failure();
621 ParseResult FIRParser::parseVersionLit(
const Twine &message) {
622 auto spelling = getTokenSpelling();
623 if (getToken().getKind() != FIRToken::version)
624 return emitError(message), failure();
626 auto [a, d] = spelling.split(
".");
627 auto [b, c] = d.split(
".");
628 APInt aInt, bInt, cInt;
629 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
630 c.getAsInteger(10, cInt))
631 return emitError(
"failed to parse version string"), failure();
632 version.major = aInt.getLimitedValue(UINT32_MAX);
633 version.minor = bInt.getLimitedValue(UINT32_MAX);
634 version.patch = cInt.getLimitedValue(UINT32_MAX);
635 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
636 return emitError(
"integers out of range"), failure();
640 consumeToken(FIRToken::version);
647 template <
typename T>
648 ParseResult FIRParser::parseOptionalWidth(T &result) {
649 if (!consumeIf(FIRToken::less))
650 return result = -1, success();
653 auto widthLoc = getToken().getLoc();
654 if (parseIntLit(result,
"expected width") ||
655 parseToken(FIRToken::greater,
"expected >"))
659 return emitError(widthLoc,
"invalid width specifier"), failure();
668 ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
669 switch (getToken().getKind()) {
671 case FIRToken::identifier:
672 case FIRToken::literal_identifier:
674 #define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
675 #include "FIRTokenKinds.def"
680 if (getToken().getKind() == FIRToken::literal_identifier)
681 result = getTokenSpelling().drop_front().drop_back();
683 result = getTokenSpelling();
693 ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
695 if (parseId(name, message))
707 ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
709 result = getTokenSpelling();
710 if (consumeIf(FIRToken::integer))
716 if (parseId(result, message))
728 ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
729 const Twine &message) {
731 StringRef tmp = getTokenSpelling();
733 if (consumeIf(FIRToken::integer)) {
734 result.push_back(tmp);
738 if (consumeIf(FIRToken::floatingpoint)) {
742 auto [a, b] = tmp.split(
".");
748 if (consumeIf(FIRToken::version)) {
750 auto [a, d] = tmp.split(
".");
751 auto [b, c] = d.split(
".");
759 if (parseId(tmp, message))
761 result.push_back(tmp);
767 ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
768 if (parseToken(FIRToken::l_brace_bar,
769 "expected leading '{|' in enumeration type"))
771 SmallVector<FEnumType::EnumElement> elements;
772 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
773 auto fieldLoc = getToken().getLoc();
777 if (parseId(name,
"expected valid identifier for enumeration tag"))
782 if (consumeIf(FIRToken::colon)) {
784 if (
parseType(parsedType,
"expected enumeration type"))
786 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
788 return emitError(fieldLoc,
"field must be a base type");
801 ParseResult FIRParser::parsePropertyType(
PropertyType &result,
802 const Twine &message) {
806 auto prop = type_dyn_cast<PropertyType>(type);
808 return emitError(
"expected property type");
814 ParseResult FIRParser::parseListType(
FIRRTLType &result) {
815 consumeToken(FIRToken::kw_List);
818 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
819 parsePropertyType(
elementType,
"expected List element type") ||
820 parseToken(FIRToken::greater,
"expected '>' in List type"))
828 ParseResult FIRParser::parseMapType(
FIRRTLType &result) {
829 consumeToken(FIRToken::kw_Map);
832 if (parseToken(FIRToken::less,
"expected '<' in Map type") ||
833 parsePropertyType(key,
"expected Map key type") ||
834 parsePropertyType(value,
"expected Map value type") ||
835 parseToken(FIRToken::greater,
"expected '>' in Map type"))
862 switch (getToken().getKind()) {
864 return emitError(message), failure();
866 case FIRToken::kw_Clock:
867 consumeToken(FIRToken::kw_Clock);
871 case FIRToken::kw_Inst: {
872 if (requireFeature({3, 2, 0},
"Inst types"))
875 consumeToken(FIRToken::kw_Inst);
876 if (parseToken(FIRToken::less,
"expected < in Inst type"))
879 auto loc = getToken().getLoc();
881 if (parseId(
id,
"expected class name in Inst type"))
885 const auto &classMap = getConstants().classMap;
886 auto lookup = classMap.find(
id);
887 if (lookup == classMap.end())
888 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
890 auto classOp = lookup->second;
892 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
895 result = classOp.getInstanceType();
899 case FIRToken::kw_AnyRef: {
900 if (requireFeature({3, 2, 0},
"AnyRef types"))
903 consumeToken(FIRToken::kw_AnyRef);
908 case FIRToken::kw_Reset:
909 consumeToken(FIRToken::kw_Reset);
913 case FIRToken::kw_AsyncReset:
914 consumeToken(FIRToken::kw_AsyncReset);
918 case FIRToken::kw_UInt:
919 case FIRToken::kw_SInt:
920 case FIRToken::kw_Analog: {
921 auto kind = getToken().getKind();
926 if (parseOptionalWidth(
width))
929 if (kind == FIRToken::kw_SInt)
931 else if (kind == FIRToken::kw_UInt)
934 assert(kind == FIRToken::kw_Analog);
940 case FIRToken::kw_Probe:
941 case FIRToken::kw_RWProbe: {
942 auto kind = getToken().getKind();
943 auto loc = getToken().getLoc();
947 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
948 parseType(type,
"expected probe data type") ||
949 parseToken(FIRToken::greater,
"expected '>' in reference type"))
952 bool forceable = kind == FIRToken::kw_RWProbe;
954 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
956 return emitError(loc,
"cannot nest reference types");
959 return emitError(loc,
"probe inner type must be passive");
961 if (forceable &&
innerType.containsConst())
962 return emitError(loc,
"rwprobe cannot contain const");
968 case FIRToken::l_brace: {
969 consumeToken(FIRToken::l_brace);
971 SmallVector<OpenBundleType::BundleElement, 4> elements;
972 bool bundleCompatible =
true;
973 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
974 bool isFlipped = consumeIf(FIRToken::kw_flip);
978 if (parseFieldId(fieldName,
"expected bundle field name") ||
979 parseToken(FIRToken::colon,
"expected ':' in bundle"))
981 if (
parseType(type,
"expected bundle field type"))
986 bundleCompatible &= isa<BundleType::ElementType>(type);
992 if (bundleCompatible) {
993 auto bundleElements = llvm::map_range(elements, [](
auto element) {
994 return BundleType::BundleElement{
995 element.name, element.isFlip,
996 cast<BundleType::ElementType>(element.type)};
998 result =
BundleType::get(getContext(), llvm::to_vector(bundleElements));
1004 case FIRToken::l_brace_bar: {
1005 if (parseEnumType(result))
1010 case FIRToken::identifier: {
1012 auto loc = getToken().getLoc();
1013 if (parseId(
id,
"expected a type alias name"))
1015 auto it = constants.aliasMap.find(
id);
1016 if (it == constants.aliasMap.end()) {
1017 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1020 result = it->second;
1024 case FIRToken::kw_const: {
1025 consumeToken(FIRToken::kw_const);
1026 auto nextToken = getToken();
1027 auto loc = nextToken.getLoc();
1030 if (nextToken.is(FIRToken::kw_const))
1031 return emitError(loc,
"'const' can only be specified once on a type");
1036 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1038 return emitError(loc,
"only hardware types can be 'const'");
1040 result = baseType.getConstType(
true);
1044 case FIRToken::kw_String:
1045 if (requireFeature({3, 1, 0},
"Strings"))
1047 consumeToken(FIRToken::kw_String);
1050 case FIRToken::kw_Integer:
1051 if (requireFeature({3, 1, 0},
"Integers"))
1053 consumeToken(FIRToken::kw_Integer);
1056 case FIRToken::kw_Bool:
1057 if (requireFeature({3, 2, 0},
"Bools"))
1059 consumeToken(FIRToken::kw_Bool);
1062 case FIRToken::kw_Double:
1063 if (requireFeature({3, 2, 0},
"Doubles"))
1065 consumeToken(FIRToken::kw_Double);
1068 case FIRToken::kw_Path:
1069 if (requireFeature({3, 1, 0},
"Paths"))
1071 consumeToken(FIRToken::kw_Path);
1074 case FIRToken::kw_List:
1075 if (requireFeature({3, 2, 0},
"Lists") || parseListType(result))
1078 case FIRToken::kw_Map:
1079 if (requireFeature({3, 2, 0},
"Maps") || parseMapType(result))
1085 while (consumeIf(FIRToken::l_square)) {
1086 auto sizeLoc = getToken().getLoc();
1088 if (parseIntLit(
size,
"expected width") ||
1089 parseToken(FIRToken::r_square,
"expected ]"))
1093 return emitError(sizeLoc,
"invalid size specifier"), failure();
1095 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1106 ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1107 switch (getToken().getKind()) {
1111 case FIRToken::kw_old:
1112 result = RUWAttr::Old;
1113 consumeToken(FIRToken::kw_old);
1115 case FIRToken::kw_new:
1116 result = RUWAttr::New;
1117 consumeToken(FIRToken::kw_new);
1119 case FIRToken::kw_undefined:
1120 result = RUWAttr::Undefined;
1121 consumeToken(FIRToken::kw_undefined);
1139 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1147 struct UnbundledValueRestorer {
1149 size_t startingSize;
1151 startingSize = list.size();
1153 ~UnbundledValueRestorer() { list.resize(startingSize); }
1162 struct FIRModuleContext :
public FIRParser {
1163 explicit FIRModuleContext(SharedParserConstants &constants,
FIRLexer &lexer,
1165 : FIRParser(constants, lexer, version) {}
1171 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1174 Value getCachedConstantInt(ImplicitLocOpBuilder &
builder, Attribute attr,
1176 auto &result = constantCache[{attr, type}];
1182 OpBuilder::InsertPoint savedIP;
1184 auto *parentOp =
builder.getInsertionBlock()->getParentOp();
1185 if (!isa<FModuleOp>(parentOp)) {
1186 savedIP =
builder.saveInsertionPoint();
1187 while (!isa<FModuleOp>(parentOp)) {
1188 builder.setInsertionPoint(parentOp);
1189 parentOp =
builder.getInsertionBlock()->getParentOp();
1193 result =
builder.create<ConstantOp>(type, value);
1195 if (savedIP.isSet())
1196 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1207 Value &getCachedSubaccess(Value value,
unsigned index) {
1208 auto &result = subaccessCache[{value, index}];
1211 auto it = scopeMap.find(value.getParentBlock());
1212 if (it != scopeMap.end())
1213 it->second->scopedSubaccesses.push_back({result, index});
1223 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1224 bool insertNameIntoGlobalScope =
false);
1225 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1226 bool insertNameIntoGlobalScope =
false) {
1228 insertNameIntoGlobalScope);
1233 SMLoc loc,
bool fatal =
true);
1238 StringRef field, SMLoc loc);
1246 assert(index < unbundledValues.size());
1247 return unbundledValues[index];
1257 struct ContextScope {
1258 friend struct FIRModuleContext;
1259 ContextScope(FIRModuleContext &moduleContext, Block *block)
1260 : moduleContext(moduleContext), block(block),
1261 previousScope(moduleContext.currentScope) {
1262 moduleContext.currentScope =
this;
1263 moduleContext.scopeMap[block] =
this;
1268 for (
auto *entryPtr : scopedDecls)
1269 entryPtr->second.first = SMLoc();
1272 for (
auto subaccess : scopedSubaccesses)
1273 moduleContext.subaccessCache.erase(subaccess);
1275 moduleContext.scopeMap.erase(block);
1277 moduleContext.currentScope = previousScope;
1281 void operator=(
const ContextScope &) =
delete;
1282 ContextScope(
const ContextScope &) =
delete;
1284 FIRModuleContext &moduleContext;
1286 ContextScope *previousScope;
1287 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1288 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1302 DenseMap<Block *, ContextScope *> scopeMap;
1307 ContextScope *currentScope =
nullptr;
1318 ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1320 bool insertNameIntoGlobalScope) {
1325 if (entryIt->second.first.isValid()) {
1326 emitError(loc,
"redefinition of name '" + name +
"'")
1327 .attachNote(translateLocation(entryIt->second.first))
1328 <<
"previous definition here";
1334 entryIt->second = {loc, entry};
1335 if (currentScope && !insertNameIntoGlobalScope)
1336 currentScope->scopedDecls.push_back(&*entryIt);
1344 StringRef name, SMLoc loc) {
1345 auto &entry = symbolTable[name];
1346 if (!entry.first.isValid())
1347 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1348 result = entry.second;
1349 assert(result &&
"name in symbol table without definition");
1353 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1355 SMLoc loc,
bool fatal) {
1356 if (!entry.is<Value>()) {
1358 emitError(loc,
"bundle value should only be used from subfield");
1361 result = entry.get<Value>();
1365 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1367 StringRef fieldName,
1370 emitError(loc,
"value should not be used from subfield");
1376 unsigned unbundledId = entry.get<
UnbundledID>() - 1;
1377 assert(unbundledId < unbundledValues.size());
1379 for (
auto elt : ubEntry) {
1380 if (elt.first == fieldAttr) {
1381 result = elt.second;
1386 emitError(loc,
"use of invalid field name '")
1387 << fieldName <<
"' on bundle value";
1413 struct LazyLocationListener :
public OpBuilder::Listener {
1419 ~LazyLocationListener() {
1420 assert(subOps.empty() &&
"didn't process parsed operations");
1425 void startStatement() {
1426 assert(!isActive &&
"Already processing a statement");
1432 void endStatement(FIRParser &parser) {
1433 assert(isActive &&
"Not parsing a statement");
1437 for (
auto opAndSMLoc : subOps) {
1441 switch (parser.getConstants().options.infoLocatorHandling) {
1442 case ILH::IgnoreInfo:
1444 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1446 case ILH::PreferInfo:
1447 opAndSMLoc.first->setLoc(infoLoc);
1449 case ILH::FusedInfo:
1451 infoLoc.getContext(),
1452 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1459 for (
auto opAndSMLoc : subOps)
1460 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1465 infoLoc = LocationAttr();
1466 currentSMLoc = SMLoc();
1471 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1474 void setInfoLoc(LocationAttr loc) {
1475 assert(!infoLoc &&
"Info location multiply specified");
1481 void notifyOperationInserted(Operation *op)
override {
1482 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1483 assert(isActive &&
"Not parsing a statement");
1484 subOps.push_back({op, currentSMLoc});
1489 bool isActive =
false;
1497 LocationAttr infoLoc;
1504 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1506 void operator=(
const LazyLocationListener &) =
delete;
1507 LazyLocationListener(
const LazyLocationListener &) =
delete;
1514 struct FIRStmtParser :
public FIRParser {
1515 explicit FIRStmtParser(Block &blockToInsertInto,
1516 FIRModuleContext &moduleContext,
1517 hw::InnerSymbolNamespace &modNameSpace,
1518 FIRVersion version, SymbolRefAttr groupSym = {})
1519 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1522 locationProcessor(this->builder), moduleContext(moduleContext),
1523 modNameSpace(modNameSpace), groupSym(groupSym) {
1524 builder.setInsertionPointToEnd(&blockToInsertInto);
1527 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1528 ParseResult parseSimpleStmtBlock(
unsigned indent);
1531 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1534 void emitInvalidate(Value val,
Flow flow);
1540 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1543 void emitPartialConnect(ImplicitLocOpBuilder &
builder, Value dst, Value src);
1546 ParseResult parseOptionalInfo() {
1548 if (failed(parseOptionalInfoLocator(loc)))
1550 locationProcessor.setInfoLoc(loc);
1555 ParseResult parseExpImpl(Value &result,
const Twine &message,
1556 bool isLeadingStmt);
1557 ParseResult parseExp(Value &result,
const Twine &message) {
1558 return parseExpImpl(result, message,
false);
1560 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1561 return parseExpImpl(result, message,
true);
1563 ParseResult parseEnumExp(Value &result);
1564 ParseResult parsePathExp(Value &result);
1565 ParseResult parseRefExp(Value &result,
const Twine &message);
1566 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1568 template <
typename subop>
1570 ArrayRef<NamedAttribute> attrs,
1571 unsigned indexNo, SMLoc loc);
1572 ParseResult parseOptionalExpPostscript(Value &result,
1573 bool allowDynamic =
true);
1574 ParseResult parsePostFixFieldId(Value &result);
1575 ParseResult parsePostFixIntSubscript(Value &result);
1576 ParseResult parsePostFixDynamicSubscript(Value &result);
1577 ParseResult parsePrimExp(Value &result);
1578 ParseResult parseIntegerLiteralExp(Value &result);
1579 ParseResult parseListExp(Value &result);
1580 ParseResult parseMapExp(Value &result);
1582 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
1585 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
1586 SymbolRefAttr groupSym);
1587 ParseResult parseAttach();
1588 ParseResult parseMemPort(MemDirAttr direction);
1589 ParseResult parsePrintf();
1590 ParseResult parseSkip();
1591 ParseResult parseStop();
1592 ParseResult parseAssert();
1593 ParseResult parseAssume();
1594 ParseResult parseCover();
1595 ParseResult parseWhen(
unsigned whenIndent);
1596 ParseResult parseMatch(
unsigned matchIndent);
1597 ParseResult parseRefDefine();
1598 ParseResult parseRefForce();
1599 ParseResult parseRefForceInitial();
1600 ParseResult parseRefRelease();
1601 ParseResult parseRefReleaseInitial();
1602 ParseResult parseRefRead(Value &result);
1603 ParseResult parseProbe(Value &result);
1604 ParseResult parsePropAssign();
1605 ParseResult parseRWProbe(Value &result);
1606 ParseResult parseLeadingExpStmt(Value lhs);
1607 ParseResult parseConnect();
1608 ParseResult parseInvalidate();
1609 ParseResult parseGroup(
unsigned indent);
1612 ParseResult parseInstance();
1613 ParseResult parseObject();
1614 ParseResult parseCombMem();
1615 ParseResult parseSeqMem();
1616 ParseResult parseMem(
unsigned memIndent);
1617 ParseResult parseNode();
1618 ParseResult parseWire();
1619 ParseResult parseRegister(
unsigned regIndent);
1620 ParseResult parseRegisterWithReset();
1624 LazyLocationListener locationProcessor;
1627 FIRModuleContext &moduleContext;
1629 hw::InnerSymbolNamespace &modNameSpace;
1633 SymbolRefAttr groupSym;
1640 void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
1641 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
1648 auto props = tpe.getRecursiveTypeProperties();
1649 if (props.isPassive && !props.containsAnalog) {
1663 TypeSwitch<FIRRTLType>(tpe)
1664 .Case<BundleType>([&](
auto tpe) {
1665 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
1666 auto &subfield = moduleContext.getCachedSubaccess(val, i);
1668 OpBuilder::InsertionGuard guard(
builder);
1669 builder.setInsertionPointAfterValue(val);
1670 subfield =
builder.create<SubfieldOp>(val, i);
1672 emitInvalidate(subfield,
1673 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
1676 .Case<FVectorType>([&](
auto tpe) {
1677 auto tpex = tpe.getElementType();
1678 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
1679 auto &subindex = moduleContext.getCachedSubaccess(val, i);
1681 OpBuilder::InsertionGuard guard(
builder);
1682 builder.setInsertionPointAfterValue(val);
1683 subindex =
builder.create<SubindexOp>(tpex, val, i);
1685 emitInvalidate(subindex, flow);
1690 void FIRStmtParser::emitPartialConnect(ImplicitLocOpBuilder &
builder, Value dst,
1692 auto dstType = type_dyn_cast<FIRRTLBaseType>(dst.getType());
1693 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
1694 if (!dstType || !srcType)
1697 if (type_isa<AnalogType>(dstType)) {
1698 builder.create<AttachOp>(ArrayRef<Value>{dst, src});
1699 }
else if (dstType == srcType && !dstType.containsAnalog()) {
1701 }
else if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
1702 auto srcBundle = type_cast<BundleType>(srcType);
1704 for (
size_t dstIndex = 0; dstIndex <
numElements; ++dstIndex) {
1706 auto &dstElement = dstBundle.getElements()[dstIndex];
1707 auto name = dstElement.name;
1708 auto maybe = srcBundle.getElementIndex(name);
1712 auto dstRef = moduleContext.getCachedSubaccess(dst, dstIndex);
1714 OpBuilder::InsertionGuard guard(
builder);
1715 builder.setInsertionPointAfterValue(dst);
1716 dstRef =
builder.create<SubfieldOp>(dst, dstIndex);
1721 auto dstField = dstRef;
1722 auto srcIndex = *maybe;
1723 auto &srcField = moduleContext.getCachedSubaccess(src, srcIndex);
1725 OpBuilder::InsertionGuard guard(
builder);
1726 builder.setInsertionPointAfterValue(src);
1727 srcField =
builder.create<SubfieldOp>(src, srcIndex);
1729 if (!dstElement.isFlip)
1730 emitPartialConnect(
builder, dstField, srcField);
1732 emitPartialConnect(
builder, srcField, dstField);
1734 }
else if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
1735 auto srcVector = type_cast<FVectorType>(srcType);
1736 auto dstNumElements = dstVector.getNumElements();
1737 auto srcNumEelemnts = srcVector.getNumElements();
1739 auto numElements = std::min(dstNumElements, srcNumEelemnts);
1741 auto &dstRef = moduleContext.getCachedSubaccess(dst, i);
1743 OpBuilder::InsertionGuard guard(
builder);
1744 builder.setInsertionPointAfterValue(dst);
1745 dstRef =
builder.create<SubindexOp>(dst, i);
1747 auto dstField = dstRef;
1748 auto &srcField = moduleContext.getCachedSubaccess(src, i);
1750 OpBuilder::InsertionGuard guard(
builder);
1751 builder.setInsertionPointAfterValue(src);
1752 srcField =
builder.create<SubindexOp>(src, i);
1754 emitPartialConnect(
builder, dstField, srcField);
1784 ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
1785 bool isLeadingStmt) {
1786 switch (getToken().getKind()) {
1789 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
1790 case FIRToken::lp_##SPELLING:
1791 #include "FIRTokenKinds.def"
1792 if (parsePrimExp(result))
1796 case FIRToken::l_brace_bar:
1798 return emitError(
"unexpected enumeration as start of statement");
1799 if (parseEnumExp(result))
1802 case FIRToken::lp_read:
1804 return emitError(
"unexpected read() as start of statement");
1805 if (parseRefRead(result))
1808 case FIRToken::lp_probe:
1810 return emitError(
"unexpected probe() as start of statement");
1811 if (parseProbe(result))
1814 case FIRToken::lp_rwprobe:
1816 return emitError(
"unexpected rwprobe() as start of statement");
1817 if (parseRWProbe(result))
1821 case FIRToken::kw_UInt:
1822 case FIRToken::kw_SInt:
1823 if (parseIntegerLiteralExp(result))
1826 case FIRToken::kw_String: {
1827 if (requireFeature({3, 1, 0},
"Strings"))
1829 locationProcessor.setLoc(getToken().getLoc());
1830 consumeToken(FIRToken::kw_String);
1832 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
1833 parseGetSpelling(spelling) ||
1834 parseToken(FIRToken::string,
1835 "expected string literal in String expression") ||
1836 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
1838 result =
builder.create<StringConstantOp>(
1842 case FIRToken::kw_Integer: {
1843 if (requireFeature({3, 1, 0},
"Integers"))
1845 locationProcessor.setLoc(getToken().getLoc());
1846 consumeToken(FIRToken::kw_Integer);
1848 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
1849 parseIntLit(value,
"expected integer literal in Integer expression") ||
1850 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
1853 builder.create<FIntegerConstantOp>(APSInt(value,
false));
1856 case FIRToken::kw_Bool: {
1857 if (requireFeature({3, 2, 0},
"Bools"))
1859 locationProcessor.setLoc(getToken().getLoc());
1860 consumeToken(FIRToken::kw_Bool);
1861 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
1864 if (consumeIf(FIRToken::kw_true))
1866 else if (consumeIf(FIRToken::kw_false))
1869 return emitError(
"expected true or false in Bool expression");
1870 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
1872 result =
builder.create<BoolConstantOp>(value);
1875 case FIRToken::kw_Double: {
1876 if (requireFeature({3, 2, 0},
"Doubles"))
1878 locationProcessor.setLoc(getToken().getLoc());
1879 consumeToken(FIRToken::kw_Double);
1880 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
1882 auto spelling = getTokenSpelling();
1883 if (parseToken(FIRToken::floatingpoint,
1884 "expected floating point in Double expression") ||
1885 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
1890 if (!llvm::to_float(spelling, d))
1891 return emitError(
"invalid double");
1892 result =
builder.create<DoubleConstantOp>(
builder.getF64FloatAttr(d));
1895 case FIRToken::kw_List: {
1896 if (requireFeature({3, 2, 0},
"Lists"))
1899 return emitError(
"unexpected List<>() as start of statement");
1900 if (parseListExp(result))
1904 case FIRToken::kw_Map: {
1905 if (requireFeature({3, 2, 0},
"Maps"))
1908 return emitError(
"unexpected Map<>() as start of statement");
1909 if (parseMapExp(result))
1913 case FIRToken::lp_path:
1915 return emitError(
"unexpected path() as start of statement");
1916 if (requireFeature({3, 2, 0},
"paths") || parsePathExp(result))
1922 case FIRToken::identifier:
1923 case FIRToken::literal_identifier:
1926 auto loc = getToken().getLoc();
1928 if (parseId(name, message) ||
1929 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
1933 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
1941 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
1942 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
1943 parseOptionalInfo())
1946 locationProcessor.setLoc(loc);
1948 unsigned unbundledId = symtabEntry.get<
UnbundledID>() - 1;
1950 moduleContext.getUnbundledEntry(unbundledId);
1951 for (
auto elt : ubEntry)
1952 emitInvalidate(elt.second);
1960 StringRef fieldName;
1961 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
1962 parseFieldId(fieldName,
"expected field name") ||
1963 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
1969 return parseOptionalExpPostscript(result);
1979 ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
1980 bool allowDynamic) {
1985 if (consumeIf(FIRToken::period)) {
1986 if (parsePostFixFieldId(result))
1993 if (consumeIf(FIRToken::l_square)) {
1994 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
1995 if (parsePostFixIntSubscript(result))
2000 return emitError(
"subaccess not allowed here");
2001 if (parsePostFixDynamicSubscript(result))
2011 template <
typename subop>
2013 FIRStmtParser::emitCachedSubAccess(Value base, ArrayRef<NamedAttribute> attrs,
2014 unsigned indexNo, SMLoc loc) {
2017 auto resultType = subop::inferReturnType({base}, attrs, {});
2020 (void)subop::inferReturnType({base}, attrs, translateLocation(loc));
2025 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2031 locationProcessor.setLoc(loc);
2032 OpBuilder::InsertionGuard guard(
builder);
2033 builder.setInsertionPointAfterValue(base);
2034 auto op =
builder.create<subop>(resultType, base, attrs);
2037 return value = op.getResult();
2044 ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2045 auto loc = getToken().getLoc();
2046 SmallVector<StringRef, 3> fields;
2047 if (parseFieldIdSeq(fields,
"expected field name"))
2049 for (
auto fieldName : fields) {
2050 std::optional<unsigned> indexV;
2051 auto type = result.getType();
2052 if (
auto refTy = type_dyn_cast<RefType>(type))
2053 type = refTy.getType();
2054 if (
auto bundle = type_dyn_cast<BundleType>(type))
2055 indexV = bundle.getElementIndex(fieldName);
2056 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2057 indexV = bundle.getElementIndex(fieldName);
2058 else if (
auto klass = type_dyn_cast<ClassType>(type))
2059 indexV = klass.getElementIndex(fieldName);
2061 return emitError(loc,
"subfield requires bundle or object operand ");
2063 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2064 << result.getType();
2065 auto indexNo = *indexV;
2068 if (type_isa<RefType>(result.getType())) {
2069 NamedAttribute attrs = {getConstants().indexIdentifier,
2070 builder.getI32IntegerAttr(indexNo)};
2071 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2072 }
else if (type_isa<ClassType>(type)) {
2073 NamedAttribute attrs = {getConstants().indexIdentifier,
2074 builder.getI32IntegerAttr(indexNo)};
2076 emitCachedSubAccess<ObjectSubfieldOp>(result, attrs, indexNo, loc);
2078 NamedAttribute attrs = {getConstants().fieldIndexIdentifier,
2079 builder.getI32IntegerAttr(indexNo)};
2080 if (type_isa<BundleType>(type))
2082 emitCachedSubAccess<SubfieldOp>(result, attrs, indexNo, loc);
2085 emitCachedSubAccess<OpenSubfieldOp>(result, attrs, indexNo, loc);
2088 if (failed(subResult))
2090 result = *subResult;
2099 ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2100 auto loc = getToken().getLoc();
2102 if (parseIntLit(indexNo,
"expected index") ||
2103 parseToken(FIRToken::r_square,
"expected ']'"))
2107 return emitError(loc,
"invalid index specifier"), failure();
2113 NamedAttribute attrs = {getConstants().indexIdentifier,
2114 builder.getI32IntegerAttr(indexNo)};
2117 if (type_isa<RefType>(result.getType()))
2118 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2119 else if (type_isa<FVectorType>(result.getType()))
2120 subResult = emitCachedSubAccess<SubindexOp>(result, attrs, indexNo, loc);
2123 emitCachedSubAccess<OpenSubindexOp>(result, attrs, indexNo, loc);
2125 if (failed(subResult))
2127 result = *subResult;
2135 ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2136 auto loc = getToken().getLoc();
2138 if (parseExp(index,
"expected subscript index expression") ||
2139 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2143 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2145 return emitError(
"expected base type for index expression");
2146 indexType = indexType.getPassiveType();
2147 locationProcessor.setLoc(loc);
2151 auto resultType = SubaccessOp::inferReturnType({result, index}, {}, {});
2154 (void)SubaccessOp::inferReturnType({result, index}, {},
2155 translateLocation(loc));
2160 auto op =
builder.create<SubaccessOp>(resultType, result, index);
2161 result = op.getResult();
2166 ParseResult FIRStmtParser::parsePrimExp(Value &result) {
2167 auto kind = getToken().getKind();
2168 auto loc = getToken().getLoc();
2172 SmallVector<Value, 3> operands;
2173 SmallVector<int64_t, 3> integers;
2174 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2176 if (getToken().isAny(FIRToken::integer, FIRToken::signed_integer,
2177 FIRToken::string)) {
2178 integers.push_back(0);
2179 return parseIntLit(integers.back(),
"expected integer");
2184 if (!integers.empty())
2185 return emitError(
"expected more integer constants"), failure();
2188 if (parseExp(operand,
"expected expression in primitive operand"))
2191 locationProcessor.setLoc(loc);
2193 operands.push_back(operand);
2198 locationProcessor.setLoc(loc);
2200 SmallVector<FIRRTLType, 3> opTypes;
2201 for (
auto v : operands)
2202 opTypes.push_back(type_cast<FIRRTLType>(v.getType()));
2204 unsigned numOperandsExpected;
2205 SmallVector<StringAttr, 2> attrNames;
2210 emitError(loc,
"primitive not supported yet");
2212 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2213 case FIRToken::lp_##SPELLING: \
2214 numOperandsExpected = NUMOPERANDS; \
2216 #include "FIRTokenKinds.def"
2223 case FIRToken::lp_bits:
2224 attrNames.push_back(getConstants().hiIdentifier);
2225 attrNames.push_back(getConstants().loIdentifier);
2227 case FIRToken::lp_head:
2228 case FIRToken::lp_pad:
2229 case FIRToken::lp_shl:
2230 case FIRToken::lp_shr:
2231 case FIRToken::lp_tail:
2232 attrNames.push_back(getConstants().amountIdentifier);
2236 if (operands.size() != numOperandsExpected) {
2237 assert(numOperandsExpected <= 3);
2238 static const char *numberName[] = {
"zero",
"one",
"two",
"three"};
2239 const char *optionalS = &
"s"[numOperandsExpected == 1];
2240 return emitError(loc,
"operation requires ")
2241 << numberName[numOperandsExpected] <<
" operand" << optionalS;
2244 if (integers.size() != attrNames.size()) {
2245 emitError(loc,
"expected ") << attrNames.size() <<
" constant arguments";
2249 NamedAttrList attrs;
2250 for (
size_t i = 0, e = attrNames.size(); i != e; ++i)
2251 attrs.append(attrNames[i],
builder.getI32IntegerAttr(integers[i]));
2255 emitError(loc,
"primitive not supported yet");
2258 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2259 case FIRToken::lp_##SPELLING: { \
2260 auto resultTy = CLASS::inferReturnType(operands, attrs, {}); \
2263 (void)CLASS::validateAndInferReturnType(operands, attrs, \
2264 translateLocation(loc)); \
2267 result = builder.create<CLASS>(resultTy, operands, attrs); \
2270 #include "FIRTokenKinds.def"
2273 llvm_unreachable(
"all cases should return");
2278 ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2279 bool isSigned = getToken().is(FIRToken::kw_SInt);
2280 auto loc = getToken().getLoc();
2286 if (parseOptionalWidth(
width) ||
2287 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2288 parseIntLit(value,
"expected integer value") ||
2289 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2296 IntegerType::SignednessSemantics signedness =
2297 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2299 if (!value.isZero())
2300 return emitError(loc,
"zero bit constant must be zero");
2301 value = value.trunc(0);
2302 }
else if (
width != -1) {
2304 bool valueFits = isSigned ? value.isSignedIntN(
width) : value.isIntN(
width);
2306 return emitError(loc,
"initializer too wide for declared width");
2307 value = isSigned ? value.sextOrTrunc(
width) : value.zextOrTrunc(
width);
2312 auto attr =
builder.getIntegerAttr(attrType, value);
2315 auto &entry = moduleContext.constantCache[{attr, type}];
2322 locationProcessor.setLoc(loc);
2323 result = moduleContext.getCachedConstantInt(
builder, attr, type, value);
2328 ParseResult FIRStmtParser::parseListExp(Value &result) {
2329 auto loc = getToken().getLoc();
2331 if (parseListType(type))
2333 auto listType = type_cast<ListType>(type);
2336 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2339 SmallVector<Value, 3> operands;
2340 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2342 locationProcessor.setLoc(loc);
2343 if (parseExp(operand,
"expected expression in List expression"))
2347 if (!isa<AnyRefType>(elementType) ||
2348 !isa<ClassType>(operand.getType()))
2349 return emitError(loc,
"unexpected expression of type ")
2350 << operand.getType() <<
" in List expression of type "
2352 operand = builder.create<ObjectAnyRefCastOp>(operand);
2355 operands.push_back(operand);
2360 locationProcessor.setLoc(loc);
2361 result =
builder.create<ListCreateOp>(listType, operands);
2367 ParseResult FIRStmtParser::parseMapExp(Value &result) {
2368 auto loc = getToken().getLoc();
2370 if (parseMapType(type))
2372 auto mapType = type_cast<MapType>(type);
2373 auto keyType = mapType.getKeyType();
2374 auto valueType = mapType.getValueType();
2376 if (parseToken(FIRToken::l_paren,
"expected '(' in Map expression"))
2379 SmallVector<Value, 3> keys, values;
2380 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2382 locationProcessor.setLoc(loc);
2383 if (parseExp(key,
"expected key expression in Map expression") ||
2384 parseToken(FIRToken::minus_greater,
2385 "expected '->' in Map expression") ||
2386 parseExp(value,
"expected value expression in Map expression"))
2389 if (key.getType() != keyType) {
2390 if (!isa<AnyRefType>(keyType) || !isa<ClassType>(key.getType()))
2391 return emitError(loc,
"unexpected expression of type ")
2392 << key.getType() <<
" for key in Map expression, expected "
2394 key = builder.create<ObjectAnyRefCastOp>(key);
2396 if (value.getType() != valueType) {
2397 if (!isa<AnyRefType>(valueType) || !isa<ClassType>(value.getType()))
2398 return emitError(loc,
"unexpected expression of type ")
2400 <<
" for value in Map expression, expected " << valueType;
2401 value = builder.create<ObjectAnyRefCastOp>(value);
2404 keys.push_back(key);
2405 values.push_back(value);
2410 locationProcessor.setLoc(loc);
2411 result =
builder.create<MapCreateOp>(mapType, keys, values);
2432 std::optional<ParseResult>
2433 FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2434 switch (getToken().getKind()) {
2437 return std::nullopt;
2439 case FIRToken::period:
2440 case FIRToken::l_square:
2441 case FIRToken::kw_is:
2442 case FIRToken::less_equal:
2443 case FIRToken::less_minus:
2449 auto loc = keyword.
getLoc();
2451 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2452 return ParseResult(failure());
2458 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2461 if (!consumeIf(FIRToken::period))
2462 return ParseResult(failure());
2464 StringRef fieldName;
2465 if (parseFieldId(fieldName,
"expected field name") ||
2466 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2467 return ParseResult(failure());
2471 if (parseOptionalExpPostscript(lhs))
2472 return ParseResult(failure());
2474 return parseLeadingExpStmt(lhs);
2480 ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2483 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2486 auto subIndent = getIndentation();
2487 if (!subIndent.has_value())
2488 return emitError(
"expected statement to be on its own line"), failure();
2490 if (*subIndent <= indent)
2494 if (parseSimpleStmt(*subIndent))
2499 ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2500 locationProcessor.startStatement();
2501 auto result = parseSimpleStmtImpl(stmtIndent);
2502 locationProcessor.endStatement(*
this);
2523 ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2524 auto kind = getToken().getKind();
2527 case FIRToken::kw_invalidate:
2528 case FIRToken::kw_connect:
2529 case FIRToken::kw_regreset:
2533 kind = FIRToken::identifier;
2540 case FIRToken::kw_attach:
2541 return parseAttach();
2542 case FIRToken::kw_infer:
2543 return parseMemPort(MemDirAttr::Infer);
2544 case FIRToken::kw_read:
2545 return parseMemPort(MemDirAttr::Read);
2546 case FIRToken::kw_write:
2547 return parseMemPort(MemDirAttr::Write);
2548 case FIRToken::kw_rdwr:
2549 return parseMemPort(MemDirAttr::ReadWrite);
2550 case FIRToken::kw_connect:
2551 return parseConnect();
2552 case FIRToken::kw_propassign:
2553 if (requireFeature({3, 1, 0},
"properties"))
2555 return parsePropAssign();
2556 case FIRToken::kw_invalidate:
2557 return parseInvalidate();
2558 case FIRToken::lp_printf:
2559 return parsePrintf();
2560 case FIRToken::kw_skip:
2562 case FIRToken::lp_stop:
2564 case FIRToken::lp_assert:
2565 return parseAssert();
2566 case FIRToken::lp_assume:
2567 return parseAssume();
2568 case FIRToken::lp_cover:
2569 return parseCover();
2570 case FIRToken::kw_when:
2571 return parseWhen(stmtIndent);
2572 case FIRToken::kw_match:
2573 return parseMatch(stmtIndent);
2574 case FIRToken::kw_define:
2575 return parseRefDefine();
2576 case FIRToken::lp_force:
2577 return parseRefForce();
2578 case FIRToken::lp_force_initial:
2579 return parseRefForceInitial();
2580 case FIRToken::lp_release:
2581 return parseRefRelease();
2582 case FIRToken::lp_release_initial:
2583 return parseRefReleaseInitial();
2584 case FIRToken::kw_group:
2585 if (requireFeature({3, 1, 0},
"optional groups"))
2587 return parseGroup(stmtIndent);
2592 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2599 return parseLeadingExpStmt(lhs);
2603 case FIRToken::kw_inst:
2604 return parseInstance();
2605 case FIRToken::kw_object:
2606 return parseObject();
2607 case FIRToken::kw_cmem:
2608 return parseCombMem();
2609 case FIRToken::kw_smem:
2610 return parseSeqMem();
2611 case FIRToken::kw_mem:
2612 return parseMem(stmtIndent);
2613 case FIRToken::kw_node:
2615 case FIRToken::kw_wire:
2617 case FIRToken::kw_reg:
2618 return parseRegister(stmtIndent);
2619 case FIRToken::kw_regreset:
2620 return parseRegisterWithReset();
2624 ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2626 SymbolRefAttr groupSym) {
2628 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2629 moduleContext, &blockToInsertInto);
2634 UnbundledValueRestorer x(moduleContext.unbundledValues);
2638 auto subParser = std::make_unique<FIRStmtParser>(
2639 blockToInsertInto, moduleContext, modNameSpace, version, groupSym);
2642 auto stmtIndent = getIndentation();
2645 if (!stmtIndent.has_value())
2646 return subParser->parseSimpleStmt(indent);
2648 if (*stmtIndent <= indent)
2649 return emitError(
"statement must be indented more than previous statement"),
2653 return subParser->parseSimpleStmtBlock(indent);
2657 ParseResult FIRStmtParser::parseAttach() {
2658 auto startTok = consumeToken(FIRToken::kw_attach);
2661 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2664 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
2667 SmallVector<Value, 4> operands;
2669 operands.push_back({});
2670 if (parseExp(operands.back(),
"expected operand in attach"))
2672 }
while (!consumeIf(FIRToken::r_paren));
2674 if (parseOptionalInfo())
2677 locationProcessor.setLoc(startTok.getLoc());
2678 builder.create<AttachOp>(operands);
2685 ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2686 auto startTok = consumeToken();
2687 auto startLoc = startTok.getLoc();
2691 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2697 Value memory, indexExp, clock;
2698 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
2699 parseId(
id,
"expected result name") ||
2700 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
2701 parseId(memName,
"expected memory name") ||
2702 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2703 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2704 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
2705 parseExp(indexExp,
"expected index expression") ||
2706 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
2707 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
2710 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2712 return emitError(startLoc,
2713 "memory port should have behavioral memory type");
2714 auto resultType = memVType.getElementType();
2716 ArrayAttr annotations = getConstants().emptyArrayAttr;
2717 locationProcessor.setLoc(startLoc);
2720 Value memoryPort, memoryData;
2722 OpBuilder::InsertionGuard guard(
builder);
2723 builder.setInsertionPointAfterValue(memory);
2724 auto memoryPortOp =
builder.create<MemoryPortOp>(
2727 memoryData = memoryPortOp.getResult(0);
2728 memoryPort = memoryPortOp.getResult(1);
2732 builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2734 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
2738 ParseResult FIRStmtParser::parsePrintf() {
2739 auto startTok = consumeToken(FIRToken::lp_printf);
2741 Value clock, condition;
2742 StringRef formatString;
2743 if (parseExp(clock,
"expected clock expression in printf") ||
2744 parseExp(condition,
"expected condition in printf") ||
2745 parseGetSpelling(formatString) ||
2746 parseToken(FIRToken::string,
"expected format string in printf"))
2749 SmallVector<Value, 4> operands;
2750 while (!consumeIf(FIRToken::r_paren)) {
2751 operands.push_back({});
2752 if (parseExp(operands.back(),
"expected operand in printf"))
2757 if (parseOptionalName(name))
2760 if (parseOptionalInfo())
2763 locationProcessor.setLoc(startTok.getLoc());
2766 builder.create<PrintFOp>(clock, condition,
2767 builder.getStringAttr(formatStrUnescaped), operands,
2773 ParseResult FIRStmtParser::parseSkip() {
2774 auto startTok = consumeToken(FIRToken::kw_skip);
2778 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2781 if (parseOptionalInfo())
2784 locationProcessor.setLoc(startTok.getLoc());
2790 ParseResult FIRStmtParser::parseStop() {
2791 auto startTok = consumeToken(FIRToken::lp_stop);
2793 Value clock, condition;
2796 if (parseExp(clock,
"expected clock expression in 'stop'") ||
2797 parseExp(condition,
"expected condition in 'stop'") ||
2798 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
2799 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
2800 parseOptionalName(name) || parseOptionalInfo())
2803 locationProcessor.setLoc(startTok.getLoc());
2804 builder.create<StopOp>(clock, condition,
builder.getI32IntegerAttr(exitCode),
2810 ParseResult FIRStmtParser::parseAssert() {
2811 auto startTok = consumeToken(FIRToken::lp_assert);
2813 Value clock, predicate, enable;
2816 if (parseExp(clock,
"expected clock expression in 'assert'") ||
2817 parseExp(predicate,
"expected predicate in 'assert'") ||
2818 parseExp(enable,
"expected enable in 'assert'") ||
2819 parseGetSpelling(message) ||
2820 parseToken(FIRToken::string,
"expected message in 'assert'") ||
2821 parseToken(FIRToken::r_paren,
"expected ')' in 'assert'") ||
2822 parseOptionalName(name) || parseOptionalInfo())
2825 locationProcessor.setLoc(startTok.getLoc());
2827 builder.create<AssertOp>(clock, predicate, enable, messageUnescaped,
2828 ValueRange{}, name.getValue());
2833 ParseResult FIRStmtParser::parseAssume() {
2834 auto startTok = consumeToken(FIRToken::lp_assume);
2836 Value clock, predicate, enable;
2839 if (parseExp(clock,
"expected clock expression in 'assume'") ||
2840 parseExp(predicate,
"expected predicate in 'assume'") ||
2841 parseExp(enable,
"expected enable in 'assume'") ||
2842 parseGetSpelling(message) ||
2843 parseToken(FIRToken::string,
"expected message in 'assume'") ||
2844 parseToken(FIRToken::r_paren,
"expected ')' in 'assume'") ||
2845 parseOptionalName(name) || parseOptionalInfo())
2848 locationProcessor.setLoc(startTok.getLoc());
2850 builder.create<AssumeOp>(clock, predicate, enable, messageUnescaped,
2851 ValueRange{}, name.getValue());
2856 ParseResult FIRStmtParser::parseCover() {
2857 auto startTok = consumeToken(FIRToken::lp_cover);
2859 Value clock, predicate, enable;
2862 if (parseExp(clock,
"expected clock expression in 'cover'") ||
2863 parseExp(predicate,
"expected predicate in 'cover'") ||
2864 parseExp(enable,
"expected enable in 'cover'") ||
2865 parseGetSpelling(message) ||
2866 parseToken(FIRToken::string,
"expected message in 'cover'") ||
2867 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
2868 parseOptionalName(name) || parseOptionalInfo())
2871 locationProcessor.setLoc(startTok.getLoc());
2873 builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
2874 ValueRange{}, name.getValue());
2880 ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
2881 auto startTok = consumeToken(FIRToken::kw_when);
2885 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2889 if (parseExp(condition,
"expected condition in 'when'") ||
2890 parseToken(FIRToken::colon,
"expected ':' in when") ||
2891 parseOptionalInfo())
2894 locationProcessor.setLoc(startTok.getLoc());
2896 auto whenStmt =
builder.create<WhenOp>(condition,
false);
2899 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, groupSym))
2903 if (getToken().isNot(FIRToken::kw_else))
2908 auto elseIndent = getIndentation();
2909 if (elseIndent && *elseIndent < whenIndent)
2912 consumeToken(FIRToken::kw_else);
2915 whenStmt.createElseRegion();
2921 if (getToken().is(FIRToken::kw_when)) {
2924 std::make_unique<FIRStmtParser>(whenStmt.getElseBlock(), moduleContext,
2925 modNameSpace, version, groupSym);
2927 return subParser->parseSimpleStmt(whenIndent);
2931 LocationAttr elseLoc;
2932 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
2933 parseOptionalInfoLocator(elseLoc) ||
2934 parseSubBlock(whenStmt.getElseBlock(), whenIndent, groupSym))
2943 ParseResult FIRStmtParser::parseEnumExp(Value &value) {
2944 auto startLoc = getToken().getLoc();
2946 if (parseEnumType(type))
2950 auto enumType = type_dyn_cast<FEnumType>(type);
2952 return emitError(startLoc,
2953 "expected enumeration type in enumeration expression");
2956 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
2957 parseId(tag,
"expected enumeration tag"))
2961 if (consumeIf(FIRToken::r_paren)) {
2966 auto attr =
builder.getIntegerAttr(attrType, APInt(0, 0,
false));
2967 input =
builder.create<ConstantOp>(type, attr);
2970 if (parseExp(input,
"expected expression in enumeration value") ||
2971 parseToken(FIRToken::r_paren,
"expected closing ')'"))
2975 locationProcessor.setLoc(startLoc);
2976 value =
builder.create<FEnumCreateOp>(enumType, tag, input);
2984 ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
2985 auto startTok = consumeToken(FIRToken::kw_match);
2987 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2991 if (parseExp(input,
"expected expression in 'match'") ||
2992 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
2993 parseOptionalInfo())
2996 auto enumType = type_dyn_cast<FEnumType>(input.getType());
2998 return mlir::emitError(
3000 "expected enumeration type for 'match' statement, but got ")
3003 locationProcessor.setLoc(startTok.getLoc());
3005 SmallVector<Attribute> tags;
3006 SmallVector<std::unique_ptr<Region>> regions;
3008 auto tagLoc = getToken().getLoc();
3011 auto caseIndent = getIndentation();
3012 if (!caseIndent || *caseIndent <= matchIndent)
3016 StringRef tagSpelling;
3017 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3019 auto tagIndex = enumType.getElementIndex(tagSpelling);
3021 return emitError(tagLoc,
"tag ")
3022 << tagSpelling <<
" not a member of enumeration " << enumType;
3024 tags.push_back(tag);
3027 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3030 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3035 UnbundledValueRestorer x(moduleContext.unbundledValues);
3038 if (consumeIf(FIRToken::l_paren)) {
3039 StringAttr identifier;
3040 if (parseId(identifier,
"expected identifier for 'case' binding"))
3044 auto dataType = enumType.getElementType(*tagIndex);
3045 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3047 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3051 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3056 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3059 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3063 auto subParser = std::make_unique<FIRStmtParser>(
3064 *caseBlock, moduleContext, modNameSpace, version, groupSym);
3065 if (subParser->parseSimpleStmtBlock(*caseIndent))
3075 ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3076 auto token = getToken().getKind();
3077 if (token == FIRToken::lp_probe)
3078 return parseProbe(result);
3079 if (token == FIRToken::lp_rwprobe)
3080 return parseRWProbe(result);
3085 return parseStaticRefExp(result, message);
3092 ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3093 const Twine &message) {
3094 auto parseIdOrInstance = [&]() -> ParseResult {
3096 auto loc = getToken().getLoc();
3098 if (parseId(
id, message) ||
3099 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3103 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3109 StringRef fieldName;
3111 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3112 parseFieldId(fieldName,
"expected field name") ||
3113 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3115 return failure(parseIdOrInstance() ||
3116 parseOptionalExpPostscript(result,
false));
3121 ParseResult FIRStmtParser::parsePathExp(Value &result) {
3122 auto startTok = consumeToken(FIRToken::lp_path);
3123 locationProcessor.setLoc(startTok.getLoc());
3125 if (parseGetSpelling(target) ||
3126 parseToken(FIRToken::string,
3127 "expected target string in path expression") ||
3128 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3130 result =
builder.create<UnresolvedPathOp>(
3136 ParseResult FIRStmtParser::parseRefDefine() {
3137 auto startTok = consumeToken(FIRToken::kw_define);
3140 if (parseStaticRefExp(target,
3141 "expected static reference expression in 'define'") ||
3142 parseToken(FIRToken::equal,
3143 "expected '=' after define reference expression") ||
3144 parseRefExp(src,
"expected reference expression in 'define'") ||
3145 parseOptionalInfo())
3149 if (!type_isa<RefType>(target.getType()))
3150 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3151 "'define' target (LHS), got ")
3152 << target.getType();
3153 if (!type_isa<RefType>(src.getType()))
3154 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3155 "'define' source (RHS), got ")
3160 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3161 return emitError(startTok.getLoc(),
3162 "cannot define into a sub-element of a reference");
3164 locationProcessor.setLoc(startTok.getLoc());
3167 return emitError(startTok.getLoc(),
"cannot define reference of type ")
3168 << target.getType() <<
" with incompatible reference of type "
3178 ParseResult FIRStmtParser::parseRefRead(Value &result) {
3179 auto startTok = consumeToken(FIRToken::lp_read);
3182 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
3183 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
3186 locationProcessor.setLoc(startTok.getLoc());
3189 if (!type_isa<RefType>(ref.getType()))
3190 return emitError(startTok.getLoc(),
3191 "expected reference-type expression in 'read', got ")
3194 result =
builder.create<RefResolveOp>(ref);
3200 ParseResult FIRStmtParser::parseProbe(Value &result) {
3201 auto startTok = consumeToken(FIRToken::lp_probe);
3204 if (parseStaticRefExp(staticRef,
3205 "expected static reference expression in 'probe'") ||
3206 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
3209 locationProcessor.setLoc(startTok.getLoc());
3212 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3213 return emitError(startTok.getLoc(),
3214 "expected base-type expression in 'probe', got ")
3215 << staticRef.getType();
3219 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3220 MemoryDebugPortOp, MemoryPortAccessOp>(
3221 staticRef.getDefiningOp()))
3222 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3224 result =
builder.create<RefSendOp>(staticRef);
3230 ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3231 auto startTok = consumeToken(FIRToken::lp_rwprobe);
3234 if (parseStaticRefExp(staticRef,
3235 "expected static reference expression in 'rwprobe'") ||
3236 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
3239 locationProcessor.setLoc(startTok.getLoc());
3245 auto targetType = type_dyn_cast<FIRRTLBaseType>(staticRef.getType());
3247 return emitError(startTok.getLoc(),
3248 "expected base-type expression in 'rwprobe', got ")
3249 << staticRef.getType();
3252 auto target = fieldRef.getValue();
3255 if (
auto arg = dyn_cast<BlockArgument>(target)) {
3257 if (targetType.hasUninferredReset())
3258 return emitError(startTok.getLoc(),
3259 "must have concrete reset type in type ")
3261 auto forceableType =
3264 return emitError(startTok.getLoc(),
"cannot force target of type ")
3268 auto mod = cast<FModuleOp>(arg.getOwner()->getParentOp());
3270 hw::InnerSymTarget(arg.getArgNumber(), mod, fieldRef.getFieldID()),
3271 [&](
auto _) -> hw::InnerSymbolNamespace & { return modNameSpace; });
3272 result =
builder.create<RWProbeOp>(forceableType, sym);
3276 auto *definingOp = target.getDefiningOp();
3278 return emitError(startTok.getLoc(),
3279 "rwprobe value must be defined by an operation");
3281 if (isa<MemOp, CombMemOp, SeqMemOp, MemoryPortOp, MemoryDebugPortOp,
3282 MemoryPortAccessOp>(definingOp))
3283 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3285 auto forceable = dyn_cast<Forceable>(definingOp);
3286 if (!forceable || !forceable.isForceable() )
3287 return emitError(startTok.getLoc(),
"rwprobe target not forceable")
3288 .attachNote(definingOp->getLoc());
3298 ParseResult FIRStmtParser::parseRefForce() {
3299 auto startTok = consumeToken(FIRToken::lp_force);
3301 Value clock, pred, dest, src;
3302 if (parseExp(clock,
"expected clock expression in force") ||
3303 parseExp(pred,
"expected predicate expression in force") ||
3304 parseRefExp(dest,
"expected destination reference expression in force") ||
3305 parseExp(src,
"expected source expression in force") ||
3306 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
3307 parseOptionalInfo())
3311 auto ref = type_dyn_cast<RefType>(dest.getType());
3312 if (!ref || !ref.getForceable())
3315 "expected rwprobe-type expression for force destination, got ")
3317 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3319 return emitError(startTok.getLoc(),
3320 "expected base-type for force source, got ")
3323 locationProcessor.setLoc(startTok.getLoc());
3326 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3327 if (noConstSrcType != ref.getType()) {
3329 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3331 dest =
builder.create<RefCastOp>(compatibleRWProbe, dest);
3334 builder.create<RefForceOp>(clock, pred, dest, src);
3340 ParseResult FIRStmtParser::parseRefForceInitial() {
3341 auto startTok = consumeToken(FIRToken::lp_force_initial);
3345 dest,
"expected destination reference expression in force_initial") ||
3346 parseExp(src,
"expected source expression in force_initial") ||
3347 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
3348 parseOptionalInfo())
3352 auto ref = type_dyn_cast<RefType>(dest.getType());
3353 if (!ref || !ref.getForceable())
3354 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3355 "force_initial destination, got ")
3357 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3359 return emitError(startTok.getLoc(),
3360 "expected base-type expression for force_initial "
3364 locationProcessor.setLoc(startTok.getLoc());
3367 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3368 if (noConstSrcType != ref.getType()) {
3370 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3372 dest =
builder.create<RefCastOp>(compatibleRWProbe, dest);
3375 auto value = APInt::getAllOnes(1);
3378 value.getBitWidth(),
3379 IntegerType::Unsigned),
3381 auto pred = moduleContext.getCachedConstantInt(
builder, attr, type, value);
3382 builder.create<RefForceInitialOp>(pred, dest, src);
3388 ParseResult FIRStmtParser::parseRefRelease() {
3389 auto startTok = consumeToken(FIRToken::lp_release);
3391 Value clock, pred, dest;
3392 if (parseExp(clock,
"expected clock expression in release") ||
3393 parseExp(pred,
"expected predicate expression in release") ||
3395 "expected destination reference expression in release") ||
3396 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
3397 parseOptionalInfo())
3401 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3402 !ref || !ref.getForceable())
3405 "expected rwprobe-type expression for release destination, got ")
3408 locationProcessor.setLoc(startTok.getLoc());
3410 builder.create<RefReleaseOp>(clock, pred, dest);
3416 ParseResult FIRStmtParser::parseRefReleaseInitial() {
3417 auto startTok = consumeToken(FIRToken::lp_release_initial);
3422 "expected destination reference expression in release_initial") ||
3423 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
3424 parseOptionalInfo())
3428 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3429 !ref || !ref.getForceable())
3430 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3431 "release_initial destination, got ")
3434 locationProcessor.setLoc(startTok.getLoc());
3436 auto value = APInt::getAllOnes(1);
3439 value.getBitWidth(),
3440 IntegerType::Unsigned),
3442 auto pred = moduleContext.getCachedConstantInt(
builder, attr, type, value);
3443 builder.create<RefReleaseInitialOp>(pred, dest);
3449 ParseResult FIRStmtParser::parseConnect() {
3450 auto startTok = consumeToken(FIRToken::kw_connect);
3451 auto loc = startTok.getLoc();
3454 if (parseExp(lhs,
"expected connect expression") ||
3455 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
3458 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3459 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3460 if (!lhsType || !rhsType)
3461 return emitError(loc,
"cannot connect reference or property types");
3463 if (lhsType.containsReference() || rhsType.containsReference())
3464 return emitError(loc,
"cannot connect types containing references");
3467 return emitError(loc,
"cannot connect non-equivalent type ")
3468 << rhsType <<
" to " << lhsType;
3470 locationProcessor.setLoc(loc);
3476 ParseResult FIRStmtParser::parsePropAssign() {
3477 auto startTok = consumeToken(FIRToken::kw_propassign);
3478 auto loc = startTok.getLoc();
3481 if (parseExp(lhs,
"expected propassign expression") ||
3482 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
3485 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
3486 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
3487 if (!lhsType || !rhsType)
3488 return emitError(loc,
"can only propassign property types");
3489 locationProcessor.setLoc(loc);
3490 if (lhsType != rhsType) {
3492 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
3493 rhs =
builder.create<ObjectAnyRefCastOp>(rhs);
3495 return emitError(loc,
"cannot propassign non-equivalent type ")
3496 << rhsType <<
" to " << lhsType;
3498 builder.create<PropAssignOp>(lhs, rhs);
3503 ParseResult FIRStmtParser::parseInvalidate() {
3504 auto startTok = consumeToken(FIRToken::kw_invalidate);
3507 if (parseExp(lhs,
"expected connect expression") || parseOptionalInfo())
3510 locationProcessor.setLoc(startTok.getLoc());
3511 emitInvalidate(lhs);
3515 ParseResult FIRStmtParser::parseGroup(
unsigned indent) {
3517 auto startTok = consumeToken(FIRToken::kw_group);
3518 auto loc = startTok.getLoc();
3521 if (parseId(
id,
"expected group identifer") ||
3522 parseToken(FIRToken::colon,
"expected ':' at end of group") ||
3523 parseOptionalInfo())
3526 locationProcessor.setLoc(loc);
3528 StringRef rootGroup;
3529 SmallVector<FlatSymbolRefAttr> nestedGroups;
3533 rootGroup = groupSym.getRootReference();
3534 auto nestedRefs = groupSym.getNestedReferences();
3535 nestedGroups.append(nestedRefs.begin(), nestedRefs.end());
3539 auto groupOp =
builder.create<GroupOp>(
3541 groupOp->getRegion(0).push_back(
new Block());
3543 if (getIndentation() > indent)
3544 if (parseSubBlock(groupOp.getRegion().front(), indent,
3545 groupOp.getGroupName()))
3554 ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
3555 auto loc = getToken().getLoc();
3558 if (consumeIf(FIRToken::kw_is)) {
3559 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
3560 parseOptionalInfo())
3563 locationProcessor.setLoc(loc);
3564 emitInvalidate(lhs);
3568 auto kind = getToken().getKind();
3570 case FIRToken::less_equal:
3572 case FIRToken::less_minus:
3578 return emitError() <<
"unexpected token '" << getToken().getSpelling()
3579 <<
"' in statement",
3585 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
3588 locationProcessor.setLoc(loc);
3590 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3591 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3592 if (!lhsType || !rhsType)
3593 return emitError(loc,
"cannot connect reference or property types");
3595 if (lhsType.containsReference() || rhsType.containsReference())
3596 return emitError(loc,
"cannot connect types containing references");
3598 if (kind == FIRToken::less_equal) {
3600 return emitError(loc,
"cannot connect non-equivalent type ")
3601 << rhsType <<
" to " << lhsType;
3604 assert(kind == FIRToken::less_minus &&
"unexpected kind");
3606 return emitError(loc,
3607 "cannot partially connect non-weakly-equivalent type ")
3608 << rhsType <<
" to " << lhsType;
3609 emitPartialConnect(
builder, lhs, rhs);
3618 ParseResult FIRStmtParser::parseInstance() {
3619 auto startTok = consumeToken(FIRToken::kw_inst);
3623 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3627 StringRef moduleName;
3628 if (parseId(
id,
"expected instance name") ||
3629 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
3630 parseId(moduleName,
"expected module name") || parseOptionalInfo())
3633 locationProcessor.setLoc(startTok.getLoc());
3637 builder.getBlock()->getParentOp()->getParentOfType<CircuitOp>();
3638 auto referencedModule =
3639 dyn_cast_or_null<FModuleLike>(circuit.lookupSymbol(moduleName));
3640 if (!referencedModule) {
3641 emitError(startTok.getLoc(),
3642 "use of undefined module name '" + moduleName +
"' in instance");
3645 if (isa<ClassOp /* ClassLike */>(referencedModule))
3646 return emitError(startTok.getLoc(),
"cannot create instance of class '" +
3648 "', did you mean object?");
3650 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
3653 SmallVector<Type, 4> resultTypes;
3654 resultTypes.reserve(modulePorts.size());
3655 SmallVector<std::pair<StringAttr, Type>, 4> resultNamesAndTypes;
3657 for (
auto port : modulePorts) {
3658 resultTypes.push_back(port.type);
3659 resultNamesAndTypes.push_back({port.name, port.type});
3662 auto annotations = getConstants().emptyArrayAttr;
3663 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
3665 StringAttr sym = {};
3666 auto result =
builder.create<InstanceOp>(
3667 referencedModule, id, NameKindEnum::InterestingName,
3668 annotations.getValue(), portAnnotations,
false, sym);
3674 unbundledValueEntry.reserve(modulePorts.size());
3675 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
3676 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
3680 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
3681 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
3682 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
3686 ParseResult FIRStmtParser::parseObject() {
3687 auto startTok = consumeToken(FIRToken::kw_object);
3691 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3694 if (requireFeature({3, 2, 0},
"object statements"))
3698 StringRef className;
3699 if (parseId(
id,
"expected object name") ||
3700 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
3701 parseId(className,
"expected class name") || parseOptionalInfo())
3704 locationProcessor.setLoc(startTok.getLoc());
3708 builder.getBlock()->getParentOp()->getParentOfType<CircuitOp>();
3709 auto referencedClass = circuit.lookupSymbol<ClassLike>(className);
3710 if (!referencedClass)
3711 return emitError(startTok.getLoc(),
"use of undefined class name '" +
3712 className +
"' in object");
3713 auto result =
builder.create<ObjectOp>(referencedClass, id);
3714 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
3718 ParseResult FIRStmtParser::parseCombMem() {
3720 auto startTok = consumeToken(FIRToken::kw_cmem);
3724 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3729 if (parseId(
id,
"expected cmem name") ||
3730 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
3731 parseType(type,
"expected cmem type") || parseOptionalInfo())
3734 locationProcessor.setLoc(startTok.getLoc());
3737 auto vectorType = type_dyn_cast<FVectorType>(type);
3739 return emitError(
"cmem requires vector type");
3741 auto annotations = getConstants().emptyArrayAttr;
3742 StringAttr sym = {};
3743 auto result =
builder.create<CombMemOp>(
3744 vectorType.getElementType(), vectorType.getNumElements(), id,
3745 NameKindEnum::InterestingName, annotations, sym);
3746 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
3750 ParseResult FIRStmtParser::parseSeqMem() {
3752 auto startTok = consumeToken(FIRToken::kw_smem);
3756 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3761 RUWAttr ruw = RUWAttr::Undefined;
3763 if (parseId(
id,
"expected smem name") ||
3764 parseToken(FIRToken::colon,
"expected ':' in smem") ||
3765 parseType(type,
"expected smem type") || parseOptionalRUW(ruw) ||
3766 parseOptionalInfo())
3769 locationProcessor.setLoc(startTok.getLoc());
3772 auto vectorType = type_dyn_cast<FVectorType>(type);
3774 return emitError(
"smem requires vector type");
3776 auto annotations = getConstants().emptyArrayAttr;
3777 StringAttr sym = {};
3778 auto result =
builder.create<SeqMemOp>(
3779 vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
3780 NameKindEnum::InterestingName, annotations, sym);
3781 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
3793 ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
3794 auto startTok = consumeToken(FIRToken::kw_mem);
3798 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3802 if (parseId(
id,
"expected mem name") ||
3803 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
3807 int64_t depth = -1, readLatency = -1, writeLatency = -1;
3808 RUWAttr ruw = RUWAttr::Undefined;
3810 SmallVector<std::pair<StringAttr, Type>, 4> ports;
3814 auto nextIndent = getIndentation();
3815 if (!nextIndent || *nextIndent <= memIndent)
3818 auto spelling = getTokenSpelling();
3819 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
3820 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
3823 if (spelling ==
"data-type") {
3825 return emitError(
"'mem' type specified multiple times"), failure();
3827 if (
parseType(type,
"expected type in data-type declaration"))
3831 if (spelling ==
"depth") {
3832 if (parseIntLit(depth,
"expected integer in depth specification"))
3836 if (spelling ==
"read-latency") {
3837 if (parseIntLit(readLatency,
"expected integer latency"))
3841 if (spelling ==
"write-latency") {
3842 if (parseIntLit(writeLatency,
"expected integer latency"))
3846 if (spelling ==
"read-under-write") {
3847 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
3848 FIRToken::kw_undefined))
3849 return emitError(
"expected specifier"), failure();
3851 if (parseOptionalRUW(ruw))
3856 MemOp::PortKind portKind;
3857 if (spelling ==
"reader")
3858 portKind = MemOp::PortKind::Read;
3859 else if (spelling ==
"writer")
3860 portKind = MemOp::PortKind::Write;
3861 else if (spelling ==
"readwriter")
3862 portKind = MemOp::PortKind::ReadWrite;
3864 return emitError(
"unexpected field in 'mem' declaration"), failure();
3867 if (parseId(portName,
"expected port name"))
3869 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
3871 return emitError(
"unexpected type, must be base type");
3872 ports.push_back({
builder.getStringAttr(portName),
3873 MemOp::getTypeForPort(depth, baseType, portKind)});
3875 while (!getIndentation().has_value()) {
3876 if (parseId(portName,
"expected port name"))
3878 ports.push_back({
builder.getStringAttr(portName),
3879 MemOp::getTypeForPort(depth, baseType, portKind)});
3890 llvm::array_pod_sort(ports.begin(), ports.end(),
3891 [](
const std::pair<StringAttr, Type> *lhs,
3892 const std::pair<StringAttr, Type> *rhs) ->
int {
3893 return lhs->first.getValue().compare(
3894 rhs->first.getValue());
3897 auto annotations = getConstants().emptyArrayAttr;
3898 SmallVector<Attribute, 4> resultNames;
3899 SmallVector<Type, 4> resultTypes;
3900 SmallVector<Attribute, 4> resultAnnotations;
3901 for (
auto p : ports) {
3902 resultNames.push_back(p.first);
3903 resultTypes.push_back(p.second);
3904 resultAnnotations.push_back(annotations);
3907 locationProcessor.setLoc(startTok.getLoc());
3909 auto result =
builder.create<MemOp>(
3910 resultTypes, readLatency, writeLatency, depth, ruw,
3911 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
3912 annotations,
builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
3913 MemoryInitAttr(), StringAttr());
3916 unbundledValueEntry.reserve(result.getNumResults());
3917 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
3918 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
3920 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
3921 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
3922 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
3926 ParseResult FIRStmtParser::parseNode() {
3927 auto startTok = consumeToken(FIRToken::kw_node);
3931 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3936 if (parseId(
id,
"expected node name") ||
3937 parseToken(FIRToken::equal,
"expected '=' in node") ||
3938 parseExp(initializer,
"expected expression for node") ||
3939 parseOptionalInfo())
3942 locationProcessor.setLoc(startTok.getLoc());
3954 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
3955 auto initializerBaseType =
3956 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
3957 if (type_isa<AnalogType>(initializerType) ||
3958 !(initializerBaseType && initializerBaseType.isPassive())) {
3959 emitError(startTok.getLoc())
3960 <<
"Node cannot be analog and must be passive or passive under a flip "
3961 << initializer.getType();
3965 auto annotations = getConstants().emptyArrayAttr;
3966 StringAttr sym = {};
3971 builder.create<NodeOp>(initializer, id, NameKindEnum::InterestingName,
3972 annotations, sym, forceable);
3973 return moduleContext.addSymbolEntry(
id, result.getResult(),
3978 ParseResult FIRStmtParser::parseWire() {
3979 auto startTok = consumeToken(FIRToken::kw_wire);
3983 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3988 if (parseId(
id,
"expected wire name") ||
3989 parseToken(FIRToken::colon,
"expected ':' in wire") ||
3990 parseType(type,
"expected wire type") || parseOptionalInfo())
3993 locationProcessor.setLoc(startTok.getLoc());
3995 auto annotations = getConstants().emptyArrayAttr;
3996 StringAttr sym = {};
4000 auto namekind = isa<PropertyType, RefType>(type)
4001 ? NameKindEnum::DroppableName
4002 : NameKindEnum::InterestingName;
4005 builder.create<WireOp>(type, id, namekind, annotations, sym, forceable);
4006 return moduleContext.addSymbolEntry(
id, result.getResult(),
4020 ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4021 auto startTok = consumeToken(FIRToken::kw_reg);
4025 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4034 if (parseId(
id,
"expected reg name") ||
4035 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4037 parseExp(clock,
"expected expression for register clock"))
4040 if (!type_isa<FIRRTLBaseType>(type))
4041 return emitError(startTok.getLoc(),
"register must have base type");
4044 Value resetSignal, resetValue;
4045 if (consumeIf(FIRToken::kw_with)) {
4046 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
4054 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4056 auto indent = getIndentation();
4057 if (!indent || *indent <= regIndent)
4058 if (!hasExtraLParen)
4059 return emitError(
"expected indented reset specifier in reg"), failure();
4061 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
4062 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
4063 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
4064 parseExp(resetSignal,
"expected expression for reset signal"))
4072 if (getTokenSpelling() ==
id) {
4074 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4076 resetSignal = Value();
4078 if (parseExp(resetValue,
"expected expression for reset value") ||
4079 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4083 if (hasExtraLParen &&
4084 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4090 if (parseOptionalInfo())
4093 locationProcessor.setLoc(startTok.getLoc());
4095 ArrayAttr annotations = getConstants().emptyArrayAttr;
4097 StringAttr sym = {};
4101 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4102 NameKindEnum::InterestingName, annotations,
4107 .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4108 annotations, sym, forceable)
4110 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4118 ParseResult FIRStmtParser::parseRegisterWithReset() {
4119 auto startTok = consumeToken(FIRToken::kw_regreset);
4123 Value clock, resetSignal, resetValue;
4125 if (parseId(
id,
"expected reg name") ||
4126 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4128 parseExp(clock,
"expected expression for register clock") ||
4129 parseExp(resetSignal,
"expected expression for register reset") ||
4130 parseExp(resetValue,
"expected expression for register reset value") ||
4131 parseOptionalInfo())
4134 if (!type_isa<FIRRTLBaseType>(type))
4135 return emitError(startTok.getLoc(),
"register must have base type");
4137 locationProcessor.setLoc(startTok.getLoc());
4141 .create<RegResetOp>(type, clock, resetSignal, resetValue,
4142 id, NameKindEnum::InterestingName,
4143 getConstants().emptyArrayAttr,
4144 StringAttr{}, forceable)
4147 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4157 struct FIRCircuitParser :
public FIRParser {
4158 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
4160 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
4163 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
4164 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBuf,
4165 mlir::TimingScope &ts);
4170 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4171 SmallVectorImpl<Attribute> &attrs);
4175 ParseResult importOMIR(CircuitOp circuit, SMLoc loc, StringRef annotationStr,
4176 SmallVectorImpl<Attribute> &attrs);
4178 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
4180 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
4181 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
4182 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
4183 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
4184 ParseResult parseModule(CircuitOp circuit,
unsigned indent);
4186 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4187 SmallVectorImpl<SMLoc> &resultPortLocs,
4190 ParseResult parseParameter(StringAttr &resultName, TypedAttr &resultValue,
4192 ParseResult parseRefList(ArrayRef<PortInfo> portList,
4193 ArrayAttr &internalPathResults);
4195 ParseResult skipToModuleEnd(
unsigned indent);
4197 ParseResult parseTypeDecl();
4199 ParseResult parseGroupDecl(CircuitOp circuit);
4201 struct DeferredModuleToParse {
4202 FModuleLike moduleOp;
4203 SmallVector<SMLoc> portLocs;
4208 ParseResult parseModuleBody(DeferredModuleToParse &deferredModule);
4210 SmallVector<DeferredModuleToParse, 0> deferredModules;
4211 ModuleOp mlirModule;
4216 FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4217 SmallVectorImpl<Attribute> &attrs) {
4219 auto annotations = json::parse(annotationsStr);
4220 if (
auto err = annotations.takeError()) {
4221 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4222 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
4223 diag.attachNote() << a.message();
4228 json::Path::Root root;
4229 llvm::StringMap<ArrayAttr> thisAnnotationMap;
4230 if (!
fromJSONRaw(annotations.get(), attrs, root, getContext())) {
4231 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
4232 std::string jsonErrorMessage =
4233 "See inline comments for problem area in JSON:\n";
4234 llvm::raw_string_ostream s(jsonErrorMessage);
4235 root.printErrorContext(annotations.get(), s);
4236 diag.attachNote() << jsonErrorMessage;
4243 ParseResult FIRCircuitParser::importOMIR(CircuitOp circuit, SMLoc loc,
4244 StringRef annotationsStr,
4245 SmallVectorImpl<Attribute> &annos) {
4247 auto annotations = json::parse(annotationsStr);
4248 if (
auto err = annotations.takeError()) {
4249 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4250 auto diag = emitError(loc,
"Failed to parse OMIR file");
4251 diag.attachNote() << a.message();
4256 json::Path::Root root;
4257 if (!
fromOMIRJSON(annotations.get(), annos, root, circuit.getContext())) {
4258 auto diag = emitError(loc,
"Invalid/unsupported OMIR format");
4259 std::string jsonErrorMessage =
4260 "See inline comments for problem area in JSON:\n";
4261 llvm::raw_string_ostream s(jsonErrorMessage);
4262 root.printErrorContext(annotations.get(), s);
4263 diag.attachNote() << jsonErrorMessage;
4275 SmallVectorImpl<SMLoc> &resultPortLocs,
4278 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
4280 getIndentation() > indent) {
4286 auto backtrackState = getLexer().getCursor();
4288 bool isOutput = getToken().is(FIRToken::kw_output);
4293 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
4294 !getToken().isKeyword()) {
4295 backtrackState.restore(getLexer());
4301 LocWithInfo info(getToken().getLoc(),
this);
4302 if (parseId(name,
"expected port name") ||
4303 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
4304 parseType(type,
"expected a type in port declaration") ||
4305 info.parseOptionalInfo())
4308 StringAttr innerSym = {};
4309 resultPorts.push_back(
4310 {name, type,
direction::get(isOutput), innerSym, info.getLoc()});
4311 resultPortLocs.push_back(info.getFIRLoc());
4315 std::function<bool(Type,
bool)> hasInputRef = [&](Type type,
4316 bool output) ->
bool {
4317 auto ftype = type_dyn_cast<FIRRTLType>(type);
4318 if (!ftype || !ftype.containsReference())
4320 return TypeSwitch<FIRRTLType, bool>(ftype)
4321 .Case<RefType>([&](
auto reftype) {
return !output; })
4322 .Case<OpenVectorType>([&](OpenVectorType ovt) {
4323 return hasInputRef(ovt.getElementType(), output);
4325 .Case<OpenBundleType>([&](OpenBundleType obt) {
4326 for (
auto field : obt.getElements())
4327 if (hasInputRef(field.type, field.isFlip ^ output))
4335 for (
auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
4336 PortInfo &port = std::get<0>(portAndLoc);
4340 return emitError(std::get<1>(portAndLoc),
4341 "input probes not yet supported");
4342 auto &entry = portIds[port.
name];
4343 if (!entry.isValid()) {
4344 entry = std::get<1>(portAndLoc);
4348 emitError(std::get<1>(portAndLoc),
4349 "redefinition of name '" + port.
getName() +
"'")
4350 .attachNote(translateLocation(entry))
4351 <<
"previous definition here";
4360 ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
4361 ArrayAttr &internalPathsResult) {
4362 struct RefStatementInfo {
4364 InternalPathAttr resolvedPath;
4368 SmallVector<RefStatementInfo> refStatements;
4369 SmallPtrSet<StringAttr, 8> seenNames;
4370 SmallPtrSet<StringAttr, 8> seenRefs;
4373 while (consumeIf(FIRToken::kw_ref)) {
4374 auto loc = getToken().getLoc();
4378 if (parseId(refName,
"expected ref name"))
4380 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
4382 loc,
"ref statements for aggregate elements not yet supported");
4383 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
4386 if (!seenRefs.insert(refName).second)
4387 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
4390 auto kind = getToken().getKind();
4391 if (kind != FIRToken::string)
4392 return emitError(loc,
"expected string in ref statement");
4396 consumeToken(FIRToken::string);
4398 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
4402 SmallVector<Attribute> internalPaths(portList.size(),
4405 llvm::SmallBitVector usedRefs(refStatements.size());
4406 size_t matchedPaths = 0;
4407 for (
auto [idx, port] : llvm::enumerate(portList)) {
4408 if (!type_isa<RefType>(port.
type))
4414 return mlir::emitError(
4416 "references in ports must be output on extmodule and intmodule");
4418 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
4419 return r.refName == pname;
4422 if (refStmtIt == refStatements.end()) {
4423 if (!refStatements.empty())
4424 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
4429 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
4430 internalPaths[idx] = refStmtIt->resolvedPath;
4434 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
4435 assert(matchedPaths < refStatements.size());
4437 auto idx = usedRefs.find_first_unset();
4439 return emitError(refStatements[idx].loc,
"unused ref statement");
4443 internalPathsResult =
ArrayAttr::get(getContext(), internalPaths);
4449 ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
4451 switch (getToken().getKind()) {
4455 case FIRToken::error:
4459 case FIRToken::kw_class:
4460 case FIRToken::kw_declgroup:
4461 case FIRToken::kw_extclass:
4462 case FIRToken::kw_extmodule:
4463 case FIRToken::kw_intmodule:
4464 case FIRToken::kw_module:
4465 case FIRToken::kw_type:
4469 if (getIndentation() == indent)
4483 ParseResult FIRCircuitParser::parseParameter(StringAttr &resultName,
4484 TypedAttr &resultValue,
4486 mlir::Builder
builder(getContext());
4488 consumeToken(FIRToken::kw_parameter);
4489 auto loc = getToken().getLoc();
4492 if (parseId(name,
"expected parameter name") ||
4493 parseToken(FIRToken::equal,
"expected '=' in parameter"))
4497 switch (getToken().getKind()) {
4499 return emitError(
"expected parameter value"), failure();
4500 case FIRToken::integer:
4501 case FIRToken::signed_integer: {
4503 if (parseIntLit(result,
"invalid integer parameter"))
4509 if (result.getBitWidth() < 32)
4510 result = result.sext(32);
4512 value =
builder.getIntegerAttr(
4513 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
4517 case FIRToken::string: {
4519 value =
builder.getStringAttr(getToken().getStringValue());
4520 consumeToken(FIRToken::string);
4523 case FIRToken::verbatim_string: {
4525 auto text =
builder.getStringAttr(getToken().getVerbatimStringValue());
4527 consumeToken(FIRToken::verbatim_string);
4530 case FIRToken::floatingpoint:
4532 if (!llvm::to_float(getTokenSpelling(), v))
4533 return emitError(
"invalid float parameter syntax"), failure();
4535 value =
builder.getF64FloatAttr(v);
4536 consumeToken(FIRToken::floatingpoint);
4540 resultName =
builder.getStringAttr(name);
4541 resultValue = value;
4548 SmallVector<Attribute, 8> parameters;
4549 SmallPtrSet<StringAttr, 8> seen;
4550 while (getToken().is(FIRToken::kw_parameter)) {
4554 if (parseParameter(name, value, loc))
4556 if (!seen.insert(name).second)
4557 return emitError(loc,
4558 "redefinition of parameter '" + name.getValue() +
"'");
4566 ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
4568 SmallVector<PortInfo, 8> portList;
4569 SmallVector<SMLoc> portLocs;
4570 LocWithInfo info(getToken().getLoc(),
this);
4572 if (requireFeature({3, 2, 0},
"classes"))
4575 consumeToken(FIRToken::kw_class);
4576 if (parseId(name,
"expected class name") ||
4577 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
4578 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4581 if (name == circuit.getName())
4582 return mlir::emitError(info.getLoc(),
4583 "class cannot be the top of a circuit");
4585 for (
auto &portInfo : portList)
4586 if (!isa<PropertyType>(portInfo.type))
4587 return mlir::emitError(portInfo.loc,
4588 "ports on classes must be properties");
4591 auto builder = circuit.getBodyBuilder();
4592 auto classOp =
builder.create<ClassOp>(info.getLoc(), name, portList);
4593 deferredModules.emplace_back(
4594 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
4597 getConstants().classMap[name.getValue()] = classOp;
4598 return skipToModuleEnd(indent);
4602 ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
4605 SmallVector<PortInfo, 8> portList;
4606 SmallVector<SMLoc> portLocs;
4607 LocWithInfo info(getToken().getLoc(),
this);
4609 if (requireFeature({3, 2, 0},
"classes"))
4612 consumeToken(FIRToken::kw_extclass);
4613 if (parseId(name,
"expected extclass name") ||
4614 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
4615 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4618 if (name == circuit.getName())
4619 return mlir::emitError(info.getLoc(),
4620 "extclass cannot be the top of a circuit");
4622 for (
auto &portInfo : portList)
4623 if (!isa<PropertyType>(portInfo.type))
4624 return mlir::emitError(portInfo.loc,
4625 "ports on extclasses must be properties");
4628 auto builder = circuit.getBodyBuilder();
4629 auto extClassOp =
builder.create<ExtClassOp>(info.getLoc(), name, portList);
4632 getConstants().classMap[name.getValue()] = extClassOp;
4633 return skipToModuleEnd(indent);
4640 ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
4643 SmallVector<PortInfo, 8> portList;
4644 SmallVector<SMLoc> portLocs;
4645 LocWithInfo info(getToken().getLoc(),
this);
4646 consumeToken(FIRToken::kw_extmodule);
4647 if (parseId(name,
"expected extmodule name") ||
4648 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
4649 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4653 if (consumeIf(FIRToken::kw_defname)) {
4654 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
4655 parseId(defName,
"expected defname name"))
4659 ArrayAttr parameters;
4660 ArrayAttr internalPaths;
4664 auto builder = circuit.getBodyBuilder();
4665 auto convention = getConstants().options.scalarizeExtModules
4666 ? Convention::Scalarized
4667 : Convention::Internal;
4670 builder.create<FExtModuleOp>(info.getLoc(), name, conventionAttr, portList,
4671 defName, annotations, parameters, internalPaths);
4679 ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
4682 SmallVector<PortInfo, 8> portList;
4683 SmallVector<SMLoc> portLocs;
4684 LocWithInfo info(getToken().getLoc(),
this);
4685 consumeToken(FIRToken::kw_intmodule);
4686 if (parseId(name,
"expected intmodule name") ||
4687 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
4688 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4692 if (consumeIf(FIRToken::kw_intrinsic)) {
4693 if (parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
4694 parseId(intName,
"expected intrinsic name"))
4698 ArrayAttr parameters;
4699 ArrayAttr internalPaths;
4703 ArrayAttr annotations = getConstants().emptyArrayAttr;
4704 auto builder = circuit.getBodyBuilder();
4705 builder.create<FIntModuleOp>(info.getLoc(), name, portList, intName,
4706 annotations, parameters, internalPaths);
4711 ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
unsigned indent) {
4713 SmallVector<PortInfo, 8> portList;
4714 SmallVector<SMLoc> portLocs;
4715 LocWithInfo info(getToken().getLoc(),
this);
4716 consumeToken(FIRToken::kw_module);
4717 if (parseId(name,
"expected module name") ||
4718 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
4719 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4722 auto circuitName = circuit.getName();
4723 auto isMainModule = (name == circuitName);
4724 ArrayAttr annotations = getConstants().emptyArrayAttr;
4725 auto convention = Convention::Internal;
4726 if (isMainModule && getConstants().options.scalarizeTopModule)
4727 convention = Convention::Scalarized;
4729 auto builder = circuit.getBodyBuilder();
4730 auto moduleOp =
builder.create<FModuleOp>(info.getLoc(), name, conventionAttr,
4731 portList, annotations);
4732 auto visibility = isMainModule ? SymbolTable::Visibility::Public
4733 : SymbolTable::Visibility::Private;
4734 SymbolTable::setSymbolVisibility(moduleOp, visibility);
4738 deferredModules.emplace_back(DeferredModuleToParse{
4739 moduleOp, portLocs, getLexer().getCursor(), indent});
4741 if (skipToModuleEnd(indent))
4746 ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
4748 switch (getToken().getKind()) {
4749 case FIRToken::kw_class:
4750 return parseClass(circuit, indent);
4751 case FIRToken::kw_declgroup:
4752 if (requireFeature({3, 1, 0},
"optional groups"))
4754 return parseGroupDecl(circuit);
4755 case FIRToken::kw_extclass:
4756 return parseExtClass(circuit, indent);
4757 case FIRToken::kw_extmodule:
4758 return parseExtModule(circuit, indent);
4759 case FIRToken::kw_intmodule:
4760 return parseIntModule(circuit, indent);
4761 case FIRToken::kw_module:
4762 return parseModule(circuit, indent);
4763 case FIRToken::kw_type:
4764 return parseTypeDecl();
4766 return emitError(getToken().getLoc(),
"unknown toplevel definition");
4771 ParseResult FIRCircuitParser::parseTypeDecl() {
4775 auto loc = getToken().getLoc();
4777 if (getToken().isKeyword())
4778 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
4779 <<
"' for type alias name";
4781 if (parseId(
id,
"expected type name") ||
4782 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
4788 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
4792 <<
"type alias for non-base type " << type
4793 <<
" is currently not supported. Type alias is stripped immediately";
4795 if (!getConstants().aliasMap.insert({id, type}).second)
4796 return emitError(loc) <<
"type alias `" << name.getValue()
4797 <<
"` is already defined";
4802 ParseResult FIRCircuitParser::parseGroupDecl(CircuitOp circuit) {
4803 auto baseIndent = getIndentation();
4806 SmallVector<std::pair<std::optional<unsigned>, GroupDeclOp>> groupStack;
4809 auto parseOne = [&](
Block *block) -> ParseResult {
4810 auto indent = getIndentation();
4811 StringRef id, convention;
4812 LocWithInfo info(getToken().getLoc(),
this);
4814 if (parseId(
id,
"expected group name") || parseGetSpelling(convention))
4816 auto groupConvention = symbolizeGroupConvention(convention);
4817 if (!groupConvention) {
4818 emitError() <<
"unknown convention '" << convention
4819 <<
"' (did you misspell it?)";
4823 if (parseToken(FIRToken::colon,
"expected ':' after group definition") ||
4824 info.parseOptionalInfo())
4826 auto builder = OpBuilder::atBlockEnd(block);
4829 builder.create<GroupDeclOp>(info.getLoc(), id, *groupConvention);
4830 groupDeclOp->getRegion(0).push_back(
new Block());
4831 groupStack.push_back({indent, groupDeclOp});
4835 if (parseOne(circuit.getBodyBlock()))
4839 while (getIndentation() > baseIndent) {
4840 switch (getToken().getKind()) {
4841 case FIRToken::kw_declgroup: {
4844 while (groupStack.back().first >= getIndentation())
4845 groupStack.pop_back();
4846 auto parentGroup = groupStack.back().second;
4847 if (parseOne(&parentGroup.getBody().front()))
4852 return emitError(
"expected 'declgroup'"), failure();
4861 FIRCircuitParser::parseModuleBody(DeferredModuleToParse &deferredModule) {
4862 FModuleLike moduleOp = deferredModule.moduleOp;
4863 auto &body = moduleOp->getRegion(0).front();
4864 auto &portLocs = deferredModule.portLocs;
4868 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
4871 deferredModule.lexerCursor.restore(moduleBodyLexer);
4873 FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
4877 auto portList = moduleOp.getPorts();
4878 auto portArgs = body.getArguments();
4879 for (
auto tuple : llvm::zip(portList, portLocs, portArgs)) {
4880 PortInfo &port = std::get<0>(tuple);
4881 llvm::SMLoc loc = std::get<1>(tuple);
4882 BlockArgument portArg = std::get<2>(tuple);
4884 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
4888 hw::InnerSymbolNamespace modNameSpace(moduleOp);
4889 FIRStmtParser stmtParser(body, moduleContext, modNameSpace, version);
4892 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
4900 SmallVector<PrintFOp> buffer;
4901 deferredModule.moduleOp.walk(
4902 [&buffer](PrintFOp printFOp) { buffer.push_back(printFOp); });
4904 for (
auto printFOp : buffer) {
4911 deferredModule.moduleOp.walk([](Forceable fop) {
4912 if (fop.isForceable() && fop.getDataRef().use_empty())
4927 ParseResult FIRCircuitParser::parseCircuit(
4928 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
4929 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBufs,
4930 mlir::TimingScope &ts) {
4932 auto indent = getIndentation();
4933 if (consumeIf(FIRToken::kw_FIRRTL)) {
4934 if (!indent.has_value())
4935 return emitError(
"'FIRRTL' must be first token on its line"), failure();
4936 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
4937 parseVersionLit(
"expected version literal"))
4939 indent = getIndentation();
4942 if (!indent.has_value())
4943 return emitError(
"'circuit' must be first token on its line"), failure();
4944 unsigned circuitIndent = *indent;
4946 LocWithInfo info(getToken().getLoc(),
this);
4948 SMLoc inlineAnnotationsLoc;
4949 StringRef inlineAnnotations;
4952 if (parseToken(FIRToken::kw_circuit,
4953 "expected a top-level 'circuit' definition") ||
4954 parseId(name,
"expected circuit name") ||
4955 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
4956 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
4957 info.parseOptionalInfo())
4961 OpBuilder b(mlirModule.getBodyRegion());
4962 auto circuit = b.create<CircuitOp>(info.getLoc(), name);
4965 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
4971 SmallVector<Attribute> annos;
4972 if (!inlineAnnotations.empty())
4973 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
4977 for (
auto *annotationsBuf : annotationsBufs)
4978 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
4982 parseAnnotationTimer.stop();
4983 auto parseOMIRTimer = ts.nest(
"Parse OMIR");
4987 for (
auto *omirBuf : omirBufs)
4988 if (importOMIR(circuit, info.getFIRLoc(), omirBuf->getBuffer(), annos))
4991 parseOMIRTimer.stop();
4999 auto parseTimer = ts.nest(
"Parse modules");
5000 deferredModules.reserve(16);
5004 switch (getToken().getKind()) {
5012 case FIRToken::error:
5016 emitError(
"unexpected token in circuit");
5019 case FIRToken::kw_class:
5020 case FIRToken::kw_declgroup:
5021 case FIRToken::kw_extclass:
5022 case FIRToken::kw_extmodule:
5023 case FIRToken::kw_intmodule:
5024 case FIRToken::kw_module:
5025 case FIRToken::kw_type: {
5026 auto indent = getIndentation();
5027 if (!indent.has_value())
5028 return emitError(
"'module' must be first token on its line"), failure();
5029 unsigned definitionIndent = *indent;
5031 if (definitionIndent <= circuitIndent)
5032 return emitError(
"module should be indented more"), failure();
5034 if (parseToplevelDefinition(circuit, definitionIndent))
5048 (void)getLexer().translateLocation(info.getFIRLoc());
5051 auto anyFailed = mlir::failableParallelForEachN(
5052 getContext(), 0, deferredModules.size(), [&](
size_t index) {
5053 if (parseModuleBody(deferredModules[index]))
5057 if (failed(anyFailed))
5060 auto main = circuit.getMainModule();
5063 if (circuit.getOps<FModuleLike>().empty()) {
5064 return mlir::emitError(circuit.getLoc())
5065 <<
"no modules found, circuit must contain one or more modules";
5067 if (
auto *notModule = circuit.lookupSymbol(circuit.getName())) {
5068 return notModule->emitOpError()
5069 <<
"cannot have the same name as the circuit";
5071 return mlir::emitError(circuit.getLoc())
5072 <<
"no main module found, circuit '" << circuit.getName()
5073 <<
"' must contain a module named '" << circuit.getName() <<
"'";
5078 if (
auto mainMod = dyn_cast<FModuleOp>(*
main)) {
5079 for (
auto mod : circuit.getOps<FModuleLike>()) {
5081 SymbolTable::setSymbolVisibility(mod, SymbolTable::Visibility::Private);
5086 for (
auto &pi : mainMod.getPorts()) {
5087 if (!pi.isOutput() && type_isa<RefType>(pi.type))
5088 return mlir::emitError(pi.loc)
5089 <<
"main module may not contain input references";
5103 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
5104 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
5105 unsigned fileID = 1;
5107 annotationsBufs.push_back(
5108 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5110 SmallVector<const llvm::MemoryBuffer *> omirBufs;
5111 for (
unsigned e = sourceMgr.getNumBuffers(); fileID < e; ++fileID)
5113 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5115 context->loadDialect<CHIRRTLDialect>();
5116 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
5122 SharedParserConstants state(context, options);
5123 FIRLexer lexer(sourceMgr, context);
5125 if (FIRCircuitParser(state, lexer, *module, version)
5126 .parseCircuit(annotationsBufs, omirBufs, ts))
5131 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
5132 if (failed(verify(*module)))
5139 static mlir::TranslateToMLIRRegistration fromFIR(
5140 "import-firrtl",
"import .fir",
5141 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
5142 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
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 ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static int64_t size(hw::ArrayType mType, capnp::schema::Field::Reader cField)
Returns the expected size of an array (capnp list) in 64-bit words.
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 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.
int main(int argc, const char *argv[])
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
Forceable replaceWithNewForceability(Forceable op, bool forceable, ::mlir::PatternRewriter *rewriter=nullptr)
Replace a Forceable op with equivalent, changing whether forceable.
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
constexpr FIRVersion defaultFIRVersion(1, 0, 0)
Flow swapFlow(Flow flow)
Get a flow's reverse.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
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.
bool areTypesWeaklyEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destFlip=false, bool srcFlip=false, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false)
Returns true if two types are weakly 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.
ParseResult foldWhenEncodedVerifOp(PrintFOp printOp)
Chisel has a tendency to emit complex assert/assume/cover statements encoded as print operations with...
Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value, unsigned fieldID)
This gets the value targeted by a field id.
bool fromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
constexpr FIRVersion minimumFIRVersion(0, 2, 0)
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,...
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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