25 #include "mlir/IR/BuiltinOps.h"
26 #include "mlir/IR/BuiltinTypes.h"
27 #include "mlir/IR/Diagnostics.h"
28 #include "mlir/IR/ImplicitLocOpBuilder.h"
29 #include "mlir/IR/PatternMatch.h"
30 #include "mlir/IR/Threading.h"
31 #include "mlir/IR/Verifier.h"
32 #include "mlir/Support/Timing.h"
33 #include "mlir/Tools/mlir-translate/Translation.h"
34 #include "llvm/ADT/PointerEmbeddedInt.h"
35 #include "llvm/ADT/STLExtras.h"
36 #include "llvm/ADT/SmallPtrSet.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/ADT/StringSet.h"
39 #include "llvm/ADT/StringSwitch.h"
40 #include "llvm/ADT/TypeSwitch.h"
41 #include "llvm/Support/JSON.h"
42 #include "llvm/Support/SourceMgr.h"
43 #include "llvm/Support/raw_ostream.h"
46 using namespace circt;
47 using namespace firrtl;
48 using namespace chirrtl;
51 using llvm::SourceMgr;
52 using mlir::LocationAttr;
65 struct SharedParserConstants {
67 : context(context), options(options),
68 emptyArrayAttr(ArrayAttr::
get(context, {})),
76 MLIRContext *
const context;
82 llvm::StringMap<FIRRTLType> aliasMap;
85 llvm::DenseMap<StringRef, ClassLike> classMap;
88 const ArrayAttr emptyArrayAttr;
91 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
92 const StringAttr fieldIndexIdentifier, indexIdentifier;
95 SharedParserConstants(
const SharedParserConstants &) =
delete;
96 void operator=(
const SharedParserConstants &) =
delete;
109 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
111 : version(version), constants(constants), lexer(lexer),
112 locatorFilenameCache(constants.loIdentifier ) {
116 SharedParserConstants &getConstants()
const {
return constants; }
117 MLIRContext *getContext()
const {
return constants.context; }
119 FIRLexer &getLexer() {
return lexer; }
122 std::optional<unsigned> getIndentation()
const {
127 const FIRToken &getToken()
const {
return lexer.getToken(); }
128 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
135 InFlightDiagnostic emitError(
const Twine &message = {}) {
136 return emitError(getToken().getLoc(), message);
138 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
141 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
142 return emitWarning(getToken().getLoc(), message);
145 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
155 Location translateLocation(llvm::SMLoc loc) {
156 return lexer.translateLocation(loc);
161 ParseResult parseOptionalInfoLocator(LocationAttr &result);
165 ParseResult parseOptionalName(StringAttr &name);
171 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
172 return requireFeature(minimum, feature, getToken().getLoc());
175 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
176 if (version < minimum)
177 return emitError(loc)
178 << feature <<
" are a FIRRTL " << minimum
179 <<
"+ feature, but the specified FIRRTL version was " << version;
183 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
184 return removedFeature(removedVersion, feature, getToken().getLoc());
187 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
189 if (version >= removedVersion)
190 return emitError(loc)
191 << feature <<
" were removed in FIRRTL " << removedVersion
192 <<
", but the specified FIRRTL version was " << version;
202 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
211 if (getToken().isNot(kind))
221 FIRToken consumedToken = getToken();
222 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
223 "shouldn't advance past EOF or errors");
225 return consumedToken;
234 FIRToken consumedToken = getToken();
235 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
237 return consumedToken;
242 ParseResult parseGetSpelling(StringRef &spelling) {
243 spelling = getTokenSpelling();
249 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
253 const std::function<ParseResult()> &parseElement);
260 ParseResult parseIntLit(APInt &result,
const Twine &message);
261 ParseResult parseIntLit(int64_t &result,
const Twine &message);
262 ParseResult parseIntLit(int32_t &result,
const Twine &message);
265 ParseResult parseVersionLit(
const Twine &message);
268 template <
typename T>
269 ParseResult parseOptionalWidth(T &result);
272 ParseResult parseId(StringRef &result,
const Twine &message);
273 ParseResult parseId(StringAttr &result,
const Twine &message);
274 ParseResult parseFieldId(StringRef &result,
const Twine &message);
275 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
276 const Twine &message);
277 ParseResult parseEnumType(
FIRRTLType &result);
278 ParseResult parseListType(
FIRRTLType &result);
281 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
283 ParseResult parseOptionalRUW(RUWAttr &result);
285 ParseResult parseParameter(StringAttr &resultName, TypedAttr &resultValue,
292 FIRParser(
const FIRParser &) =
delete;
293 void operator=(
const FIRParser &) =
delete;
297 SharedParserConstants &constants;
301 StringAttr locatorFilenameCache;
303 FileLineColLoc fileLineColLocCache;
312 InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
313 auto diag = mlir::emitError(translateLocation(loc), message);
317 if (getToken().is(FIRToken::error))
322 InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
323 return mlir::emitWarning(translateLocation(loc), message);
333 const Twine &message) {
334 if (consumeIf(expectedToken))
336 return emitError(message);
342 const std::function<ParseResult()> &parseElement) {
344 while (!consumeIf(rightToken)) {
362 : parser(parser), firLoc(firLoc) {}
369 auto result = parser->translateLocation(firLoc);
377 if (failed(parser->parseOptionalInfoLocator(loc)))
381 switch (parser->constants.options.infoLocatorHandling) {
382 case ILH::IgnoreInfo:
383 assert(0 &&
"Should not return info locations if ignoring");
385 case ILH::PreferInfo:
390 {loc, parser->translateLocation(firLoc)});
417 ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
418 if (getToken().isNot(FIRToken::fileinfo))
421 auto loc = getToken().getLoc();
423 auto spelling = getTokenSpelling();
424 consumeToken(FIRToken::fileinfo);
428 constants.options.infoLocatorHandling ==
430 locatorFilenameCache, fileLineColLocCache, getContext());
433 if (!locationPair.first) {
434 mlir::emitWarning(translateLocation(loc),
435 "ignoring unknown @ info record format");
441 if (locationPair.first && constants.options.infoLocatorHandling ==
446 result = *locationPair.second;
454 ParseResult FIRParser::parseOptionalName(StringAttr &name) {
456 if (getToken().isNot(FIRToken::colon)) {
461 consumeToken(FIRToken::colon);
463 if (parseId(nameRef,
"expected result name"))
477 ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
479 if (getToken().isNot(FIRToken::inlineannotation))
482 loc = getToken().getLoc();
484 result = getTokenSpelling().drop_front(2).drop_back(1);
485 consumeToken(FIRToken::inlineannotation);
503 ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
504 auto spelling = getTokenSpelling();
505 bool isNegative =
false;
506 switch (getToken().getKind()) {
507 case FIRToken::signed_integer:
508 isNegative = spelling[0] ==
'-';
509 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
510 spelling = spelling.drop_front();
512 case FIRToken::integer:
513 if (spelling.getAsInteger(10, result))
514 return emitError(message), failure();
518 if (result.isNegative())
519 result = result.zext(result.getBitWidth() + 1);
528 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
529 result = result.trunc(32);
533 case FIRToken::radix_specified_integer: {
534 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
536 if (spelling[0] ==
'-') {
538 spelling = spelling.drop_front();
540 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
545 spelling = spelling.drop_front(2);
546 if (spelling.getAsInteger(base, result))
547 return emitError(
"invalid character in integer literal"), failure();
548 if (result.isNegative())
549 result = result.zext(result.getBitWidth() + 1);
555 case FIRToken::string: {
558 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
561 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
562 spelling = spelling.drop_back().drop_front();
566 switch (spelling.empty() ?
' ' : spelling.front()) {
577 return emitError(
"expected base specifier (h/o/b) in integer literal"),
580 spelling = spelling.drop_front();
583 bool isNegative =
false;
584 if (!spelling.empty() && spelling.front() ==
'+')
585 spelling = spelling.drop_front();
586 else if (!spelling.empty() && spelling.front() ==
'-') {
588 spelling = spelling.drop_front();
592 if (spelling.empty())
593 return emitError(
"expected digits in integer literal"), failure();
595 if (spelling.getAsInteger(base, result))
596 return emitError(
"invalid character in integer literal"), failure();
601 if (result.isNegative())
602 result = result.zext(result.getBitWidth() + 1);
607 consumeToken(FIRToken::string);
612 return emitError(
"expected integer literal"), failure();
616 ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
618 auto loc = getToken().getLoc();
619 if (parseIntLit(value, message))
622 result = (int64_t)value.getLimitedValue(INT64_MAX);
624 return emitError(loc,
"value is too big to handle"), failure();
628 ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
630 auto loc = getToken().getLoc();
631 if (parseIntLit(value, message))
634 result = (int32_t)value.getLimitedValue(INT32_MAX);
636 return emitError(loc,
"value is too big to handle"), failure();
642 ParseResult FIRParser::parseVersionLit(
const Twine &message) {
643 auto spelling = getTokenSpelling();
644 if (getToken().getKind() != FIRToken::version)
645 return emitError(message), failure();
647 auto [a, d] = spelling.split(
".");
648 auto [b, c] = d.split(
".");
649 APInt aInt, bInt, cInt;
650 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
651 c.getAsInteger(10, cInt))
652 return emitError(
"failed to parse version string"), failure();
653 version.major = aInt.getLimitedValue(UINT32_MAX);
654 version.minor = bInt.getLimitedValue(UINT32_MAX);
655 version.patch = cInt.getLimitedValue(UINT32_MAX);
656 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
657 return emitError(
"integers out of range"), failure();
661 consumeToken(FIRToken::version);
668 template <
typename T>
669 ParseResult FIRParser::parseOptionalWidth(T &result) {
670 if (!consumeIf(FIRToken::less))
671 return result = -1, success();
674 auto widthLoc = getToken().getLoc();
675 if (parseIntLit(result,
"expected width") ||
676 parseToken(FIRToken::greater,
"expected >"))
680 return emitError(widthLoc,
"invalid width specifier"), failure();
689 ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
690 switch (getToken().getKind()) {
692 case FIRToken::identifier:
693 case FIRToken::literal_identifier:
695 #define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
696 #include "FIRTokenKinds.def"
701 if (getToken().getKind() == FIRToken::literal_identifier)
702 result = getTokenSpelling().drop_front().drop_back();
704 result = getTokenSpelling();
714 ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
716 if (parseId(name, message))
728 ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
730 result = getTokenSpelling();
731 if (consumeIf(FIRToken::integer))
737 if (parseId(result, message))
749 ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
750 const Twine &message) {
752 StringRef tmp = getTokenSpelling();
754 if (consumeIf(FIRToken::integer)) {
755 result.push_back(tmp);
759 if (consumeIf(FIRToken::floatingpoint)) {
763 auto [a, b] = tmp.split(
".");
769 if (consumeIf(FIRToken::version)) {
771 auto [a, d] = tmp.split(
".");
772 auto [b, c] = d.split(
".");
780 if (parseId(tmp, message))
782 result.push_back(tmp);
788 ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
789 if (parseToken(FIRToken::l_brace_bar,
790 "expected leading '{|' in enumeration type"))
792 SmallVector<FEnumType::EnumElement> elements;
793 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
794 auto fieldLoc = getToken().getLoc();
798 if (parseId(name,
"expected valid identifier for enumeration tag"))
803 if (consumeIf(FIRToken::colon)) {
805 if (
parseType(parsedType,
"expected enumeration type"))
807 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
809 return emitError(fieldLoc,
"field must be a base type");
822 ParseResult FIRParser::parsePropertyType(
PropertyType &result,
823 const Twine &message) {
827 auto prop = type_dyn_cast<PropertyType>(type);
829 return emitError(
"expected property type");
835 ParseResult FIRParser::parseListType(
FIRRTLType &result) {
836 consumeToken(FIRToken::kw_List);
839 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
840 parsePropertyType(
elementType,
"expected List element type") ||
841 parseToken(FIRToken::greater,
"expected '>' in List type"))
867 switch (getToken().getKind()) {
869 return emitError(message), failure();
871 case FIRToken::kw_Clock:
872 consumeToken(FIRToken::kw_Clock);
876 case FIRToken::kw_Inst: {
880 consumeToken(FIRToken::kw_Inst);
881 if (parseToken(FIRToken::less,
"expected < in Inst type"))
884 auto loc = getToken().getLoc();
886 if (parseId(
id,
"expected class name in Inst type"))
890 const auto &classMap = getConstants().classMap;
891 auto lookup = classMap.find(
id);
892 if (lookup == classMap.end())
893 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
895 auto classOp = lookup->second;
897 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
900 result = classOp.getInstanceType();
904 case FIRToken::kw_AnyRef: {
908 consumeToken(FIRToken::kw_AnyRef);
913 case FIRToken::kw_Reset:
914 consumeToken(FIRToken::kw_Reset);
918 case FIRToken::kw_AsyncReset:
919 consumeToken(FIRToken::kw_AsyncReset);
923 case FIRToken::kw_UInt:
924 case FIRToken::kw_SInt:
925 case FIRToken::kw_Analog: {
926 auto kind = getToken().getKind();
931 if (parseOptionalWidth(
width))
934 if (kind == FIRToken::kw_SInt)
936 else if (kind == FIRToken::kw_UInt)
939 assert(kind == FIRToken::kw_Analog);
945 case FIRToken::kw_Probe:
946 case FIRToken::kw_RWProbe: {
947 auto kind = getToken().getKind();
948 auto loc = getToken().getLoc();
953 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
954 parseType(type,
"expected probe data type"))
958 SmallVector<StringRef> layers;
959 if (getToken().getKind() == FIRToken::identifier) {
960 if (requireFeature({3, 2, 0},
"colored probes"))
964 loc = getToken().getLoc();
965 if (parseId(layer,
"expected layer name"))
967 layers.push_back(layer);
968 }
while (consumeIf(FIRToken::period));
971 if (!consumeIf(FIRToken::greater))
972 return emitError(loc,
"expected '>' to end reference type");
974 bool forceable = kind == FIRToken::kw_RWProbe;
976 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
978 return emitError(loc,
"invalid probe inner type, must be base-type");
981 return emitError(loc,
"probe inner type must be passive");
983 if (forceable &&
innerType.containsConst())
984 return emitError(loc,
"rwprobe cannot contain const");
987 if (!layers.empty()) {
989 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
993 llvm::to_vector(nestedLayers));
1000 case FIRToken::l_brace: {
1001 consumeToken(FIRToken::l_brace);
1003 SmallVector<OpenBundleType::BundleElement, 4> elements;
1004 bool bundleCompatible =
true;
1005 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1006 bool isFlipped = consumeIf(FIRToken::kw_flip);
1008 StringRef fieldName;
1010 if (parseFieldId(fieldName,
"expected bundle field name") ||
1011 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1013 if (
parseType(type,
"expected bundle field type"))
1018 bundleCompatible &= isa<BundleType::ElementType>(type);
1024 if (bundleCompatible) {
1025 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1026 return BundleType::BundleElement{
1027 element.name, element.isFlip,
1028 cast<BundleType::ElementType>(element.type)};
1030 result =
BundleType::get(getContext(), llvm::to_vector(bundleElements));
1036 case FIRToken::l_brace_bar: {
1037 if (parseEnumType(result))
1042 case FIRToken::identifier: {
1044 auto loc = getToken().getLoc();
1045 if (parseId(
id,
"expected a type alias name"))
1047 auto it = constants.aliasMap.find(
id);
1048 if (it == constants.aliasMap.end()) {
1049 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1052 result = it->second;
1056 case FIRToken::kw_const: {
1057 consumeToken(FIRToken::kw_const);
1058 auto nextToken = getToken();
1059 auto loc = nextToken.getLoc();
1062 if (nextToken.is(FIRToken::kw_const))
1063 return emitError(loc,
"'const' can only be specified once on a type");
1068 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1070 return emitError(loc,
"only hardware types can be 'const'");
1072 result = baseType.getConstType(
true);
1076 case FIRToken::kw_String:
1077 if (requireFeature({3, 1, 0},
"Strings"))
1079 consumeToken(FIRToken::kw_String);
1082 case FIRToken::kw_Integer:
1083 if (requireFeature({3, 1, 0},
"Integers"))
1085 consumeToken(FIRToken::kw_Integer);
1088 case FIRToken::kw_Bool:
1091 consumeToken(FIRToken::kw_Bool);
1094 case FIRToken::kw_Double:
1097 consumeToken(FIRToken::kw_Double);
1100 case FIRToken::kw_Path:
1103 consumeToken(FIRToken::kw_Path);
1106 case FIRToken::kw_List:
1107 if (requireFeature(
nextFIRVersion,
"Lists") || parseListType(result))
1113 while (consumeIf(FIRToken::l_square)) {
1114 auto sizeLoc = getToken().getLoc();
1116 if (parseIntLit(size,
"expected width") ||
1117 parseToken(FIRToken::r_square,
"expected ]"))
1121 return emitError(sizeLoc,
"invalid size specifier"), failure();
1123 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1134 ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1135 switch (getToken().getKind()) {
1139 case FIRToken::kw_old:
1140 result = RUWAttr::Old;
1141 consumeToken(FIRToken::kw_old);
1143 case FIRToken::kw_new:
1144 result = RUWAttr::New;
1145 consumeToken(FIRToken::kw_new);
1147 case FIRToken::kw_undefined:
1148 result = RUWAttr::Undefined;
1149 consumeToken(FIRToken::kw_undefined);
1160 ParseResult FIRParser::parseParameter(StringAttr &resultName,
1161 TypedAttr &resultValue,
1163 mlir::Builder
builder(getContext());
1165 auto loc = getToken().getLoc();
1168 if (parseId(name,
"expected parameter name") ||
1169 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1173 switch (getToken().getKind()) {
1175 return emitError(
"expected parameter value"), failure();
1176 case FIRToken::integer:
1177 case FIRToken::signed_integer: {
1179 if (parseIntLit(result,
"invalid integer parameter"))
1185 if (result.getBitWidth() < 32)
1186 result = result.sext(32);
1188 value =
builder.getIntegerAttr(
1189 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1193 case FIRToken::string: {
1195 value =
builder.getStringAttr(getToken().getStringValue());
1196 consumeToken(FIRToken::string);
1199 case FIRToken::verbatim_string: {
1201 auto text =
builder.getStringAttr(getToken().getVerbatimStringValue());
1203 consumeToken(FIRToken::verbatim_string);
1206 case FIRToken::floatingpoint:
1208 if (!llvm::to_float(getTokenSpelling(), v))
1209 return emitError(
"invalid float parameter syntax"), failure();
1211 value =
builder.getF64FloatAttr(v);
1212 consumeToken(FIRToken::floatingpoint);
1216 resultName =
builder.getStringAttr(name);
1217 resultValue = value;
1233 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1241 struct UnbundledValueRestorer {
1243 size_t startingSize;
1245 startingSize = list.size();
1247 ~UnbundledValueRestorer() { list.resize(startingSize); }
1256 struct FIRModuleContext :
public FIRParser {
1257 explicit FIRModuleContext(SharedParserConstants &constants,
FIRLexer &lexer,
1259 : FIRParser(constants, lexer, version) {}
1265 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1268 Value getCachedConstantInt(ImplicitLocOpBuilder &
builder, Attribute attr,
1270 auto &result = constantCache[{attr, type}];
1276 OpBuilder::InsertPoint savedIP;
1278 auto *parentOp =
builder.getInsertionBlock()->getParentOp();
1279 if (!isa<FModuleOp>(parentOp)) {
1280 savedIP =
builder.saveInsertionPoint();
1281 while (!isa<FModuleOp>(parentOp)) {
1282 builder.setInsertionPoint(parentOp);
1283 parentOp =
builder.getInsertionBlock()->getParentOp();
1287 result =
builder.create<ConstantOp>(type, value);
1289 if (savedIP.isSet())
1290 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1301 Value &getCachedSubaccess(Value value,
unsigned index) {
1302 auto &result = subaccessCache[{value, index}];
1305 auto it = scopeMap.find(value.getParentBlock());
1306 if (it != scopeMap.end())
1307 it->second->scopedSubaccesses.push_back({result, index});
1317 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1318 bool insertNameIntoGlobalScope =
false);
1319 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1320 bool insertNameIntoGlobalScope =
false) {
1322 insertNameIntoGlobalScope);
1327 SMLoc loc,
bool fatal =
true);
1332 StringRef field, SMLoc loc);
1340 assert(index < unbundledValues.size());
1341 return unbundledValues[index];
1351 struct ContextScope {
1352 friend struct FIRModuleContext;
1353 ContextScope(FIRModuleContext &moduleContext, Block *block)
1354 : moduleContext(moduleContext), block(block),
1355 previousScope(moduleContext.currentScope) {
1356 moduleContext.currentScope =
this;
1357 moduleContext.scopeMap[block] =
this;
1362 for (
auto *entryPtr : scopedDecls)
1363 entryPtr->second.first = SMLoc();
1366 for (
auto subaccess : scopedSubaccesses)
1367 moduleContext.subaccessCache.erase(subaccess);
1369 moduleContext.scopeMap.erase(block);
1371 moduleContext.currentScope = previousScope;
1375 void operator=(
const ContextScope &) =
delete;
1376 ContextScope(
const ContextScope &) =
delete;
1378 FIRModuleContext &moduleContext;
1380 ContextScope *previousScope;
1381 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1382 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1396 DenseMap<Block *, ContextScope *> scopeMap;
1401 ContextScope *currentScope =
nullptr;
1412 ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1414 bool insertNameIntoGlobalScope) {
1419 if (entryIt->second.first.isValid()) {
1420 emitError(loc,
"redefinition of name '" + name +
"'")
1421 .attachNote(translateLocation(entryIt->second.first))
1422 <<
"previous definition here";
1428 entryIt->second = {loc, entry};
1429 if (currentScope && !insertNameIntoGlobalScope)
1430 currentScope->scopedDecls.push_back(&*entryIt);
1438 StringRef name, SMLoc loc) {
1439 auto &entry = symbolTable[name];
1440 if (!entry.first.isValid())
1441 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1442 result = entry.second;
1443 assert(result &&
"name in symbol table without definition");
1447 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1449 SMLoc loc,
bool fatal) {
1450 if (!entry.is<Value>()) {
1452 emitError(loc,
"bundle value should only be used from subfield");
1455 result = entry.get<Value>();
1459 ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1461 StringRef fieldName,
1464 emitError(loc,
"value should not be used from subfield");
1470 unsigned unbundledId = entry.get<
UnbundledID>() - 1;
1471 assert(unbundledId < unbundledValues.size());
1473 for (
auto elt : ubEntry) {
1474 if (elt.first == fieldAttr) {
1475 result = elt.second;
1480 emitError(loc,
"use of invalid field name '")
1481 << fieldName <<
"' on bundle value";
1507 struct LazyLocationListener :
public OpBuilder::Listener {
1513 ~LazyLocationListener() {
1514 assert(subOps.empty() &&
"didn't process parsed operations");
1519 void startStatement() {
1520 assert(!isActive &&
"Already processing a statement");
1526 void endStatement(FIRParser &parser) {
1527 assert(isActive &&
"Not parsing a statement");
1531 for (
auto opAndSMLoc : subOps) {
1535 switch (parser.getConstants().options.infoLocatorHandling) {
1536 case ILH::IgnoreInfo:
1538 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1540 case ILH::PreferInfo:
1541 opAndSMLoc.first->setLoc(infoLoc);
1543 case ILH::FusedInfo:
1545 infoLoc.getContext(),
1546 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1553 for (
auto opAndSMLoc : subOps)
1554 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1559 infoLoc = LocationAttr();
1560 currentSMLoc = SMLoc();
1565 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1568 void setInfoLoc(LocationAttr loc) {
1569 assert(!infoLoc &&
"Info location multiply specified");
1575 void notifyOperationInserted(Operation *op,
1576 mlir::IRRewriter::InsertPoint)
override {
1577 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1578 assert(isActive &&
"Not parsing a statement");
1579 subOps.push_back({op, currentSMLoc});
1584 bool isActive =
false;
1592 LocationAttr infoLoc;
1599 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1601 void operator=(
const LazyLocationListener &) =
delete;
1602 LazyLocationListener(
const LazyLocationListener &) =
delete;
1609 struct FIRStmtParser :
public FIRParser {
1610 explicit FIRStmtParser(Block &blockToInsertInto,
1611 FIRModuleContext &moduleContext,
1612 hw::InnerSymbolNamespace &modNameSpace,
1613 const SymbolTable &circuitSymTbl,
FIRVersion version,
1614 SymbolRefAttr layerSym = {})
1615 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1618 locationProcessor(this->builder), moduleContext(moduleContext),
1619 modNameSpace(modNameSpace), layerSym(layerSym),
1620 circuitSymTbl(circuitSymTbl) {
1621 builder.setInsertionPointToEnd(&blockToInsertInto);
1624 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1625 ParseResult parseSimpleStmtBlock(
unsigned indent);
1628 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1631 void emitInvalidate(Value val,
Flow flow);
1637 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1640 void emitPartialConnect(ImplicitLocOpBuilder &
builder, Value dst, Value src);
1643 ParseResult parseOptionalInfo() {
1645 if (failed(parseOptionalInfoLocator(loc)))
1647 locationProcessor.setInfoLoc(loc);
1652 ParseResult parseExpImpl(Value &result,
const Twine &message,
1653 bool isLeadingStmt);
1654 ParseResult parseExp(Value &result,
const Twine &message) {
1655 return parseExpImpl(result, message,
false);
1657 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1658 return parseExpImpl(result, message,
true);
1660 ParseResult parseEnumExp(Value &result);
1661 ParseResult parsePathExp(Value &result);
1662 ParseResult parseRefExp(Value &result,
const Twine &message);
1663 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1664 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1665 const Twine &message);
1668 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1669 ParseResult parseIntrinsicStmt() {
1671 return parseIntrinsic(unused,
true);
1673 ParseResult parseIntrinsicExp(Value &result) {
1674 return parseIntrinsic(result,
false);
1676 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1678 template <
typename subop>
1680 ArrayRef<NamedAttribute> attrs,
1681 unsigned indexNo, SMLoc loc);
1682 ParseResult parseOptionalExpPostscript(Value &result,
1683 bool allowDynamic =
true);
1684 ParseResult parsePostFixFieldId(Value &result);
1685 ParseResult parsePostFixIntSubscript(Value &result);
1686 ParseResult parsePostFixDynamicSubscript(Value &result);
1687 ParseResult parsePrimExp(Value &result);
1688 ParseResult parseIntegerLiteralExp(Value &result);
1689 ParseResult parseListExp(Value &result);
1691 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
1694 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
1695 SymbolRefAttr layerSym);
1696 ParseResult parseAttach();
1697 ParseResult parseMemPort(MemDirAttr direction);
1698 ParseResult parsePrintf();
1699 ParseResult parseSkip();
1700 ParseResult parseStop();
1701 ParseResult parseAssert();
1702 ParseResult parseAssume();
1703 ParseResult parseCover();
1704 ParseResult parseWhen(
unsigned whenIndent);
1705 ParseResult parseMatch(
unsigned matchIndent);
1706 ParseResult parseRefDefine();
1707 ParseResult parseRefForce();
1708 ParseResult parseRefForceInitial();
1709 ParseResult parseRefRelease();
1710 ParseResult parseRefReleaseInitial();
1711 ParseResult parseRefRead(Value &result);
1712 ParseResult parseProbe(Value &result);
1713 ParseResult parsePropAssign();
1714 ParseResult parseRWProbe(Value &result);
1715 ParseResult parseLeadingExpStmt(Value lhs);
1716 ParseResult parseConnect();
1717 ParseResult parseInvalidate();
1718 ParseResult parseLayerBlockOrGroup(
unsigned indent);
1721 ParseResult parseInstance();
1722 ParseResult parseInstanceChoice();
1723 ParseResult parseObject();
1724 ParseResult parseCombMem();
1725 ParseResult parseSeqMem();
1726 ParseResult parseMem(
unsigned memIndent);
1727 ParseResult parseNode();
1728 ParseResult parseWire();
1729 ParseResult parseRegister(
unsigned regIndent);
1730 ParseResult parseRegisterWithReset();
1733 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
1737 LazyLocationListener locationProcessor;
1740 FIRModuleContext &moduleContext;
1742 hw::InnerSymbolNamespace &modNameSpace;
1746 SymbolRefAttr layerSym;
1748 const SymbolTable &circuitSymTbl;
1755 void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
1756 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
1763 auto props = tpe.getRecursiveTypeProperties();
1764 if (props.isPassive && !props.containsAnalog) {
1778 TypeSwitch<FIRRTLType>(tpe)
1779 .Case<BundleType>([&](
auto tpe) {
1780 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
1781 auto &subfield = moduleContext.getCachedSubaccess(val, i);
1783 OpBuilder::InsertionGuard guard(
builder);
1784 builder.setInsertionPointAfterValue(val);
1785 subfield =
builder.create<SubfieldOp>(val, i);
1787 emitInvalidate(subfield,
1788 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
1791 .Case<FVectorType>([&](
auto tpe) {
1792 auto tpex = tpe.getElementType();
1793 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
1794 auto &subindex = moduleContext.getCachedSubaccess(val, i);
1796 OpBuilder::InsertionGuard guard(
builder);
1797 builder.setInsertionPointAfterValue(val);
1798 subindex =
builder.create<SubindexOp>(tpex, val, i);
1800 emitInvalidate(subindex, flow);
1805 void FIRStmtParser::emitPartialConnect(ImplicitLocOpBuilder &
builder, Value dst,
1807 auto dstType = type_dyn_cast<FIRRTLBaseType>(dst.getType());
1808 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
1809 if (!dstType || !srcType)
1812 if (type_isa<AnalogType>(dstType)) {
1813 builder.create<AttachOp>(ArrayRef<Value>{dst, src});
1814 }
else if (dstType == srcType && !dstType.containsAnalog()) {
1816 }
else if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
1817 auto srcBundle = type_cast<BundleType>(srcType);
1819 for (
size_t dstIndex = 0; dstIndex <
numElements; ++dstIndex) {
1821 auto &dstElement = dstBundle.getElements()[dstIndex];
1822 auto name = dstElement.name;
1823 auto maybe = srcBundle.getElementIndex(name);
1827 auto dstRef = moduleContext.getCachedSubaccess(dst, dstIndex);
1829 OpBuilder::InsertionGuard guard(
builder);
1830 builder.setInsertionPointAfterValue(dst);
1831 dstRef =
builder.create<SubfieldOp>(dst, dstIndex);
1836 auto dstField = dstRef;
1837 auto srcIndex = *maybe;
1838 auto &srcField = moduleContext.getCachedSubaccess(src, srcIndex);
1840 OpBuilder::InsertionGuard guard(
builder);
1841 builder.setInsertionPointAfterValue(src);
1842 srcField =
builder.create<SubfieldOp>(src, srcIndex);
1844 if (!dstElement.isFlip)
1845 emitPartialConnect(
builder, dstField, srcField);
1847 emitPartialConnect(
builder, srcField, dstField);
1849 }
else if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
1850 auto srcVector = type_cast<FVectorType>(srcType);
1851 auto dstNumElements = dstVector.getNumElements();
1852 auto srcNumEelemnts = srcVector.getNumElements();
1854 auto numElements = std::min(dstNumElements, srcNumEelemnts);
1856 auto &dstRef = moduleContext.getCachedSubaccess(dst, i);
1858 OpBuilder::InsertionGuard guard(
builder);
1859 builder.setInsertionPointAfterValue(dst);
1860 dstRef =
builder.create<SubindexOp>(dst, i);
1862 auto dstField = dstRef;
1863 auto &srcField = moduleContext.getCachedSubaccess(src, i);
1865 OpBuilder::InsertionGuard guard(
builder);
1866 builder.setInsertionPointAfterValue(src);
1867 srcField =
builder.create<SubindexOp>(src, i);
1869 emitPartialConnect(
builder, dstField, srcField);
1899 ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
1900 bool isLeadingStmt) {
1901 switch (getToken().getKind()) {
1904 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
1905 case FIRToken::lp_##SPELLING:
1906 #include "FIRTokenKinds.def"
1907 if (parsePrimExp(result))
1911 case FIRToken::l_brace_bar:
1913 return emitError(
"unexpected enumeration as start of statement");
1914 if (parseEnumExp(result))
1917 case FIRToken::lp_read:
1919 return emitError(
"unexpected read() as start of statement");
1920 if (parseRefRead(result))
1923 case FIRToken::lp_probe:
1925 return emitError(
"unexpected probe() as start of statement");
1926 if (parseProbe(result))
1929 case FIRToken::lp_rwprobe:
1931 return emitError(
"unexpected rwprobe() as start of statement");
1932 if (parseRWProbe(result))
1936 case FIRToken::kw_UInt:
1937 case FIRToken::kw_SInt:
1938 if (parseIntegerLiteralExp(result))
1941 case FIRToken::kw_String: {
1942 if (requireFeature({3, 1, 0},
"Strings"))
1944 locationProcessor.setLoc(getToken().getLoc());
1945 consumeToken(FIRToken::kw_String);
1947 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
1948 parseGetSpelling(spelling) ||
1949 parseToken(FIRToken::string,
1950 "expected string literal in String expression") ||
1951 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
1953 result =
builder.create<StringConstantOp>(
1957 case FIRToken::kw_Integer: {
1958 if (requireFeature({3, 1, 0},
"Integers"))
1960 locationProcessor.setLoc(getToken().getLoc());
1961 consumeToken(FIRToken::kw_Integer);
1963 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
1964 parseIntLit(value,
"expected integer literal in Integer expression") ||
1965 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
1968 builder.create<FIntegerConstantOp>(APSInt(value,
false));
1971 case FIRToken::kw_Bool: {
1974 locationProcessor.setLoc(getToken().getLoc());
1975 consumeToken(FIRToken::kw_Bool);
1976 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
1979 if (consumeIf(FIRToken::kw_true))
1981 else if (consumeIf(FIRToken::kw_false))
1984 return emitError(
"expected true or false in Bool expression");
1985 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
1987 result =
builder.create<BoolConstantOp>(value);
1990 case FIRToken::kw_Double: {
1993 locationProcessor.setLoc(getToken().getLoc());
1994 consumeToken(FIRToken::kw_Double);
1995 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
1997 auto spelling = getTokenSpelling();
1998 if (parseToken(FIRToken::floatingpoint,
1999 "expected floating point in Double expression") ||
2000 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2005 if (!llvm::to_float(spelling, d))
2006 return emitError(
"invalid double");
2007 result =
builder.create<DoubleConstantOp>(
builder.getF64FloatAttr(d));
2010 case FIRToken::kw_List: {
2014 return emitError(
"unexpected List<>() as start of statement");
2015 if (parseListExp(result))
2019 case FIRToken::lp_path:
2021 return emitError(
"unexpected path() as start of statement");
2022 if (requireFeature(
nextFIRVersion,
"paths") || parsePathExp(result))
2026 case FIRToken::lp_intrinsic:
2027 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2028 parseIntrinsicExp(result))
2034 case FIRToken::identifier:
2035 case FIRToken::literal_identifier:
2038 auto loc = getToken().getLoc();
2040 if (parseId(name, message) ||
2041 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2045 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2053 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2054 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2055 parseOptionalInfo())
2058 locationProcessor.setLoc(loc);
2060 unsigned unbundledId = symtabEntry.get<
UnbundledID>() - 1;
2062 moduleContext.getUnbundledEntry(unbundledId);
2063 for (
auto elt : ubEntry)
2064 emitInvalidate(elt.second);
2072 StringRef fieldName;
2073 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2074 parseFieldId(fieldName,
"expected field name") ||
2075 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2081 return parseOptionalExpPostscript(result);
2091 ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2092 bool allowDynamic) {
2097 if (consumeIf(FIRToken::period)) {
2098 if (parsePostFixFieldId(result))
2105 if (consumeIf(FIRToken::l_square)) {
2106 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2107 if (parsePostFixIntSubscript(result))
2112 return emitError(
"subaccess not allowed here");
2113 if (parsePostFixDynamicSubscript(result))
2123 template <
typename subop>
2125 FIRStmtParser::emitCachedSubAccess(Value base, ArrayRef<NamedAttribute> attrs,
2126 unsigned indexNo, SMLoc loc) {
2129 auto resultType = subop::inferReturnType({base}, attrs, {});
2132 (void)subop::inferReturnType({base}, attrs, translateLocation(loc));
2137 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2143 locationProcessor.setLoc(loc);
2144 OpBuilder::InsertionGuard guard(
builder);
2145 builder.setInsertionPointAfterValue(base);
2146 auto op =
builder.create<subop>(resultType, base, attrs);
2149 return value = op.getResult();
2156 ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2157 auto loc = getToken().getLoc();
2158 SmallVector<StringRef, 3> fields;
2159 if (parseFieldIdSeq(fields,
"expected field name"))
2161 for (
auto fieldName : fields) {
2162 std::optional<unsigned> indexV;
2163 auto type = result.getType();
2164 if (
auto refTy = type_dyn_cast<RefType>(type))
2165 type = refTy.getType();
2166 if (
auto bundle = type_dyn_cast<BundleType>(type))
2167 indexV = bundle.getElementIndex(fieldName);
2168 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2169 indexV = bundle.getElementIndex(fieldName);
2170 else if (
auto klass = type_dyn_cast<ClassType>(type))
2171 indexV = klass.getElementIndex(fieldName);
2173 return emitError(loc,
"subfield requires bundle or object operand ");
2175 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2176 << result.getType();
2177 auto indexNo = *indexV;
2180 if (type_isa<RefType>(result.getType())) {
2181 NamedAttribute attrs = {getConstants().indexIdentifier,
2182 builder.getI32IntegerAttr(indexNo)};
2183 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2184 }
else if (type_isa<ClassType>(type)) {
2185 NamedAttribute attrs = {getConstants().indexIdentifier,
2186 builder.getI32IntegerAttr(indexNo)};
2188 emitCachedSubAccess<ObjectSubfieldOp>(result, attrs, indexNo, loc);
2190 NamedAttribute attrs = {getConstants().fieldIndexIdentifier,
2191 builder.getI32IntegerAttr(indexNo)};
2192 if (type_isa<BundleType>(type))
2194 emitCachedSubAccess<SubfieldOp>(result, attrs, indexNo, loc);
2197 emitCachedSubAccess<OpenSubfieldOp>(result, attrs, indexNo, loc);
2200 if (failed(subResult))
2202 result = *subResult;
2211 ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2212 auto loc = getToken().getLoc();
2214 if (parseIntLit(indexNo,
"expected index") ||
2215 parseToken(FIRToken::r_square,
"expected ']'"))
2219 return emitError(loc,
"invalid index specifier"), failure();
2225 NamedAttribute attrs = {getConstants().indexIdentifier,
2226 builder.getI32IntegerAttr(indexNo)};
2229 if (type_isa<RefType>(result.getType()))
2230 subResult = emitCachedSubAccess<RefSubOp>(result, attrs, indexNo, loc);
2231 else if (type_isa<FVectorType>(result.getType()))
2232 subResult = emitCachedSubAccess<SubindexOp>(result, attrs, indexNo, loc);
2235 emitCachedSubAccess<OpenSubindexOp>(result, attrs, indexNo, loc);
2237 if (failed(subResult))
2239 result = *subResult;
2247 ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2248 auto loc = getToken().getLoc();
2250 if (parseExp(index,
"expected subscript index expression") ||
2251 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2255 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2257 return emitError(
"expected base type for index expression");
2258 indexType = indexType.getPassiveType();
2259 locationProcessor.setLoc(loc);
2263 auto resultType = SubaccessOp::inferReturnType({result, index}, {}, {});
2266 (void)SubaccessOp::inferReturnType({result, index}, {},
2267 translateLocation(loc));
2272 auto op =
builder.create<SubaccessOp>(resultType, result, index);
2273 result = op.getResult();
2278 ParseResult FIRStmtParser::parsePrimExp(Value &result) {
2279 auto kind = getToken().getKind();
2280 auto loc = getToken().getLoc();
2284 SmallVector<Value, 3> operands;
2285 SmallVector<int64_t, 3> integers;
2286 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2288 if (getToken().isAny(FIRToken::integer, FIRToken::signed_integer,
2289 FIRToken::string)) {
2290 integers.push_back(0);
2291 return parseIntLit(integers.back(),
"expected integer");
2296 if (!integers.empty())
2297 return emitError(
"expected more integer constants"), failure();
2300 if (parseExp(operand,
"expected expression in primitive operand"))
2303 locationProcessor.setLoc(loc);
2305 operands.push_back(operand);
2310 locationProcessor.setLoc(loc);
2312 SmallVector<FIRRTLType, 3> opTypes;
2313 for (
auto v : operands)
2314 opTypes.push_back(type_cast<FIRRTLType>(v.getType()));
2316 unsigned numOperandsExpected;
2317 SmallVector<StringAttr, 2> attrNames;
2322 emitError(loc,
"primitive not supported yet");
2324 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2325 case FIRToken::lp_##SPELLING: \
2326 numOperandsExpected = NUMOPERANDS; \
2328 #include "FIRTokenKinds.def"
2335 case FIRToken::lp_bits:
2336 attrNames.push_back(getConstants().hiIdentifier);
2337 attrNames.push_back(getConstants().loIdentifier);
2339 case FIRToken::lp_head:
2340 case FIRToken::lp_pad:
2341 case FIRToken::lp_shl:
2342 case FIRToken::lp_shr:
2343 case FIRToken::lp_tail:
2344 attrNames.push_back(getConstants().amountIdentifier);
2346 case FIRToken::lp_integer_add:
2347 case FIRToken::lp_integer_mul:
2348 case FIRToken::lp_integer_shr:
2349 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions", loc))
2354 if (operands.size() != numOperandsExpected) {
2355 assert(numOperandsExpected <= 3);
2356 static const char *numberName[] = {
"zero",
"one",
"two",
"three"};
2357 const char *optionalS = &
"s"[numOperandsExpected == 1];
2358 return emitError(loc,
"operation requires ")
2359 << numberName[numOperandsExpected] <<
" operand" << optionalS;
2362 if (integers.size() != attrNames.size()) {
2363 emitError(loc,
"expected ") << attrNames.size() <<
" constant arguments";
2367 NamedAttrList attrs;
2368 for (
size_t i = 0, e = attrNames.size(); i != e; ++i)
2369 attrs.append(attrNames[i],
builder.getI32IntegerAttr(integers[i]));
2373 emitError(loc,
"primitive not supported yet");
2376 #define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS) \
2377 case FIRToken::lp_##SPELLING: { \
2378 auto resultTy = CLASS::inferReturnType(operands, attrs, {}); \
2381 (void)CLASS::validateAndInferReturnType(operands, attrs, \
2382 translateLocation(loc)); \
2385 result = builder.create<CLASS>(resultTy, operands, attrs); \
2388 #include "FIRTokenKinds.def"
2395 case FIRToken::lp_shr:
2398 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2399 result =
builder.create<PadPrimOp>(result, 1);
2407 ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2408 bool isSigned = getToken().is(FIRToken::kw_SInt);
2409 auto loc = getToken().getLoc();
2415 if (parseOptionalWidth(
width) ||
2416 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2417 parseIntLit(value,
"expected integer value") ||
2418 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2425 IntegerType::SignednessSemantics signedness =
2426 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2428 if (!value.isZero())
2429 return emitError(loc,
"zero bit constant must be zero");
2430 value = value.trunc(0);
2431 }
else if (
width != -1) {
2433 bool valueFits = isSigned ? value.isSignedIntN(
width) : value.isIntN(
width);
2435 return emitError(loc,
"initializer too wide for declared width");
2436 value = isSigned ? value.sextOrTrunc(
width) : value.zextOrTrunc(
width);
2441 auto attr =
builder.getIntegerAttr(attrType, value);
2444 auto &entry = moduleContext.constantCache[{attr, type}];
2451 locationProcessor.setLoc(loc);
2452 result = moduleContext.getCachedConstantInt(
builder, attr, type, value);
2457 ParseResult FIRStmtParser::parseListExp(Value &result) {
2458 auto loc = getToken().getLoc();
2460 if (parseListType(type))
2462 auto listType = type_cast<ListType>(type);
2465 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2468 SmallVector<Value, 3> operands;
2469 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2471 locationProcessor.setLoc(loc);
2472 if (parseExp(operand,
"expected expression in List expression"))
2476 if (!isa<AnyRefType>(elementType) ||
2477 !isa<ClassType>(operand.getType()))
2478 return emitError(loc,
"unexpected expression of type ")
2479 << operand.getType() <<
" in List expression of type "
2481 operand = builder.create<ObjectAnyRefCastOp>(operand);
2484 operands.push_back(operand);
2489 locationProcessor.setLoc(loc);
2490 result =
builder.create<ListCreateOp>(listType, operands);
2511 std::optional<ParseResult>
2512 FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2513 switch (getToken().getKind()) {
2516 return std::nullopt;
2518 case FIRToken::period:
2519 case FIRToken::l_square:
2520 case FIRToken::kw_is:
2521 case FIRToken::less_equal:
2522 case FIRToken::less_minus:
2528 auto loc = keyword.
getLoc();
2530 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2531 return ParseResult(failure());
2537 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2540 if (!consumeIf(FIRToken::period))
2541 return ParseResult(failure());
2543 StringRef fieldName;
2544 if (parseFieldId(fieldName,
"expected field name") ||
2545 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2546 return ParseResult(failure());
2550 if (parseOptionalExpPostscript(lhs))
2551 return ParseResult(failure());
2553 return parseLeadingExpStmt(lhs);
2559 ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2562 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2565 auto subIndent = getIndentation();
2566 if (!subIndent.has_value())
2567 return emitError(
"expected statement to be on its own line"), failure();
2569 if (*subIndent <= indent)
2573 if (parseSimpleStmt(*subIndent))
2578 ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2579 locationProcessor.startStatement();
2580 auto result = parseSimpleStmtImpl(stmtIndent);
2581 locationProcessor.endStatement(*
this);
2602 ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2603 auto kind = getToken().getKind();
2606 case FIRToken::kw_invalidate:
2607 case FIRToken::kw_connect:
2608 case FIRToken::kw_regreset:
2612 kind = FIRToken::identifier;
2619 case FIRToken::kw_attach:
2620 return parseAttach();
2621 case FIRToken::kw_infer:
2622 return parseMemPort(MemDirAttr::Infer);
2623 case FIRToken::kw_read:
2624 return parseMemPort(MemDirAttr::Read);
2625 case FIRToken::kw_write:
2626 return parseMemPort(MemDirAttr::Write);
2627 case FIRToken::kw_rdwr:
2628 return parseMemPort(MemDirAttr::ReadWrite);
2629 case FIRToken::kw_connect:
2630 return parseConnect();
2631 case FIRToken::kw_propassign:
2632 if (requireFeature({3, 1, 0},
"properties"))
2634 return parsePropAssign();
2635 case FIRToken::kw_invalidate:
2636 return parseInvalidate();
2637 case FIRToken::lp_printf:
2638 return parsePrintf();
2639 case FIRToken::kw_skip:
2641 case FIRToken::lp_stop:
2643 case FIRToken::lp_assert:
2644 return parseAssert();
2645 case FIRToken::lp_assume:
2646 return parseAssume();
2647 case FIRToken::lp_cover:
2648 return parseCover();
2649 case FIRToken::kw_when:
2650 return parseWhen(stmtIndent);
2651 case FIRToken::kw_match:
2652 return parseMatch(stmtIndent);
2653 case FIRToken::kw_define:
2654 return parseRefDefine();
2655 case FIRToken::lp_force:
2656 return parseRefForce();
2657 case FIRToken::lp_force_initial:
2658 return parseRefForceInitial();
2659 case FIRToken::lp_release:
2660 return parseRefRelease();
2661 case FIRToken::lp_release_initial:
2662 return parseRefReleaseInitial();
2663 case FIRToken::kw_group:
2664 if (requireFeature({3, 2, 0},
"optional groups") ||
2665 removedFeature({4, 0, 0},
"optional groups"))
2667 return parseLayerBlockOrGroup(stmtIndent);
2668 case FIRToken::kw_layerblock:
2669 if (requireFeature({4, 0, 0},
"layers"))
2671 return parseLayerBlockOrGroup(stmtIndent);
2672 case FIRToken::lp_intrinsic:
2673 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2675 return parseIntrinsicStmt();
2679 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2686 return parseLeadingExpStmt(lhs);
2690 case FIRToken::kw_inst:
2691 return parseInstance();
2692 case FIRToken::kw_instchoice:
2693 return parseInstanceChoice();
2694 case FIRToken::kw_object:
2695 return parseObject();
2696 case FIRToken::kw_cmem:
2697 return parseCombMem();
2698 case FIRToken::kw_smem:
2699 return parseSeqMem();
2700 case FIRToken::kw_mem:
2701 return parseMem(stmtIndent);
2702 case FIRToken::kw_node:
2704 case FIRToken::kw_wire:
2706 case FIRToken::kw_reg:
2707 return parseRegister(stmtIndent);
2708 case FIRToken::kw_regreset:
2709 return parseRegisterWithReset();
2713 ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2715 SymbolRefAttr layerSym) {
2717 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2718 moduleContext, &blockToInsertInto);
2723 UnbundledValueRestorer x(moduleContext.unbundledValues);
2727 auto subParser = std::make_unique<FIRStmtParser>(
2728 blockToInsertInto, moduleContext, modNameSpace, circuitSymTbl, version,
2732 auto stmtIndent = getIndentation();
2735 if (!stmtIndent.has_value())
2736 return subParser->parseSimpleStmt(indent);
2738 if (*stmtIndent <= indent)
2739 return emitError(
"statement must be indented more than previous statement"),
2743 return subParser->parseSimpleStmtBlock(indent);
2747 ParseResult FIRStmtParser::parseAttach() {
2748 auto startTok = consumeToken(FIRToken::kw_attach);
2751 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2754 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
2757 SmallVector<Value, 4> operands;
2759 operands.push_back({});
2760 if (parseExp(operands.back(),
"expected operand in attach"))
2762 }
while (!consumeIf(FIRToken::r_paren));
2764 if (parseOptionalInfo())
2767 locationProcessor.setLoc(startTok.getLoc());
2768 builder.create<AttachOp>(operands);
2775 ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2776 auto startTok = consumeToken();
2777 auto startLoc = startTok.getLoc();
2781 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2787 Value memory, indexExp, clock;
2788 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
2789 parseId(
id,
"expected result name") ||
2790 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
2791 parseId(memName,
"expected memory name") ||
2792 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2793 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2794 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
2795 parseExp(indexExp,
"expected index expression") ||
2796 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
2797 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
2800 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2802 return emitError(startLoc,
2803 "memory port should have behavioral memory type");
2804 auto resultType = memVType.getElementType();
2806 ArrayAttr annotations = getConstants().emptyArrayAttr;
2807 locationProcessor.setLoc(startLoc);
2810 Value memoryPort, memoryData;
2812 OpBuilder::InsertionGuard guard(
builder);
2813 builder.setInsertionPointAfterValue(memory);
2814 auto memoryPortOp =
builder.create<MemoryPortOp>(
2817 memoryData = memoryPortOp.getResult(0);
2818 memoryPort = memoryPortOp.getResult(1);
2822 builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2824 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
2828 ParseResult FIRStmtParser::parsePrintf() {
2829 auto startTok = consumeToken(FIRToken::lp_printf);
2831 Value clock, condition;
2832 StringRef formatString;
2833 if (parseExp(clock,
"expected clock expression in printf") ||
2834 parseExp(condition,
"expected condition in printf") ||
2835 parseGetSpelling(formatString) ||
2836 parseToken(FIRToken::string,
"expected format string in printf"))
2839 SmallVector<Value, 4> operands;
2840 while (!consumeIf(FIRToken::r_paren)) {
2841 operands.push_back({});
2842 if (parseExp(operands.back(),
"expected operand in printf"))
2847 if (parseOptionalName(name))
2850 if (parseOptionalInfo())
2853 locationProcessor.setLoc(startTok.getLoc());
2856 builder.create<PrintFOp>(clock, condition,
2857 builder.getStringAttr(formatStrUnescaped), operands,
2863 ParseResult FIRStmtParser::parseSkip() {
2864 auto startTok = consumeToken(FIRToken::kw_skip);
2868 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2871 if (parseOptionalInfo())
2874 locationProcessor.setLoc(startTok.getLoc());
2880 ParseResult FIRStmtParser::parseStop() {
2881 auto startTok = consumeToken(FIRToken::lp_stop);
2883 Value clock, condition;
2886 if (parseExp(clock,
"expected clock expression in 'stop'") ||
2887 parseExp(condition,
"expected condition in 'stop'") ||
2888 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
2889 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
2890 parseOptionalName(name) || parseOptionalInfo())
2893 locationProcessor.setLoc(startTok.getLoc());
2894 builder.create<StopOp>(clock, condition,
builder.getI32IntegerAttr(exitCode),
2900 ParseResult FIRStmtParser::parseAssert() {
2901 auto startTok = consumeToken(FIRToken::lp_assert);
2903 Value clock, predicate, enable;
2904 StringRef formatString;
2906 if (parseExp(clock,
"expected clock expression in 'assert'") ||
2907 parseExp(predicate,
"expected predicate in 'assert'") ||
2908 parseExp(enable,
"expected enable in 'assert'") ||
2909 parseGetSpelling(formatString) ||
2910 parseToken(FIRToken::string,
"expected format string in 'assert'"))
2913 SmallVector<Value, 4> operands;
2914 while (!consumeIf(FIRToken::r_paren)) {
2915 operands.push_back({});
2916 if (parseExp(operands.back(),
"expected operand in 'assert'"))
2920 if (parseOptionalName(name) || parseOptionalInfo())
2923 locationProcessor.setLoc(startTok.getLoc());
2925 builder.create<AssertOp>(clock, predicate, enable, formatStrUnescaped,
2926 operands, name.getValue());
2931 ParseResult FIRStmtParser::parseAssume() {
2932 auto startTok = consumeToken(FIRToken::lp_assume);
2934 Value clock, predicate, enable;
2935 StringRef formatString;
2937 if (parseExp(clock,
"expected clock expression in 'assume'") ||
2938 parseExp(predicate,
"expected predicate in 'assume'") ||
2939 parseExp(enable,
"expected enable in 'assume'") ||
2940 parseGetSpelling(formatString) ||
2941 parseToken(FIRToken::string,
"expected format string in 'assume'"))
2944 SmallVector<Value, 4> operands;
2945 while (!consumeIf(FIRToken::r_paren)) {
2946 operands.push_back({});
2947 if (parseExp(operands.back(),
"expected operand in 'assume'"))
2951 if (parseOptionalName(name) || parseOptionalInfo())
2954 locationProcessor.setLoc(startTok.getLoc());
2956 builder.create<AssumeOp>(clock, predicate, enable, formatStrUnescaped,
2957 operands, name.getValue());
2962 ParseResult FIRStmtParser::parseCover() {
2963 auto startTok = consumeToken(FIRToken::lp_cover);
2965 Value clock, predicate, enable;
2968 if (parseExp(clock,
"expected clock expression in 'cover'") ||
2969 parseExp(predicate,
"expected predicate in 'cover'") ||
2970 parseExp(enable,
"expected enable in 'cover'") ||
2971 parseGetSpelling(message) ||
2972 parseToken(FIRToken::string,
"expected message in 'cover'") ||
2973 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
2974 parseOptionalName(name) || parseOptionalInfo())
2977 locationProcessor.setLoc(startTok.getLoc());
2979 builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
2980 ValueRange{}, name.getValue());
2986 ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
2987 auto startTok = consumeToken(FIRToken::kw_when);
2991 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2995 if (parseExp(condition,
"expected condition in 'when'") ||
2996 parseToken(FIRToken::colon,
"expected ':' in when") ||
2997 parseOptionalInfo())
3000 locationProcessor.setLoc(startTok.getLoc());
3002 auto whenStmt =
builder.create<WhenOp>(condition,
false);
3005 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3009 if (getToken().isNot(FIRToken::kw_else))
3014 auto elseIndent = getIndentation();
3015 if (elseIndent && *elseIndent < whenIndent)
3018 consumeToken(FIRToken::kw_else);
3021 whenStmt.createElseRegion();
3027 if (getToken().is(FIRToken::kw_when)) {
3029 auto subParser = std::make_unique<FIRStmtParser>(
3030 whenStmt.getElseBlock(), moduleContext, modNameSpace, circuitSymTbl,
3033 return subParser->parseSimpleStmt(whenIndent);
3037 LocationAttr elseLoc;
3038 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3039 parseOptionalInfoLocator(elseLoc) ||
3040 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3049 ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3050 auto startLoc = getToken().getLoc();
3051 locationProcessor.setLoc(startLoc);
3053 if (parseEnumType(type))
3057 auto enumType = type_dyn_cast<FEnumType>(type);
3059 return emitError(startLoc,
3060 "expected enumeration type in enumeration expression");
3063 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3064 parseId(tag,
"expected enumeration tag"))
3068 if (consumeIf(FIRToken::r_paren)) {
3073 auto attr =
builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3074 input =
builder.create<ConstantOp>(type, attr);
3077 if (parseExp(input,
"expected expression in enumeration value") ||
3078 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3082 value =
builder.create<FEnumCreateOp>(enumType, tag, input);
3090 ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3091 auto startTok = consumeToken(FIRToken::kw_match);
3093 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3097 if (parseExp(input,
"expected expression in 'match'") ||
3098 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3099 parseOptionalInfo())
3102 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3104 return mlir::emitError(
3106 "expected enumeration type for 'match' statement, but got ")
3109 locationProcessor.setLoc(startTok.getLoc());
3111 SmallVector<Attribute> tags;
3112 SmallVector<std::unique_ptr<Region>> regions;
3114 auto tagLoc = getToken().getLoc();
3117 auto caseIndent = getIndentation();
3118 if (!caseIndent || *caseIndent <= matchIndent)
3122 StringRef tagSpelling;
3123 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3125 auto tagIndex = enumType.getElementIndex(tagSpelling);
3127 return emitError(tagLoc,
"tag ")
3128 << tagSpelling <<
" not a member of enumeration " << enumType;
3130 tags.push_back(tag);
3133 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3136 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3141 UnbundledValueRestorer x(moduleContext.unbundledValues);
3144 if (consumeIf(FIRToken::l_paren)) {
3145 StringAttr identifier;
3146 if (parseId(identifier,
"expected identifier for 'case' binding"))
3150 auto dataType = enumType.getElementType(*tagIndex);
3151 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3153 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3157 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3162 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3165 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3170 std::make_unique<FIRStmtParser>(*caseBlock, moduleContext, modNameSpace,
3171 circuitSymTbl, version, layerSym);
3172 if (subParser->parseSimpleStmtBlock(*caseIndent))
3182 ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3183 auto token = getToken().getKind();
3184 if (token == FIRToken::lp_probe)
3185 return parseProbe(result);
3186 if (token == FIRToken::lp_rwprobe)
3187 return parseRWProbe(result);
3192 return parseStaticRefExp(result, message);
3199 ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3200 const Twine &message) {
3201 auto parseIdOrInstance = [&]() -> ParseResult {
3203 auto loc = getToken().getLoc();
3205 if (parseId(
id, message) ||
3206 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3210 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3216 StringRef fieldName;
3218 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3219 parseFieldId(fieldName,
"expected field name") ||
3220 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3222 return failure(parseIdOrInstance() ||
3223 parseOptionalExpPostscript(result,
false));
3234 ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3236 const Twine &message) {
3237 auto loc = getToken().getLoc();
3241 if (parseId(
id, message) ||
3242 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3252 if (
auto unbundledId = symtabEntry.dyn_cast<
UnbundledID>()) {
3254 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3256 StringRef fieldName;
3257 auto loc = getToken().getLoc();
3258 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3259 parseFieldId(fieldName,
"expected field name"))
3265 for (
auto &elt : ubEntry) {
3266 if (elt.first == fieldAttr) {
3269 auto &instResult = elt.second;
3272 auto *defining = instResult.getDefiningOp();
3274 if (isa<Forceable>(defining)) {
3275 assert(cast<Forceable>(defining).isForceable());
3276 result = instResult;
3281 auto type = instResult.getType();
3285 bool forceable =
static_cast<bool>(
3288 return emitError(loc,
"unable to force instance result of type ")
3292 auto annotations = getConstants().emptyArrayAttr;
3293 StringAttr sym = {};
3294 SmallString<64> name;
3295 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3296 locationProcessor.setLoc(loc);
3297 OpBuilder::InsertionGuard guard(
builder);
3298 builder.setInsertionPoint(defining);
3300 builder.create<WireOp>(type, name, NameKindEnum::InterestingName,
3301 annotations, sym,
true);
3302 auto bounceVal = bounce.getData();
3305 instResult.replaceAllUsesWith(bounceVal);
3308 builder.setInsertionPointAfter(defining);
3316 result = instResult = bounce.getDataRaw();
3322 emitError(loc,
"use of invalid field name '")
3323 << fieldName <<
"' on bundle value";
3328 result = symtabEntry.get<Value>();
3332 assert(isa<BlockArgument>(result) || result.getDefiningOp<Forceable>());
3338 type = result.getType();
3340 if (consumeIf(FIRToken::period)) {
3341 SmallVector<StringRef, 3> fields;
3342 if (parseFieldIdSeq(fields,
"expected field name"))
3344 for (
auto fieldName : fields) {
3345 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3346 if (
auto index = bundle.getElementIndex(fieldName)) {
3347 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3348 type = bundle.getElementTypePreservingConst(*index);
3351 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3352 if (
auto index = bundle.getElementIndex(fieldName)) {
3353 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3354 type = bundle.getElementTypePreservingConst(*index);
3358 return emitError(loc,
"subfield requires bundle operand")
3359 <<
"got " << type <<
"\n";
3361 return emitError(loc,
3362 "unknown field '" + fieldName +
"' in bundle type ")
3367 if (consumeIf(FIRToken::l_square)) {
3368 auto loc = getToken().
getLoc();
3370 if (parseIntLit(index,
"expected index") ||
3371 parseToken(FIRToken::r_square,
"expected ']'"))
3375 return emitError(loc,
"invalid index specifier");
3377 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3378 if ((
unsigned)index < vector.getNumElements()) {
3379 refResult = refResult.
getSubField(vector.getFieldID(index));
3380 type = vector.getElementTypePreservingConst();
3383 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3384 if ((
unsigned)index < vector.getNumElements()) {
3385 refResult = refResult.
getSubField(vector.getFieldID(index));
3386 type = vector.getElementTypePreservingConst();
3390 return emitError(loc,
"subindex requires vector operand");
3392 return emitError(loc,
"out of range index '")
3393 << index <<
"' for vector type " << type;
3401 ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3402 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3403 StringRef intrinsic;
3404 ArrayAttr parameters;
3407 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3408 parseOptionalParams(parameters))
3411 if (consumeIf(FIRToken::colon)) {
3412 if (
parseType(type,
"expected intrinsic return type"))
3414 }
else if (!isStatement)
3415 return emitError(
"expected ':' in intrinsic expression");
3417 SmallVector<Value> operands;
3418 auto loc = startTok.getLoc();
3419 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3421 if (parseExp(operand,
"expected operand in intrinsic"))
3423 operands.push_back(operand);
3424 locationProcessor.setLoc(loc);
3430 if (parseOptionalInfo())
3433 locationProcessor.setLoc(loc);
3435 auto op =
builder.create<GenericIntrinsicOp>(
3436 type,
builder.getStringAttr(intrinsic), operands, parameters);
3438 result = op.getResult();
3443 ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3444 if (!consumeIf(FIRToken::less))
3447 SmallVector<Attribute, 8> parameters;
3448 SmallPtrSet<StringAttr, 8> seen;
3449 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3453 if (parseParameter(name, value, loc))
3455 if (!seen.insert(name).second)
3456 return emitError(loc,
"redefinition of parameter '" +
3457 name.getValue() +
"'");
3469 ParseResult FIRStmtParser::parsePathExp(Value &result) {
3470 auto startTok = consumeToken(FIRToken::lp_path);
3471 locationProcessor.setLoc(startTok.getLoc());
3473 if (parseGetSpelling(target) ||
3474 parseToken(FIRToken::string,
3475 "expected target string in path expression") ||
3476 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3478 result =
builder.create<UnresolvedPathOp>(
3484 ParseResult FIRStmtParser::parseRefDefine() {
3485 auto startTok = consumeToken(FIRToken::kw_define);
3488 if (parseStaticRefExp(target,
3489 "expected static reference expression in 'define'") ||
3490 parseToken(FIRToken::equal,
3491 "expected '=' after define reference expression") ||
3492 parseRefExp(src,
"expected reference expression in 'define'") ||
3493 parseOptionalInfo())
3497 if (!type_isa<RefType>(target.getType()))
3498 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3499 "'define' target (LHS), got ")
3500 << target.getType();
3501 if (!type_isa<RefType>(src.getType()))
3502 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3503 "'define' source (RHS), got ")
3508 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3509 return emitError(startTok.getLoc(),
3510 "cannot define into a sub-element of a reference");
3512 locationProcessor.setLoc(startTok.getLoc());
3515 return emitError(startTok.getLoc(),
"cannot define reference of type ")
3516 << target.getType() <<
" with incompatible reference of type "
3526 ParseResult FIRStmtParser::parseRefRead(Value &result) {
3527 auto startTok = consumeToken(FIRToken::lp_read);
3530 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
3531 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
3534 locationProcessor.setLoc(startTok.getLoc());
3537 if (!type_isa<RefType>(ref.getType()))
3538 return emitError(startTok.getLoc(),
3539 "expected reference-type expression in 'read', got ")
3542 result =
builder.create<RefResolveOp>(ref);
3548 ParseResult FIRStmtParser::parseProbe(Value &result) {
3549 auto startTok = consumeToken(FIRToken::lp_probe);
3552 if (parseStaticRefExp(staticRef,
3553 "expected static reference expression in 'probe'") ||
3554 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
3557 locationProcessor.setLoc(startTok.getLoc());
3560 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3561 return emitError(startTok.getLoc(),
3562 "expected base-type expression in 'probe', got ")
3563 << staticRef.getType();
3567 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3568 MemoryDebugPortOp, MemoryPortAccessOp>(
3569 staticRef.getDefiningOp()))
3570 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3572 result =
builder.create<RefSendOp>(staticRef);
3578 ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3579 auto startTok = consumeToken(FIRToken::lp_rwprobe);
3582 Type parsedTargetType;
3583 if (parseRWProbeStaticRefExp(
3584 staticRef, parsedTargetType,
3585 "expected static reference expression in 'rwprobe'") ||
3586 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
3589 locationProcessor.setLoc(startTok.getLoc());
3595 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
3597 return emitError(startTok.getLoc(),
3598 "expected base-type expression in 'rwprobe', got ")
3599 << parsedTargetType;
3602 auto *definingOp = root.getDefiningOp();
3604 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3605 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
3606 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3610 return emitError(startTok.getLoc(),
"cannot force target of type ")
3614 if (targetType.hasUninferredReset()) {
3616 return emitError(startTok.getLoc(),
3617 "must have concrete reset type in type ")
3620 auto forceable = dyn_cast<Forceable>(definingOp);
3621 if (!forceable || !forceable.isForceable() )
3622 return emitError(startTok.getLoc(),
"rwprobe target not forceable")
3623 .attachNote(definingOp->getLoc());
3627 assert(result.getType() == forceableType);
3634 [&](
auto _) -> hw::InnerSymbolNamespace & {
return modNameSpace; });
3635 result =
builder.create<RWProbeOp>(forceableType, sym);
3640 ParseResult FIRStmtParser::parseRefForce() {
3641 auto startTok = consumeToken(FIRToken::lp_force);
3643 Value clock, pred, dest, src;
3644 if (parseExp(clock,
"expected clock expression in force") ||
3645 parseExp(pred,
"expected predicate expression in force") ||
3646 parseRefExp(dest,
"expected destination reference expression in force") ||
3647 parseExp(src,
"expected source expression in force") ||
3648 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
3649 parseOptionalInfo())
3653 auto ref = type_dyn_cast<RefType>(dest.getType());
3654 if (!ref || !ref.getForceable())
3657 "expected rwprobe-type expression for force destination, got ")
3659 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3661 return emitError(startTok.getLoc(),
3662 "expected base-type for force source, got ")
3665 locationProcessor.setLoc(startTok.getLoc());
3668 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3669 if (noConstSrcType != ref.getType()) {
3671 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3673 dest =
builder.create<RefCastOp>(compatibleRWProbe, dest);
3676 builder.create<RefForceOp>(clock, pred, dest, src);
3682 ParseResult FIRStmtParser::parseRefForceInitial() {
3683 auto startTok = consumeToken(FIRToken::lp_force_initial);
3687 dest,
"expected destination reference expression in force_initial") ||
3688 parseExp(src,
"expected source expression in force_initial") ||
3689 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
3690 parseOptionalInfo())
3694 auto ref = type_dyn_cast<RefType>(dest.getType());
3695 if (!ref || !ref.getForceable())
3696 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3697 "force_initial destination, got ")
3699 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3701 return emitError(startTok.getLoc(),
3702 "expected base-type expression for force_initial "
3706 locationProcessor.setLoc(startTok.getLoc());
3709 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3710 if (noConstSrcType != ref.getType()) {
3712 auto compatibleRWProbe =
RefType::get(noConstSrcType,
true);
3714 dest =
builder.create<RefCastOp>(compatibleRWProbe, dest);
3717 auto value = APInt::getAllOnes(1);
3720 value.getBitWidth(),
3721 IntegerType::Unsigned),
3723 auto pred = moduleContext.getCachedConstantInt(
builder, attr, type, value);
3724 builder.create<RefForceInitialOp>(pred, dest, src);
3730 ParseResult FIRStmtParser::parseRefRelease() {
3731 auto startTok = consumeToken(FIRToken::lp_release);
3733 Value clock, pred, dest;
3734 if (parseExp(clock,
"expected clock expression in release") ||
3735 parseExp(pred,
"expected predicate expression in release") ||
3737 "expected destination reference expression in release") ||
3738 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
3739 parseOptionalInfo())
3743 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3744 !ref || !ref.getForceable())
3747 "expected rwprobe-type expression for release destination, got ")
3750 locationProcessor.setLoc(startTok.getLoc());
3752 builder.create<RefReleaseOp>(clock, pred, dest);
3758 ParseResult FIRStmtParser::parseRefReleaseInitial() {
3759 auto startTok = consumeToken(FIRToken::lp_release_initial);
3764 "expected destination reference expression in release_initial") ||
3765 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
3766 parseOptionalInfo())
3770 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3771 !ref || !ref.getForceable())
3772 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3773 "release_initial destination, got ")
3776 locationProcessor.setLoc(startTok.getLoc());
3778 auto value = APInt::getAllOnes(1);
3781 value.getBitWidth(),
3782 IntegerType::Unsigned),
3784 auto pred = moduleContext.getCachedConstantInt(
builder, attr, type, value);
3785 builder.create<RefReleaseInitialOp>(pred, dest);
3791 ParseResult FIRStmtParser::parseConnect() {
3792 auto startTok = consumeToken(FIRToken::kw_connect);
3793 auto loc = startTok.getLoc();
3796 if (parseExp(lhs,
"expected connect expression") ||
3797 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
3800 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3801 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3802 if (!lhsType || !rhsType)
3803 return emitError(loc,
"cannot connect reference or property types");
3805 if (lhsType.containsReference() || rhsType.containsReference())
3806 return emitError(loc,
"cannot connect types containing references");
3809 return emitError(loc,
"cannot connect non-equivalent type ")
3810 << rhsType <<
" to " << lhsType;
3812 locationProcessor.setLoc(loc);
3818 ParseResult FIRStmtParser::parsePropAssign() {
3819 auto startTok = consumeToken(FIRToken::kw_propassign);
3820 auto loc = startTok.getLoc();
3823 if (parseExp(lhs,
"expected propassign expression") ||
3824 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
3827 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
3828 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
3829 if (!lhsType || !rhsType)
3830 return emitError(loc,
"can only propassign property types");
3831 locationProcessor.setLoc(loc);
3832 if (lhsType != rhsType) {
3834 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
3835 rhs =
builder.create<ObjectAnyRefCastOp>(rhs);
3837 return emitError(loc,
"cannot propassign non-equivalent type ")
3838 << rhsType <<
" to " << lhsType;
3840 builder.create<PropAssignOp>(lhs, rhs);
3845 ParseResult FIRStmtParser::parseInvalidate() {
3846 auto startTok = consumeToken(FIRToken::kw_invalidate);
3849 if (parseExp(lhs,
"expected connect expression") || parseOptionalInfo())
3852 locationProcessor.setLoc(startTok.getLoc());
3853 emitInvalidate(lhs);
3857 ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
3859 auto startTok = consumeToken();
3860 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
3861 "consumed an unexpected token");
3862 auto loc = startTok.getLoc();
3865 if (parseId(
id,
"expected layer identifer") ||
3866 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
3867 parseOptionalInfo())
3870 locationProcessor.setLoc(loc);
3872 StringRef rootLayer;
3873 SmallVector<FlatSymbolRefAttr> nestedLayers;
3877 rootLayer = layerSym.getRootReference();
3878 auto nestedRefs = layerSym.getNestedReferences();
3879 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
3883 auto layerBlockOp =
builder.create<LayerBlockOp>(
3885 layerBlockOp->getRegion(0).push_back(
new Block());
3887 if (getIndentation() > indent)
3888 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
3889 layerBlockOp.getLayerName()))
3898 ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
3899 auto loc = getToken().getLoc();
3902 if (consumeIf(FIRToken::kw_is)) {
3903 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
3904 parseOptionalInfo())
3907 locationProcessor.setLoc(loc);
3908 emitInvalidate(lhs);
3912 auto kind = getToken().getKind();
3914 case FIRToken::less_equal:
3916 case FIRToken::less_minus:
3917 if (removedFeature({2, 0, 0},
"partial connects"))
3921 return emitError() <<
"unexpected token '" << getToken().getSpelling()
3922 <<
"' in statement",
3928 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
3931 locationProcessor.setLoc(loc);
3933 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3934 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3935 if (!lhsType || !rhsType)
3936 return emitError(loc,
"cannot connect reference or property types");
3938 if (lhsType.containsReference() || rhsType.containsReference())
3939 return emitError(loc,
"cannot connect types containing references");
3941 if (kind == FIRToken::less_equal) {
3943 return emitError(loc,
"cannot connect non-equivalent type ")
3944 << rhsType <<
" to " << lhsType;
3947 assert(kind == FIRToken::less_minus &&
"unexpected kind");
3949 return emitError(loc,
3950 "cannot partially connect non-weakly-equivalent type ")
3951 << rhsType <<
" to " << lhsType;
3952 emitPartialConnect(
builder, lhs, rhs);
3961 ParseResult FIRStmtParser::parseInstance() {
3962 auto startTok = consumeToken(FIRToken::kw_inst);
3966 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3970 StringRef moduleName;
3971 if (parseId(
id,
"expected instance name") ||
3972 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
3973 parseId(moduleName,
"expected module name") || parseOptionalInfo())
3976 locationProcessor.setLoc(startTok.getLoc());
3979 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
3980 if (!referencedModule)
3983 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
3985 auto annotations = getConstants().emptyArrayAttr;
3986 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
3988 hw::InnerSymAttr sym = {};
3989 auto result =
builder.create<InstanceOp>(
3990 referencedModule, id, NameKindEnum::InterestingName,
3991 annotations.getValue(), portAnnotations,
false, sym);
3997 unbundledValueEntry.reserve(modulePorts.size());
3998 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
3999 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4003 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4004 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4005 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4010 ParseResult FIRStmtParser::parseInstanceChoice() {
4011 auto startTok = consumeToken(FIRToken::kw_instchoice);
4012 SMLoc loc = startTok.getLoc();
4015 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4018 if (requireFeature({4, 0, 0},
"option groups/instance choices"))
4022 StringRef defaultModuleName;
4023 StringRef optionGroupName;
4024 if (parseId(
id,
"expected instance name") ||
4025 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4026 parseId(defaultModuleName,
"expected module name") ||
4027 parseId(optionGroupName,
"expected option group name") ||
4028 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4029 parseOptionalInfo())
4032 locationProcessor.setLoc(startTok.getLoc());
4036 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4040 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4043 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4045 return emitError(loc,
4046 "use of undefined option group '" + optionGroupName +
"'");
4048 auto baseIndent = getIndentation();
4049 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4050 while (getIndentation() == baseIndent) {
4052 StringRef caseModuleName;
4053 if (parseId(caseId,
"expected a case identifier") ||
4054 parseToken(FIRToken::equal_greater,
4055 "expected '=> in instance choice definition") ||
4056 parseId(caseModuleName,
"expected module name"))
4059 auto caseModule = getReferencedModule(loc, caseModuleName);
4063 for (
const auto &[defaultPort, casePort] :
4064 llvm::zip(modulePorts, caseModule.getPorts())) {
4065 if (defaultPort.name != casePort.name)
4066 return emitError(loc,
"instance case module port '")
4067 << casePort.name.getValue()
4068 <<
"' does not match the default module port '"
4069 << defaultPort.name.getValue() <<
"'";
4070 if (defaultPort.type != casePort.type)
4071 return emitError(loc,
"instance case port '")
4072 << casePort.name.getValue()
4073 <<
"' type does not match the default module port";
4077 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4079 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4080 caseModules.emplace_back(optionCase, caseModule);
4083 auto annotations = getConstants().emptyArrayAttr;
4084 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4088 auto result =
builder.create<InstanceChoiceOp>(
4089 defaultModule, caseModules, id, NameKindEnum::InterestingName,
4090 annotations.getValue(), portAnnotations, sym);
4094 unbundledValueEntry.reserve(modulePorts.size());
4095 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4096 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4098 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4099 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4100 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4103 FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4104 StringRef moduleName) {
4105 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4106 if (!referencedModule) {
4108 "use of undefined module name '" + moduleName +
"' in instance");
4111 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4112 emitError(loc,
"cannot create instance of class '" + moduleName +
4113 "', did you mean object?");
4116 return referencedModule;
4120 ParseResult FIRStmtParser::parseObject() {
4121 auto startTok = consumeToken(FIRToken::kw_object);
4125 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4132 StringRef className;
4133 if (parseId(
id,
"expected object name") ||
4134 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4135 parseId(className,
"expected class name") || parseOptionalInfo())
4138 locationProcessor.setLoc(startTok.getLoc());
4141 const auto &classMap = getConstants().classMap;
4142 auto lookup = classMap.find(className);
4143 if (lookup == classMap.end())
4144 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4145 className +
"' in object");
4146 auto referencedClass = lookup->getSecond();
4147 auto result =
builder.create<ObjectOp>(referencedClass, id);
4148 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4152 ParseResult FIRStmtParser::parseCombMem() {
4154 auto startTok = consumeToken(FIRToken::kw_cmem);
4158 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4163 if (parseId(
id,
"expected cmem name") ||
4164 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4165 parseType(type,
"expected cmem type") || parseOptionalInfo())
4168 locationProcessor.setLoc(startTok.getLoc());
4171 auto vectorType = type_dyn_cast<FVectorType>(type);
4173 return emitError(
"cmem requires vector type");
4175 auto annotations = getConstants().emptyArrayAttr;
4176 StringAttr sym = {};
4177 auto result =
builder.create<CombMemOp>(
4178 vectorType.getElementType(), vectorType.getNumElements(), id,
4179 NameKindEnum::InterestingName, annotations, sym);
4180 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4184 ParseResult FIRStmtParser::parseSeqMem() {
4186 auto startTok = consumeToken(FIRToken::kw_smem);
4190 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4195 RUWAttr ruw = RUWAttr::Undefined;
4197 if (parseId(
id,
"expected smem name") ||
4198 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4199 parseType(type,
"expected smem type") || parseOptionalRUW(ruw) ||
4200 parseOptionalInfo())
4203 locationProcessor.setLoc(startTok.getLoc());
4206 auto vectorType = type_dyn_cast<FVectorType>(type);
4208 return emitError(
"smem requires vector type");
4210 auto annotations = getConstants().emptyArrayAttr;
4211 StringAttr sym = {};
4212 auto result =
builder.create<SeqMemOp>(
4213 vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
4214 NameKindEnum::InterestingName, annotations, sym);
4215 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4227 ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4228 auto startTok = consumeToken(FIRToken::kw_mem);
4232 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4236 if (parseId(
id,
"expected mem name") ||
4237 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4241 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4242 RUWAttr ruw = RUWAttr::Undefined;
4244 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4248 auto nextIndent = getIndentation();
4249 if (!nextIndent || *nextIndent <= memIndent)
4252 auto spelling = getTokenSpelling();
4253 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4254 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4257 if (spelling ==
"data-type") {
4259 return emitError(
"'mem' type specified multiple times"), failure();
4261 if (
parseType(type,
"expected type in data-type declaration"))
4265 if (spelling ==
"depth") {
4266 if (parseIntLit(depth,
"expected integer in depth specification"))
4270 if (spelling ==
"read-latency") {
4271 if (parseIntLit(readLatency,
"expected integer latency"))
4275 if (spelling ==
"write-latency") {
4276 if (parseIntLit(writeLatency,
"expected integer latency"))
4280 if (spelling ==
"read-under-write") {
4281 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4282 FIRToken::kw_undefined))
4283 return emitError(
"expected specifier"), failure();
4285 if (parseOptionalRUW(ruw))
4290 MemOp::PortKind portKind;
4291 if (spelling ==
"reader")
4292 portKind = MemOp::PortKind::Read;
4293 else if (spelling ==
"writer")
4294 portKind = MemOp::PortKind::Write;
4295 else if (spelling ==
"readwriter")
4296 portKind = MemOp::PortKind::ReadWrite;
4298 return emitError(
"unexpected field in 'mem' declaration"), failure();
4301 if (parseId(portName,
"expected port name"))
4303 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4305 return emitError(
"unexpected type, must be base type");
4306 ports.push_back({
builder.getStringAttr(portName),
4307 MemOp::getTypeForPort(depth, baseType, portKind)});
4309 while (!getIndentation().has_value()) {
4310 if (parseId(portName,
"expected port name"))
4312 ports.push_back({
builder.getStringAttr(portName),
4313 MemOp::getTypeForPort(depth, baseType, portKind)});
4324 llvm::array_pod_sort(ports.begin(), ports.end(),
4325 [](
const std::pair<StringAttr, Type> *lhs,
4326 const std::pair<StringAttr, Type> *rhs) ->
int {
4327 return lhs->first.getValue().compare(
4328 rhs->first.getValue());
4331 auto annotations = getConstants().emptyArrayAttr;
4332 SmallVector<Attribute, 4> resultNames;
4333 SmallVector<Type, 4> resultTypes;
4334 SmallVector<Attribute, 4> resultAnnotations;
4335 for (
auto p : ports) {
4336 resultNames.push_back(p.first);
4337 resultTypes.push_back(p.second);
4338 resultAnnotations.push_back(annotations);
4341 locationProcessor.setLoc(startTok.getLoc());
4343 auto result =
builder.create<MemOp>(
4344 resultTypes, readLatency, writeLatency, depth, ruw,
4345 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
4346 annotations,
builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4347 MemoryInitAttr(), StringAttr());
4350 unbundledValueEntry.reserve(result.getNumResults());
4351 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4352 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4354 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4355 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4356 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4360 ParseResult FIRStmtParser::parseNode() {
4361 auto startTok = consumeToken(FIRToken::kw_node);
4365 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4370 if (parseId(
id,
"expected node name") ||
4371 parseToken(FIRToken::equal,
"expected '=' in node") ||
4372 parseExp(initializer,
"expected expression for node") ||
4373 parseOptionalInfo())
4376 locationProcessor.setLoc(startTok.getLoc());
4388 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4389 auto initializerBaseType =
4390 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4391 if (type_isa<AnalogType>(initializerType) ||
4392 !(initializerBaseType && initializerBaseType.isPassive())) {
4393 emitError(startTok.getLoc())
4394 <<
"Node cannot be analog and must be passive or passive under a flip "
4395 << initializer.getType();
4399 auto annotations = getConstants().emptyArrayAttr;
4400 StringAttr sym = {};
4405 builder.create<NodeOp>(initializer, id, NameKindEnum::InterestingName,
4406 annotations, sym, forceable);
4407 return moduleContext.addSymbolEntry(
id, result.getResult(),
4412 ParseResult FIRStmtParser::parseWire() {
4413 auto startTok = consumeToken(FIRToken::kw_wire);
4417 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4422 if (parseId(
id,
"expected wire name") ||
4423 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4424 parseType(type,
"expected wire type") || parseOptionalInfo())
4427 locationProcessor.setLoc(startTok.getLoc());
4429 auto annotations = getConstants().emptyArrayAttr;
4430 StringAttr sym = {};
4434 auto namekind = isa<PropertyType, RefType>(type)
4435 ? NameKindEnum::DroppableName
4436 : NameKindEnum::InterestingName;
4439 builder.create<WireOp>(type, id, namekind, annotations, sym, forceable);
4440 return moduleContext.addSymbolEntry(
id, result.getResult(),
4454 ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4455 auto startTok = consumeToken(FIRToken::kw_reg);
4459 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4468 if (parseId(
id,
"expected reg name") ||
4469 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4471 parseExp(clock,
"expected expression for register clock"))
4474 if (!type_isa<FIRRTLBaseType>(type))
4475 return emitError(startTok.getLoc(),
"register must have base type");
4478 Value resetSignal, resetValue;
4479 if (consumeIf(FIRToken::kw_with)) {
4480 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
4488 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4490 auto indent = getIndentation();
4491 if (!indent || *indent <= regIndent)
4492 if (!hasExtraLParen)
4493 return emitError(
"expected indented reset specifier in reg"), failure();
4495 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
4496 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
4497 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
4498 parseExp(resetSignal,
"expected expression for reset signal"))
4506 if (getTokenSpelling() ==
id) {
4508 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4510 resetSignal = Value();
4512 if (parseExp(resetValue,
"expected expression for reset value") ||
4513 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4517 if (hasExtraLParen &&
4518 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4524 if (parseOptionalInfo())
4527 locationProcessor.setLoc(startTok.getLoc());
4529 ArrayAttr annotations = getConstants().emptyArrayAttr;
4531 StringAttr sym = {};
4535 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4536 NameKindEnum::InterestingName, annotations,
4541 .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4542 annotations, sym, forceable)
4544 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4552 ParseResult FIRStmtParser::parseRegisterWithReset() {
4553 auto startTok = consumeToken(FIRToken::kw_regreset);
4557 Value clock, resetSignal, resetValue;
4559 if (parseId(
id,
"expected reg name") ||
4560 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4562 parseExp(clock,
"expected expression for register clock") ||
4563 parseExp(resetSignal,
"expected expression for register reset") ||
4564 parseExp(resetValue,
"expected expression for register reset value") ||
4565 parseOptionalInfo())
4568 if (!type_isa<FIRRTLBaseType>(type))
4569 return emitError(startTok.getLoc(),
"register must have base type");
4571 locationProcessor.setLoc(startTok.getLoc());
4575 .create<RegResetOp>(type, clock, resetSignal, resetValue,
4576 id, NameKindEnum::InterestingName,
4577 getConstants().emptyArrayAttr,
4578 StringAttr{}, forceable)
4581 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4591 struct FIRCircuitParser :
public FIRParser {
4592 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
4594 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
4597 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
4598 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBuf,
4599 mlir::TimingScope &ts);
4604 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4605 SmallVectorImpl<Attribute> &attrs);
4609 ParseResult importOMIR(CircuitOp circuit, SMLoc loc, StringRef annotationStr,
4610 SmallVectorImpl<Attribute> &attrs);
4612 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
4614 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
4615 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
4616 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
4617 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
4618 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
4620 ParseResult parseLayerName(SymbolRefAttr &result);
4621 ParseResult parseOptionalEnabledLayers(ArrayAttr &result);
4622 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4623 SmallVectorImpl<SMLoc> &resultPortLocs,
4626 ParseResult parseRefList(ArrayRef<PortInfo> portList,
4627 ArrayAttr &internalPathsResult);
4629 ParseResult skipToModuleEnd(
unsigned indent);
4631 ParseResult parseTypeDecl();
4633 ParseResult parseOptionDecl(CircuitOp circuit);
4635 ParseResult parseLayer(CircuitOp circuit);
4637 struct DeferredModuleToParse {
4638 FModuleLike moduleOp;
4639 SmallVector<SMLoc> portLocs;
4644 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
4645 DeferredModuleToParse &deferredModule);
4647 SmallVector<DeferredModuleToParse, 0> deferredModules;
4648 ModuleOp mlirModule;
4653 FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4654 SmallVectorImpl<Attribute> &attrs) {
4656 auto annotations = json::parse(annotationsStr);
4657 if (
auto err = annotations.takeError()) {
4658 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4659 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
4660 diag.attachNote() << a.message();
4665 json::Path::Root root;
4666 llvm::StringMap<ArrayAttr> thisAnnotationMap;
4669 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
4670 std::string jsonErrorMessage =
4671 "See inline comments for problem area in JSON:\n";
4672 llvm::raw_string_ostream s(jsonErrorMessage);
4673 root.printErrorContext(annotations.get(), s);
4674 diag.attachNote() << jsonErrorMessage;
4681 ParseResult FIRCircuitParser::importOMIR(CircuitOp circuit, SMLoc loc,
4682 StringRef annotationsStr,
4683 SmallVectorImpl<Attribute> &annos) {
4685 auto annotations = json::parse(annotationsStr);
4686 if (
auto err = annotations.takeError()) {
4687 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4688 auto diag = emitError(loc,
"Failed to parse OMIR file");
4689 diag.attachNote() << a.message();
4694 json::Path::Root root;
4695 if (!
fromOMIRJSON(annotations.get(), annos, root, circuit.getContext())) {
4696 auto diag = emitError(loc,
"Invalid/unsupported OMIR format");
4697 std::string jsonErrorMessage =
4698 "See inline comments for problem area in JSON:\n";
4699 llvm::raw_string_ostream s(jsonErrorMessage);
4700 root.printErrorContext(annotations.get(), s);
4701 diag.attachNote() << jsonErrorMessage;
4708 ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
4709 auto *context = getContext();
4710 SmallVector<StringRef> strings;
4713 if (parseId(name,
"expected layer name"))
4715 strings.push_back(name);
4716 }
while (consumeIf(FIRToken::period));
4718 SmallVector<FlatSymbolRefAttr> nested;
4719 nested.reserve(strings.size() - 1);
4720 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
4727 ParseResult FIRCircuitParser::parseOptionalEnabledLayers(ArrayAttr &result) {
4728 if (getToken().getKind() != FIRToken::kw_enablelayer) {
4733 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
4736 SmallVector<Attribute> layers;
4738 SymbolRefAttr layer;
4740 if (parseLayerName(layer))
4742 layers.push_back(layer);
4743 }
while (getToken().getKind() == FIRToken::kw_enablelayer);
4754 SmallVectorImpl<SMLoc> &resultPortLocs,
4757 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
4759 getIndentation() > indent) {
4765 auto backtrackState = getLexer().getCursor();
4767 bool isOutput = getToken().is(FIRToken::kw_output);
4772 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
4773 !getToken().isKeyword()) {
4774 backtrackState.restore(getLexer());
4780 LocWithInfo info(getToken().getLoc(),
this);
4781 if (parseId(name,
"expected port name") ||
4782 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
4783 parseType(type,
"expected a type in port declaration") ||
4784 info.parseOptionalInfo())
4787 StringAttr innerSym = {};
4788 resultPorts.push_back(
4789 {name, type,
direction::get(isOutput), innerSym, info.getLoc()});
4790 resultPortLocs.push_back(info.getFIRLoc());
4795 for (
auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
4796 PortInfo &port = std::get<0>(portAndLoc);
4797 auto &entry = portIds[port.
name];
4798 if (!entry.isValid()) {
4799 entry = std::get<1>(portAndLoc);
4803 emitError(std::get<1>(portAndLoc),
4804 "redefinition of name '" + port.
getName() +
"'")
4805 .attachNote(translateLocation(entry))
4806 <<
"previous definition here";
4815 ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
4816 ArrayAttr &internalPathsResult) {
4817 struct RefStatementInfo {
4819 InternalPathAttr resolvedPath;
4823 SmallVector<RefStatementInfo> refStatements;
4824 SmallPtrSet<StringAttr, 8> seenNames;
4825 SmallPtrSet<StringAttr, 8> seenRefs;
4828 if (getToken().is(FIRToken::kw_ref) &&
4829 removedFeature({4, 0, 0},
"ref statements"))
4833 while (consumeIf(FIRToken::kw_ref)) {
4834 auto loc = getToken().getLoc();
4838 if (parseId(refName,
"expected ref name"))
4840 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
4842 loc,
"ref statements for aggregate elements not yet supported");
4843 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
4846 if (!seenRefs.insert(refName).second)
4847 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
4850 auto kind = getToken().getKind();
4851 if (kind != FIRToken::string)
4852 return emitError(loc,
"expected string in ref statement");
4856 consumeToken(FIRToken::string);
4858 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
4862 SmallVector<Attribute> internalPaths(portList.size(),
4865 llvm::SmallBitVector usedRefs(refStatements.size());
4866 size_t matchedPaths = 0;
4867 for (
auto [idx, port] : llvm::enumerate(portList)) {
4868 if (!type_isa<RefType>(port.
type))
4874 return mlir::emitError(
4876 "references in ports must be output on extmodule and intmodule");
4878 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
4879 return r.refName == pname;
4882 if (refStmtIt == refStatements.end()) {
4883 if (!refStatements.empty())
4884 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
4889 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
4890 internalPaths[idx] = refStmtIt->resolvedPath;
4894 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
4895 assert(matchedPaths < refStatements.size());
4897 auto idx = usedRefs.find_first_unset();
4899 return emitError(refStatements[idx].loc,
"unused ref statement");
4903 internalPathsResult =
ArrayAttr::get(getContext(), internalPaths);
4909 ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
4911 switch (getToken().getKind()) {
4915 case FIRToken::error:
4919 case FIRToken::kw_class:
4920 case FIRToken::kw_declgroup:
4921 case FIRToken::kw_extclass:
4922 case FIRToken::kw_extmodule:
4923 case FIRToken::kw_intmodule:
4924 case FIRToken::kw_module:
4925 case FIRToken::kw_public:
4926 case FIRToken::kw_layer:
4927 case FIRToken::kw_option:
4928 case FIRToken::kw_type:
4932 if (getIndentation() == indent)
4945 SmallVector<Attribute, 8> parameters;
4946 SmallPtrSet<StringAttr, 8> seen;
4947 while (consumeIf(FIRToken::kw_parameter)) {
4951 if (parseParameter(name, value, loc))
4953 if (!seen.insert(name).second)
4954 return emitError(loc,
4955 "redefinition of parameter '" + name.getValue() +
"'");
4963 ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
4965 SmallVector<PortInfo, 8> portList;
4966 SmallVector<SMLoc> portLocs;
4967 LocWithInfo info(getToken().getLoc(),
this);
4972 consumeToken(FIRToken::kw_class);
4973 if (parseId(name,
"expected class name") ||
4974 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
4975 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
4978 if (name == circuit.getName())
4979 return mlir::emitError(info.getLoc(),
4980 "class cannot be the top of a circuit");
4982 for (
auto &portInfo : portList)
4983 if (!isa<PropertyType>(portInfo.type))
4984 return mlir::emitError(portInfo.loc,
4985 "ports on classes must be properties");
4988 auto builder = circuit.getBodyBuilder();
4989 auto classOp =
builder.create<ClassOp>(info.getLoc(), name, portList);
4990 classOp.setPrivate();
4991 deferredModules.emplace_back(
4992 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
4995 getConstants().classMap[name.getValue()] = classOp;
4996 return skipToModuleEnd(indent);
5000 ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5003 SmallVector<PortInfo, 8> portList;
5004 SmallVector<SMLoc> portLocs;
5005 LocWithInfo info(getToken().getLoc(),
this);
5010 consumeToken(FIRToken::kw_extclass);
5011 if (parseId(name,
"expected extclass name") ||
5012 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5013 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5016 if (name == circuit.getName())
5017 return mlir::emitError(info.getLoc(),
5018 "extclass cannot be the top of a circuit");
5020 for (
auto &portInfo : portList)
5021 if (!isa<PropertyType>(portInfo.type))
5022 return mlir::emitError(portInfo.loc,
5023 "ports on extclasses must be properties");
5026 auto builder = circuit.getBodyBuilder();
5027 auto extClassOp =
builder.create<ExtClassOp>(info.getLoc(), name, portList);
5030 getConstants().classMap[name.getValue()] = extClassOp;
5031 return skipToModuleEnd(indent);
5038 ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5042 SmallVector<PortInfo, 8> portList;
5043 SmallVector<SMLoc> portLocs;
5044 LocWithInfo info(getToken().getLoc(),
this);
5045 consumeToken(FIRToken::kw_extmodule);
5046 if (parseId(name,
"expected extmodule name") ||
5047 parseOptionalEnabledLayers(layers) ||
5048 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5049 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5053 if (consumeIf(FIRToken::kw_defname)) {
5054 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5055 parseId(defName,
"expected defname name"))
5059 ArrayAttr parameters;
5060 ArrayAttr internalPaths;
5065 for (
auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5066 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5067 if (ftype.hasUninferredWidth())
5068 return emitError(loc,
"extmodule port must have known width");
5073 auto builder = circuit.getBodyBuilder();
5074 auto isMainModule = (name == circuit.getName());
5076 (isMainModule && getConstants().options.scalarizePublicModules) ||
5077 getConstants().options.scalarizeExtModules
5078 ? Convention::Scalarized
5079 : Convention::Internal;
5082 auto extModuleOp =
builder.create<FExtModuleOp>(
5083 info.getLoc(), name, conventionAttr, portList, defName, annotations,
5084 parameters, internalPaths, layers);
5085 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5086 : SymbolTable::Visibility::Private;
5087 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5095 ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5100 SmallVector<PortInfo, 8> portList;
5101 SmallVector<SMLoc> portLocs;
5102 LocWithInfo info(getToken().getLoc(),
this);
5103 consumeToken(FIRToken::kw_intmodule);
5104 if (parseId(name,
"expected intmodule name") ||
5105 parseOptionalEnabledLayers(layers) ||
5106 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5107 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent) ||
5108 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5109 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5110 parseId(intName,
"expected intrinsic name"))
5113 ArrayAttr parameters;
5114 ArrayAttr internalPaths;
5118 ArrayAttr annotations = getConstants().emptyArrayAttr;
5119 auto builder = circuit.getBodyBuilder();
5121 .create<FIntModuleOp>(info.getLoc(), name, portList, intName, annotations,
5122 parameters, internalPaths, layers)
5128 ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5131 SmallVector<PortInfo, 8> portList;
5132 SmallVector<SMLoc> portLocs;
5134 auto modLoc = getToken().getLoc();
5135 LocWithInfo info(modLoc,
this);
5136 consumeToken(FIRToken::kw_module);
5137 if (parseId(name,
"expected module name") ||
5138 parseOptionalEnabledLayers(layers) ||
5139 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5140 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5144 if (name == circuit.getName()) {
5145 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5150 if (isPublic && version >=
FIRVersion{4, 0, 0}) {
5151 for (
auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5152 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5153 if (ftype.hasUninferredWidth())
5154 return emitError(loc,
"public module port must have known width");
5155 if (ftype.hasUninferredReset())
5156 return emitError(loc,
5157 "public module port must have concrete reset type");
5162 ArrayAttr annotations = getConstants().emptyArrayAttr;
5163 auto convention = Convention::Internal;
5164 if (isPublic && getConstants().options.scalarizePublicModules)
5165 convention = Convention::Scalarized;
5166 if (!isPublic && getConstants().options.scalarizeInternalModules)
5167 convention = Convention::Scalarized;
5169 auto builder = circuit.getBodyBuilder();
5170 auto moduleOp =
builder.create<FModuleOp>(info.getLoc(), name, conventionAttr,
5171 portList, annotations, layers);
5173 auto visibility = isPublic ? SymbolTable::Visibility::Public
5174 : SymbolTable::Visibility::Private;
5175 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5179 deferredModules.emplace_back(DeferredModuleToParse{
5180 moduleOp, portLocs, getLexer().getCursor(), indent});
5182 if (skipToModuleEnd(indent))
5187 ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5189 switch (getToken().getKind()) {
5190 case FIRToken::kw_class:
5191 return parseClass(circuit, indent);
5192 case FIRToken::kw_declgroup:
5193 if (requireFeature({3, 2, 0},
"optional groups") ||
5194 removedFeature({4, 0, 0},
"optional groups"))
5196 return parseLayer(circuit);
5197 case FIRToken::kw_extclass:
5198 return parseExtClass(circuit, indent);
5199 case FIRToken::kw_extmodule:
5200 return parseExtModule(circuit, indent);
5201 case FIRToken::kw_intmodule:
5202 return parseIntModule(circuit, indent);
5203 case FIRToken::kw_layer:
5204 if (requireFeature({4, 0, 0},
"layers"))
5206 return parseLayer(circuit);
5207 case FIRToken::kw_module:
5208 return parseModule(circuit,
false, indent);
5209 case FIRToken::kw_public:
5210 if (requireFeature({4, 0, 0},
"public modules"))
5213 if (getToken().getKind() == FIRToken::kw_module)
5214 return parseModule(circuit,
true, indent);
5215 return emitError(getToken().getLoc(),
"only modules may be public");
5216 case FIRToken::kw_type:
5217 return parseTypeDecl();
5218 case FIRToken::kw_option:
5219 if (requireFeature({4, 0, 0},
"option groups/instance choices"))
5221 return parseOptionDecl(circuit);
5223 return emitError(getToken().getLoc(),
"unknown toplevel definition");
5228 ParseResult FIRCircuitParser::parseTypeDecl() {
5232 auto loc = getToken().getLoc();
5234 if (getToken().isKeyword())
5235 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5236 <<
"' for type alias name";
5238 if (parseId(
id,
"expected type name") ||
5239 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5245 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5249 <<
"type alias for non-base type " << type
5250 <<
" is currently not supported. Type alias is stripped immediately";
5252 if (!getConstants().aliasMap.insert({id, type}).second)
5253 return emitError(loc) <<
"type alias `" << name.getValue()
5254 <<
"` is already defined";
5259 ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
5262 auto loc = getToken().getLoc();
5264 LocWithInfo info(getToken().getLoc(),
this);
5265 if (parseId(
id,
"expected an option group name") ||
5266 parseToken(FIRToken::colon,
5267 "expected ':' after option group definition") ||
5268 info.parseOptionalInfo())
5271 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
5272 auto optionOp =
builder.create<OptionOp>(info.getLoc(), id);
5273 auto *block =
new Block;
5274 optionOp.getBody().push_back(block);
5275 builder.setInsertionPointToEnd(block);
5277 auto baseIndent = getIndentation();
5279 while (getIndentation() == baseIndent) {
5281 LocWithInfo caseInfo(getToken().getLoc(),
this);
5282 if (parseId(
id,
"expected an option case ID") ||
5283 caseInfo.parseOptionalInfo())
5286 if (!cases.insert(
id).second)
5287 return emitError(loc)
5288 <<
"duplicate option case definition '" <<
id <<
"'";
5290 builder.create<OptionCaseOp>(caseInfo.getLoc(), id);
5297 ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
5298 auto baseIndent = getIndentation();
5301 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
5304 auto parseOne = [&](
Block *block) -> ParseResult {
5305 auto indent = getIndentation();
5306 StringRef id, convention;
5307 LocWithInfo info(getToken().getLoc(),
this);
5309 if (parseId(
id,
"expected layer name") || parseGetSpelling(convention))
5311 auto layerConvention = symbolizeLayerConvention(convention);
5312 if (!layerConvention) {
5313 emitError() <<
"unknown convention '" << convention
5314 <<
"' (did you misspell it?)";
5318 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
5319 info.parseOptionalInfo())
5321 auto builder = OpBuilder::atBlockEnd(block);
5323 auto layerOp =
builder.create<LayerOp>(info.getLoc(), id, *layerConvention);
5324 layerOp->getRegion(0).push_back(
new Block());
5325 layerStack.push_back({indent, layerOp});
5329 if (parseOne(circuit.getBodyBlock()))
5333 while (getIndentation() > baseIndent) {
5334 switch (getToken().getKind()) {
5335 case FIRToken::kw_declgroup:
5336 case FIRToken::kw_layer: {
5339 while (layerStack.back().first >= getIndentation())
5340 layerStack.pop_back();
5341 auto parentLayer = layerStack.back().second;
5342 if (parseOne(&parentLayer.getBody().front()))
5347 return emitError(
"expected 'layer'"), failure();
5356 FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
5357 DeferredModuleToParse &deferredModule) {
5358 FModuleLike moduleOp = deferredModule.moduleOp;
5359 auto &body = moduleOp->getRegion(0).front();
5360 auto &portLocs = deferredModule.portLocs;
5364 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
5367 deferredModule.lexerCursor.restore(moduleBodyLexer);
5369 FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
5373 auto portList = moduleOp.getPorts();
5374 auto portArgs = body.getArguments();
5375 for (
auto tuple : llvm::zip(portList, portLocs, portArgs)) {
5376 PortInfo &port = std::get<0>(tuple);
5377 llvm::SMLoc loc = std::get<1>(tuple);
5378 BlockArgument portArg = std::get<2>(tuple);
5380 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
5384 hw::InnerSymbolNamespace modNameSpace(moduleOp);
5385 FIRStmtParser stmtParser(body, moduleContext, modNameSpace, circuitSymTbl,
5389 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
5397 SmallVector<PrintFOp> buffer;
5398 deferredModule.moduleOp.walk(
5399 [&buffer](PrintFOp printFOp) { buffer.push_back(printFOp); });
5401 for (
auto printFOp : buffer) {
5408 deferredModule.moduleOp.walk([](Forceable fop) {
5409 if (fop.isForceable() && fop.getDataRef().use_empty())
5424 ParseResult FIRCircuitParser::parseCircuit(
5425 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
5426 SmallVectorImpl<const llvm::MemoryBuffer *> &omirBufs,
5427 mlir::TimingScope &ts) {
5429 auto indent = getIndentation();
5430 if (consumeIf(FIRToken::kw_FIRRTL)) {
5431 if (!indent.has_value())
5432 return emitError(
"'FIRRTL' must be first token on its line"), failure();
5433 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
5434 parseVersionLit(
"expected version literal"))
5436 indent = getIndentation();
5439 if (!indent.has_value())
5440 return emitError(
"'circuit' must be first token on its line"), failure();
5441 unsigned circuitIndent = *indent;
5443 LocWithInfo info(getToken().getLoc(),
this);
5445 SMLoc inlineAnnotationsLoc;
5446 StringRef inlineAnnotations;
5449 if (parseToken(FIRToken::kw_circuit,
5450 "expected a top-level 'circuit' definition") ||
5451 parseId(name,
"expected circuit name") ||
5452 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
5453 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
5454 info.parseOptionalInfo())
5458 OpBuilder b(mlirModule.getBodyRegion());
5459 auto circuit = b.create<CircuitOp>(info.getLoc(), name);
5462 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
5468 SmallVector<Attribute> annos;
5469 if (!inlineAnnotations.empty())
5470 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
5474 for (
auto *annotationsBuf : annotationsBufs)
5475 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
5479 parseAnnotationTimer.stop();
5480 auto parseOMIRTimer = ts.nest(
"Parse OMIR");
5484 for (
auto *omirBuf : omirBufs)
5485 if (importOMIR(circuit, info.getFIRLoc(), omirBuf->getBuffer(), annos))
5488 parseOMIRTimer.stop();
5496 auto parseTimer = ts.nest(
"Parse modules");
5497 deferredModules.reserve(16);
5501 switch (getToken().getKind()) {
5509 case FIRToken::error:
5513 emitError(
"unexpected token in circuit");
5516 case FIRToken::kw_class:
5517 case FIRToken::kw_declgroup:
5518 case FIRToken::kw_extclass:
5519 case FIRToken::kw_extmodule:
5520 case FIRToken::kw_intmodule:
5521 case FIRToken::kw_layer:
5522 case FIRToken::kw_module:
5523 case FIRToken::kw_option:
5524 case FIRToken::kw_public:
5525 case FIRToken::kw_type: {
5526 auto indent = getIndentation();
5527 if (!indent.has_value())
5528 return emitError(
"'module' must be first token on its line"), failure();
5529 unsigned definitionIndent = *indent;
5531 if (definitionIndent <= circuitIndent)
5532 return emitError(
"module should be indented more"), failure();
5534 if (parseToplevelDefinition(circuit, definitionIndent))
5548 (void)getLexer().translateLocation(info.getFIRLoc());
5554 DenseMap<Attribute, Location> nameToOrigLoc;
5555 for (
auto &op : *circuit.getBodyBlock()) {
5558 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
5563 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
5566 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
5567 .attachNote(it.first->second)
5568 .append(
"see existing symbol definition here");
5574 SymbolTable circuitSymTbl(circuit);
5577 auto anyFailed = mlir::failableParallelForEachN(
5578 getContext(), 0, deferredModules.size(), [&](
size_t index) {
5579 if (parseModuleBody(circuitSymTbl, deferredModules[index]))
5583 if (failed(anyFailed))
5597 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
5598 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
5599 unsigned fileID = 1;
5601 annotationsBufs.push_back(
5602 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5604 SmallVector<const llvm::MemoryBuffer *> omirBufs;
5605 for (
unsigned e = sourceMgr.getNumBuffers(); fileID < e; ++fileID)
5607 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5609 context->loadDialect<CHIRRTLDialect>();
5610 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
5617 SharedParserConstants state(context, options);
5618 FIRLexer lexer(sourceMgr, context);
5620 if (FIRCircuitParser(state, lexer, *module, version)
5621 .parseCircuit(annotationsBufs, omirBufs, ts))
5626 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
5627 if (failed(verify(*module)))
5634 static mlir::TranslateToMLIRRegistration fromFIR(
5635 "import-firrtl",
"import .fir",
5636 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
5637 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 std::vector< mlir::Value > toVector(mlir::ValueRange range)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
unsigned getFieldID() const
Get the field ID of this FieldRef, which is a unique identifier mapped to a specific field in a bundl...
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
This is the common base class between SIntType and UIntType.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
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.
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.
constexpr FIRVersion minimumFIRVersion(0, 2, 0)
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
bool fromOMIRJSON(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Convert a JSON value containing OMIR JSON (an array of OMNodes), convert this to an OMIRAnnotation,...
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
constexpr FIRVersion nextFIRVersion(3, 3, 0)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
@ IgnoreInfo
If this is set to true, the @info locators are ignored, and the locations are set to the location in ...
The FIRRTL specification version.
This holds the name and type that describes the module's ports.
bool isOutput() const
Return true if this is a simple output-only port.
StringRef getName() const