26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Diagnostics.h"
29#include "mlir/IR/ImplicitLocOpBuilder.h"
30#include "mlir/IR/PatternMatch.h"
31#include "mlir/IR/Threading.h"
32#include "mlir/IR/Verifier.h"
33#include "mlir/Support/Timing.h"
34#include "mlir/Tools/mlir-translate/Translation.h"
35#include "llvm/ADT/PointerEmbeddedInt.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallPtrSet.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/StringSet.h"
40#include "llvm/ADT/StringSwitch.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/JSON.h"
43#include "llvm/Support/SourceMgr.h"
44#include "llvm/Support/raw_ostream.h"
49using namespace firrtl;
50using namespace chirrtl;
54using mlir::LocationAttr;
67struct SharedParserConstants {
69 : context(context), options(options),
70 emptyArrayAttr(ArrayAttr::
get(context, {})),
71 loIdentifier(StringAttr::get(context,
"lo")),
72 hiIdentifier(StringAttr::get(context,
"hi")),
73 amountIdentifier(StringAttr::get(context,
"amount")),
75 hw::InnerRefAttr::get(StringAttr::get(context,
"module"),
76 StringAttr::get(context,
"placeholder"))) {}
79 MLIRContext *
const context;
85 llvm::StringMap<FIRRTLType> aliasMap;
88 llvm::DenseMap<StringRef, ClassLike> classMap;
91 const ArrayAttr emptyArrayAttr;
94 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
97 const hw::InnerRefAttr placeholderInnerRef;
100 SharedParserConstants(
const SharedParserConstants &) =
delete;
101 void operator=(
const SharedParserConstants &) =
delete;
114 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
116 : version(version), constants(constants), lexer(lexer),
117 locatorFilenameCache(constants.loIdentifier ) {
121 SharedParserConstants &getConstants()
const {
return constants; }
122 MLIRContext *getContext()
const {
return constants.context; }
124 FIRLexer &getLexer() {
return lexer; }
127 std::optional<unsigned> getIndentation()
const {
132 const FIRToken &getToken()
const {
return lexer.getToken(); }
133 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
140 InFlightDiagnostic emitError(
const Twine &message = {}) {
141 return emitError(getToken().
getLoc(), message);
143 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
146 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
147 return emitWarning(getToken().
getLoc(), message);
150 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
160 Location translateLocation(llvm::SMLoc loc) {
161 return lexer.translateLocation(loc);
166 ParseResult parseOptionalInfoLocator(LocationAttr &result);
170 ParseResult parseOptionalName(StringAttr &name);
176 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
177 return requireFeature(minimum, feature, getToken().
getLoc());
180 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
181 if (version < minimum)
182 return emitError(loc)
183 << feature <<
" are a FIRRTL " << minimum
184 <<
"+ feature, but the specified FIRRTL version was " << version;
188 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
189 return removedFeature(removedVersion, feature, getToken().
getLoc());
192 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
194 if (version >= removedVersion)
195 return emitError(loc)
196 << feature <<
" were removed in FIRRTL " << removedVersion
197 <<
", but the specified FIRRTL version was " << version;
207 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
216 if (getToken().isNot(kind))
226 FIRToken consumedToken = getToken();
227 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
228 "shouldn't advance past EOF or errors");
230 return consumedToken;
239 FIRToken consumedToken = getToken();
240 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
242 return consumedToken;
247 ParseResult parseGetSpelling(StringRef &spelling) {
248 spelling = getTokenSpelling();
254 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
259 const std::function<ParseResult()> &parseElement);
266 ParseResult parseIntLit(APInt &result,
const Twine &message);
267 ParseResult parseIntLit(int64_t &result,
const Twine &message);
268 ParseResult parseIntLit(int32_t &result,
const Twine &message);
271 ParseResult parseVersionLit(
const Twine &message);
274 template <
typename T>
275 ParseResult parseOptionalWidth(T &result);
278 ParseResult parseId(StringRef &result,
const Twine &message);
279 ParseResult parseId(StringAttr &result,
const Twine &message);
280 ParseResult parseFieldId(StringRef &result,
const Twine &message);
281 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
282 const Twine &message);
283 ParseResult parseEnumType(
FIRRTLType &result);
284 ParseResult parseListType(
FIRRTLType &result);
287 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
289 ParseResult parseRUW(RUWAttr &result);
290 ParseResult parseOptionalRUW(RUWAttr &result);
292 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
293 SMLoc &resultLoc,
bool allowAggregates =
false);
294 ParseResult parseParameterValue(Attribute &resultValue,
295 bool allowAggregates =
false);
301 FIRParser(
const FIRParser &) =
delete;
302 void operator=(
const FIRParser &) =
delete;
306 SharedParserConstants &constants;
310 StringAttr locatorFilenameCache;
312 FileLineColLoc fileLineColLocCache;
321InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
322 auto diag = mlir::emitError(translateLocation(loc), message);
326 if (getToken().is(FIRToken::error))
331InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
332 return mlir::emitWarning(translateLocation(loc), message);
342 const Twine &message) {
343 if (consumeIf(expectedToken))
345 return emitError(message);
352 const std::function<ParseResult()> &parseElement) {
353 if (consumeIf(rightToken))
359 while (consumeIf(FIRToken::comma)) {
364 if (parseToken(rightToken,
"expected ','"))
396 if (failed(
parser->parseOptionalInfoLocator(loc)))
400 switch (
parser->constants.options.infoLocatorHandling) {
401 case ILH::IgnoreInfo:
402 assert(0 &&
"Should not return info locations if ignoring");
404 case ILH::PreferInfo:
408 infoLoc = FusedLoc::get(loc.getContext(),
409 {loc, parser->translateLocation(firLoc)});
436ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
437 if (getToken().isNot(FIRToken::fileinfo))
440 auto loc = getToken().getLoc();
442 auto spelling = getTokenSpelling();
443 consumeToken(FIRToken::fileinfo);
447 constants.options.infoLocatorHandling ==
448 FIRParserOptions::InfoLocHandling::IgnoreInfo,
449 locatorFilenameCache, fileLineColLocCache, getContext());
452 if (!locationPair.first) {
453 mlir::emitWarning(translateLocation(loc),
454 "ignoring unknown @ info record format");
460 if (locationPair.first && constants.options.infoLocatorHandling ==
461 FIRParserOptions::InfoLocHandling::IgnoreInfo)
465 result = *locationPair.second;
473ParseResult FIRParser::parseOptionalName(StringAttr &name) {
475 if (getToken().isNot(FIRToken::colon)) {
476 name = StringAttr::get(getContext(),
"");
480 consumeToken(FIRToken::colon);
482 if (parseId(nameRef,
"expected result name"))
485 name = StringAttr::get(getContext(), nameRef);
496ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
498 if (getToken().isNot(FIRToken::inlineannotation))
501 loc = getToken().getLoc();
503 result = getTokenSpelling().drop_front(2).drop_back(1);
504 consumeToken(FIRToken::inlineannotation);
522ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
523 auto spelling = getTokenSpelling();
524 bool isNegative =
false;
525 switch (getToken().getKind()) {
526 case FIRToken::signed_integer:
527 isNegative = spelling[0] ==
'-';
528 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
529 spelling = spelling.drop_front();
531 case FIRToken::integer:
532 if (spelling.getAsInteger(10, result))
533 return emitError(message), failure();
537 if (result.isNegative())
538 result = result.zext(result.getBitWidth() + 1);
547 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
548 result = result.trunc(32);
552 case FIRToken::radix_specified_integer: {
553 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
555 if (spelling[0] ==
'-') {
557 spelling = spelling.drop_front();
559 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
564 spelling = spelling.drop_front(2);
565 if (spelling.getAsInteger(base, result))
566 return emitError(
"invalid character in integer literal"), failure();
567 if (result.isNegative())
568 result = result.zext(result.getBitWidth() + 1);
574 case FIRToken::string: {
577 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
580 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
581 spelling = spelling.drop_back().drop_front();
585 switch (spelling.empty() ?
' ' : spelling.front()) {
596 return emitError(
"expected base specifier (h/o/b) in integer literal"),
599 spelling = spelling.drop_front();
602 bool isNegative =
false;
603 if (!spelling.empty() && spelling.front() ==
'+')
604 spelling = spelling.drop_front();
605 else if (!spelling.empty() && spelling.front() ==
'-') {
607 spelling = spelling.drop_front();
611 if (spelling.empty())
612 return emitError(
"expected digits in integer literal"), failure();
614 if (spelling.getAsInteger(base, result))
615 return emitError(
"invalid character in integer literal"), failure();
620 if (result.isNegative())
621 result = result.zext(result.getBitWidth() + 1);
626 consumeToken(FIRToken::string);
631 return emitError(
"expected integer literal"), failure();
635ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
637 auto loc = getToken().getLoc();
638 if (parseIntLit(value, message))
641 result = (int64_t)value.getLimitedValue(INT64_MAX);
643 return emitError(loc,
"value is too big to handle"), failure();
647ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
649 auto loc = getToken().getLoc();
650 if (parseIntLit(value, message))
653 result = (int32_t)value.getLimitedValue(INT32_MAX);
655 return emitError(loc,
"value is too big to handle"), failure();
661ParseResult FIRParser::parseVersionLit(
const Twine &message) {
662 auto spelling = getTokenSpelling();
663 if (getToken().getKind() != FIRToken::version)
664 return emitError(message), failure();
666 auto [a, d] = spelling.split(
".");
667 auto [b, c] = d.split(
".");
668 APInt aInt, bInt, cInt;
669 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
670 c.getAsInteger(10, cInt))
671 return emitError(
"failed to parse version string"), failure();
672 version.major = aInt.getLimitedValue(UINT32_MAX);
673 version.minor = bInt.getLimitedValue(UINT32_MAX);
674 version.patch = cInt.getLimitedValue(UINT32_MAX);
675 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
676 return emitError(
"integers out of range"), failure();
680 consumeToken(FIRToken::version);
688ParseResult FIRParser::parseOptionalWidth(T &result) {
689 if (!consumeIf(FIRToken::less))
690 return result = -1, success();
693 auto widthLoc = getToken().getLoc();
694 if (parseIntLit(result,
"expected width") ||
695 parseToken(FIRToken::greater,
"expected >"))
699 return emitError(widthLoc,
"invalid width specifier"), failure();
708ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
709 switch (getToken().getKind()) {
711 case FIRToken::identifier:
712 case FIRToken::literal_identifier:
714#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
715#include "FIRTokenKinds.def"
720 if (getToken().getKind() == FIRToken::literal_identifier)
721 result = getTokenSpelling().drop_front().drop_back();
723 result = getTokenSpelling();
733ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
735 if (parseId(name, message))
738 result = StringAttr::get(getContext(), name);
747ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
749 result = getTokenSpelling();
750 if (consumeIf(FIRToken::integer))
756 if (parseId(result, message))
768ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
769 const Twine &message) {
771 StringRef tmp = getTokenSpelling();
773 if (consumeIf(FIRToken::integer)) {
774 result.push_back(tmp);
778 if (consumeIf(FIRToken::floatingpoint)) {
782 auto [a, b] = tmp.split(
".");
788 if (consumeIf(FIRToken::version)) {
790 auto [a, d] = tmp.split(
".");
791 auto [b, c] = d.split(
".");
799 if (parseId(tmp, message))
801 result.push_back(tmp);
807ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
808 if (parseToken(FIRToken::l_brace_bar,
809 "expected leading '{|' in enumeration type"))
811 SmallVector<FEnumType::EnumElement> elements;
812 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
813 auto fieldLoc = getToken().getLoc();
817 if (parseId(name,
"expected valid identifier for enumeration tag"))
822 if (consumeIf(FIRToken::colon)) {
824 if (
parseType(parsedType,
"expected enumeration type"))
826 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
828 return emitError(fieldLoc,
"field must be a base type");
831 type = UIntType::get(getContext(), 0);
833 elements.emplace_back(StringAttr::get(getContext(), name), type);
837 result = FEnumType::get(getContext(), elements);
841ParseResult FIRParser::parsePropertyType(
PropertyType &result,
842 const Twine &message) {
846 auto prop = type_dyn_cast<PropertyType>(type);
848 return emitError(
"expected property type");
854ParseResult FIRParser::parseListType(
FIRRTLType &result) {
855 consumeToken(FIRToken::kw_List);
858 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
859 parsePropertyType(
elementType,
"expected List element type") ||
860 parseToken(FIRToken::greater,
"expected '>' in List type"))
885ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
886 switch (getToken().getKind()) {
888 return emitError(message), failure();
890 case FIRToken::kw_Clock:
891 consumeToken(FIRToken::kw_Clock);
892 result = ClockType::get(getContext());
895 case FIRToken::kw_Inst: {
899 consumeToken(FIRToken::kw_Inst);
900 if (parseToken(FIRToken::less,
"expected < in Inst type"))
903 auto loc = getToken().getLoc();
905 if (parseId(
id,
"expected class name in Inst type"))
909 const auto &classMap = getConstants().classMap;
910 auto lookup = classMap.find(
id);
911 if (lookup == classMap.end())
912 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
914 auto classOp = lookup->second;
916 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
919 result = classOp.getInstanceType();
923 case FIRToken::kw_AnyRef: {
927 consumeToken(FIRToken::kw_AnyRef);
928 result = AnyRefType::get(getContext());
932 case FIRToken::kw_Reset:
933 consumeToken(FIRToken::kw_Reset);
934 result = ResetType::get(getContext());
937 case FIRToken::kw_AsyncReset:
938 consumeToken(FIRToken::kw_AsyncReset);
939 result = AsyncResetType::get(getContext());
942 case FIRToken::kw_UInt:
943 case FIRToken::kw_SInt:
944 case FIRToken::kw_Analog: {
945 auto kind = getToken().getKind();
950 if (parseOptionalWidth(width))
953 if (kind == FIRToken::kw_SInt)
954 result = SIntType::get(getContext(), width);
955 else if (kind == FIRToken::kw_UInt)
956 result = UIntType::get(getContext(), width);
958 assert(kind == FIRToken::kw_Analog);
959 result = AnalogType::get(getContext(), width);
964 case FIRToken::kw_Probe:
965 case FIRToken::kw_RWProbe: {
966 auto kind = getToken().getKind();
967 auto loc = getToken().getLoc();
972 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
973 parseType(type,
"expected probe data type"))
976 SmallVector<StringRef> layers;
977 if (consumeIf(FIRToken::comma)) {
978 if (requireFeature({4, 0, 0},
"colored probes"))
983 loc = getToken().getLoc();
984 if (parseId(layer,
"expected layer name"))
986 layers.push_back(layer);
987 }
while (consumeIf(FIRToken::period));
990 if (!consumeIf(FIRToken::greater))
991 return emitError(loc,
"expected '>' to end reference type");
993 bool forceable = kind == FIRToken::kw_RWProbe;
995 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
997 return emitError(loc,
"invalid probe inner type, must be base-type");
1000 return emitError(loc,
"probe inner type must be passive");
1002 if (forceable &&
innerType.containsConst())
1003 return emitError(loc,
"rwprobe cannot contain const");
1005 SymbolRefAttr layer;
1006 if (!layers.empty()) {
1008 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1009 return FlatSymbolRefAttr::get(getContext(), a);
1011 layer = SymbolRefAttr::get(getContext(), layers.front(),
1012 llvm::to_vector(nestedLayers));
1015 result = RefType::get(innerType, forceable, layer);
1019 case FIRToken::l_brace: {
1020 consumeToken(FIRToken::l_brace);
1022 SmallVector<OpenBundleType::BundleElement, 4> elements;
1023 bool bundleCompatible =
true;
1024 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1025 bool isFlipped = consumeIf(FIRToken::kw_flip);
1027 StringRef fieldName;
1029 if (parseFieldId(fieldName,
"expected bundle field name") ||
1030 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1032 if (
parseType(type,
"expected bundle field type"))
1036 {StringAttr::get(getContext(), fieldName), isFlipped, type});
1037 bundleCompatible &= isa<BundleType::ElementType>(type);
1044 if (bundleCompatible) {
1045 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1046 return BundleType::BundleElement{
1047 element.name, element.isFlip,
1048 cast<BundleType::ElementType>(element.type)};
1050 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1052 result = OpenBundleType::get(getContext(), elements);
1056 case FIRToken::l_brace_bar: {
1057 if (parseEnumType(result))
1062 case FIRToken::identifier: {
1064 auto loc = getToken().getLoc();
1065 if (parseId(
id,
"expected a type alias name"))
1067 auto it = constants.aliasMap.find(
id);
1068 if (it == constants.aliasMap.end()) {
1069 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1072 result = it->second;
1076 case FIRToken::kw_const: {
1077 consumeToken(FIRToken::kw_const);
1078 auto nextToken = getToken();
1079 auto loc = nextToken.getLoc();
1082 if (nextToken.is(FIRToken::kw_const))
1083 return emitError(loc,
"'const' can only be specified once on a type");
1088 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1090 return emitError(loc,
"only hardware types can be 'const'");
1092 result = baseType.getConstType(
true);
1096 case FIRToken::kw_String:
1097 if (requireFeature({3, 1, 0},
"Strings"))
1099 consumeToken(FIRToken::kw_String);
1100 result = StringType::get(getContext());
1102 case FIRToken::kw_Integer:
1103 if (requireFeature({3, 1, 0},
"Integers"))
1105 consumeToken(FIRToken::kw_Integer);
1106 result = FIntegerType::get(getContext());
1108 case FIRToken::kw_Bool:
1111 consumeToken(FIRToken::kw_Bool);
1112 result = BoolType::get(getContext());
1114 case FIRToken::kw_Double:
1117 consumeToken(FIRToken::kw_Double);
1118 result = DoubleType::get(getContext());
1120 case FIRToken::kw_Path:
1123 consumeToken(FIRToken::kw_Path);
1124 result = PathType::get(getContext());
1126 case FIRToken::kw_List:
1127 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1133 while (consumeIf(FIRToken::l_square)) {
1134 auto sizeLoc = getToken().getLoc();
1136 if (parseIntLit(size,
"expected width") ||
1137 parseToken(FIRToken::r_square,
"expected ]"))
1141 return emitError(sizeLoc,
"invalid size specifier"), failure();
1143 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1145 result = FVectorType::get(baseType, size);
1147 result = OpenVectorType::get(result, size);
1154ParseResult FIRParser::parseRUW(RUWAttr &result) {
1155 switch (getToken().getKind()) {
1157 case FIRToken::kw_old:
1158 result = RUWAttr::Old;
1159 consumeToken(FIRToken::kw_old);
1161 case FIRToken::kw_new:
1162 result = RUWAttr::New;
1163 consumeToken(FIRToken::kw_new);
1165 case FIRToken::kw_undefined:
1166 result = RUWAttr::Undefined;
1167 consumeToken(FIRToken::kw_undefined);
1177ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1178 switch (getToken().getKind()) {
1182 case FIRToken::kw_old:
1183 result = RUWAttr::Old;
1184 consumeToken(FIRToken::kw_old);
1186 case FIRToken::kw_new:
1187 result = RUWAttr::New;
1188 consumeToken(FIRToken::kw_new);
1190 case FIRToken::kw_undefined:
1191 result = RUWAttr::Undefined;
1192 consumeToken(FIRToken::kw_undefined);
1200ParseResult FIRParser::parseParameter(StringAttr &resultName,
1201 Attribute &resultValue, SMLoc &resultLoc,
1202 bool allowAggregates) {
1203 auto loc = getToken().getLoc();
1207 if (parseId(name,
"expected parameter name") ||
1208 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1213 if (parseParameterValue(value, allowAggregates))
1216 resultName = StringAttr::get(getContext(), name);
1217 resultValue = value;
1228ParseResult FIRParser::parseParameterValue(Attribute &value,
1229 bool allowAggregates) {
1230 mlir::Builder builder(getContext());
1231 switch (getToken().getKind()) {
1234 case FIRToken::integer:
1235 case FIRToken::signed_integer: {
1237 if (parseIntLit(result,
"invalid integer parameter"))
1243 if (result.getBitWidth() < 32)
1244 result = result.sext(32);
1246 value = builder.getIntegerAttr(
1247 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1253 case FIRToken::string: {
1255 value = builder.getStringAttr(getToken().getStringValue());
1256 consumeToken(FIRToken::string);
1261 case FIRToken::verbatim_string: {
1263 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1264 value = hw::ParamVerbatimAttr::get(text);
1265 consumeToken(FIRToken::verbatim_string);
1270 case FIRToken::floatingpoint: {
1272 if (!llvm::to_float(getTokenSpelling(), v))
1273 return emitError(
"invalid float parameter syntax"), failure();
1275 value = builder.getF64FloatAttr(v);
1276 consumeToken(FIRToken::floatingpoint);
1281 case FIRToken::l_square: {
1282 if (!allowAggregates)
1283 return emitError(
"expected non-aggregate parameter value");
1286 SmallVector<Attribute> elements;
1287 auto parseElement = [&] {
1288 return parseParameterValue(elements.emplace_back(),
1291 if (parseListUntil(FIRToken::r_square, parseElement))
1294 value = builder.getArrayAttr(elements);
1299 case FIRToken::l_brace: {
1300 if (!allowAggregates)
1301 return emitError(
"expected non-aggregate parameter value");
1304 NamedAttrList fields;
1305 auto parseField = [&]() -> ParseResult {
1306 StringAttr fieldName;
1307 Attribute fieldValue;
1309 if (parseParameter(fieldName, fieldValue, fieldLoc,
1312 if (fields.set(fieldName, fieldValue))
1313 return emitError(fieldLoc)
1314 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1317 if (parseListUntil(FIRToken::r_brace, parseField))
1320 value = fields.getDictionary(getContext());
1325 return emitError(
"expected parameter value");
1340 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1348struct UnbundledValueRestorer {
1350 size_t startingSize;
1352 startingSize = list.size();
1354 ~UnbundledValueRestorer() { list.resize(startingSize); }
1363struct FIRModuleContext :
public FIRParser {
1364 explicit FIRModuleContext(SharedParserConstants &constants,
FIRLexer &lexer,
1366 : FIRParser(constants, lexer, version) {}
1372 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1375 template <
typename OpTy = ConstantOp,
typename... Args>
1376 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1377 Type type, Args &&...args) {
1378 auto &result = constantCache[{attr, type}];
1384 OpBuilder::InsertPoint savedIP;
1386 auto *parentOp = builder.getInsertionBlock()->getParentOp();
1387 if (!isa<FModuleLike>(parentOp)) {
1388 savedIP = builder.saveInsertionPoint();
1389 while (!isa<FModuleLike>(parentOp)) {
1390 builder.setInsertionPoint(parentOp);
1391 parentOp = builder.getInsertionBlock()->getParentOp();
1395 result = builder.create<OpTy>(type, std::forward<Args>(args)...);
1397 if (savedIP.isSet())
1398 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1409 Value &getCachedSubaccess(Value value,
unsigned index) {
1410 auto &result = subaccessCache[{value, index}];
1413 auto it = scopeMap.find(value.getParentBlock());
1414 if (it != scopeMap.end())
1415 it->second->scopedSubaccesses.push_back({result, index});
1425 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1426 bool insertNameIntoGlobalScope =
false);
1427 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1428 bool insertNameIntoGlobalScope =
false) {
1430 insertNameIntoGlobalScope);
1434 void removeSymbolEntry(StringRef name);
1438 SMLoc loc,
bool fatal =
true);
1443 StringRef field, SMLoc loc);
1451 assert(index < unbundledValues.size());
1452 return unbundledValues[index];
1462 struct ContextScope {
1463 friend struct FIRModuleContext;
1464 ContextScope(FIRModuleContext &moduleContext, Block *block)
1465 : moduleContext(moduleContext), block(block),
1466 previousScope(moduleContext.currentScope) {
1467 moduleContext.currentScope =
this;
1468 moduleContext.scopeMap[block] =
this;
1473 for (
auto *entryPtr : scopedDecls)
1474 entryPtr->second.first = SMLoc();
1477 for (
auto subaccess : scopedSubaccesses)
1478 moduleContext.subaccessCache.erase(subaccess);
1480 moduleContext.scopeMap.erase(block);
1482 moduleContext.currentScope = previousScope;
1486 void operator=(
const ContextScope &) =
delete;
1487 ContextScope(
const ContextScope &) =
delete;
1489 FIRModuleContext &moduleContext;
1491 ContextScope *previousScope;
1492 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1493 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1507 DenseMap<Block *, ContextScope *> scopeMap;
1512 ContextScope *currentScope =
nullptr;
1518void FIRModuleContext::removeSymbolEntry(StringRef name) {
1519 symbolTable.erase(name);
1528ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1530 bool insertNameIntoGlobalScope) {
1533 auto [entryIt, inserted] =
1538 if (entryIt->second.first.isValid()) {
1540 emitError(loc,
"redefinition of name '" + name +
"' ")
1541 .attachNote(translateLocation(entryIt->second.first))
1542 <<
"previous definition here.";
1545 emitError(loc,
"redefinition of name '" + name +
"' ")
1546 <<
"- FIRRTL has flat namespace and requires all "
1547 <<
"declarations in a module to have unique names.";
1554 entryIt->second = {loc, entry};
1555 if (currentScope && !insertNameIntoGlobalScope)
1556 currentScope->scopedDecls.push_back(&*entryIt);
1563 StringRef name, SMLoc loc) {
1564 auto &entry = symbolTable[name];
1565 if (!entry.first.isValid())
1566 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1567 result = entry.second;
1568 assert(result &&
"name in symbol table without definition");
1572ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1574 SMLoc loc,
bool fatal) {
1575 if (!isa<Value>(entry)) {
1577 emitError(loc,
"bundle value should only be used from subfield");
1580 result = cast<Value>(entry);
1584ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1586 StringRef fieldName,
1588 if (!isa<UnbundledID>(entry)) {
1589 emitError(loc,
"value should not be used from subfield");
1593 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1595 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1596 assert(unbundledId < unbundledValues.size());
1598 for (
auto elt : ubEntry) {
1599 if (elt.first == fieldAttr) {
1600 result = elt.second;
1605 emitError(loc,
"use of invalid field name '")
1606 << fieldName <<
"' on bundle value";
1632struct LazyLocationListener :
public OpBuilder::Listener {
1633 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1634 assert(builder.getListener() ==
nullptr);
1635 builder.setListener(
this);
1638 ~LazyLocationListener() {
1639 assert(subOps.empty() &&
"didn't process parsed operations");
1640 assert(builder.getListener() ==
this);
1641 builder.setListener(
nullptr);
1644 void startStatement() {
1645 assert(!isActive &&
"Already processing a statement");
1651 void endStatement(FIRParser &parser) {
1652 assert(isActive &&
"Not parsing a statement");
1656 for (
auto opAndSMLoc : subOps) {
1660 switch (parser.getConstants().options.infoLocatorHandling) {
1661 case ILH::IgnoreInfo:
1663 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1665 case ILH::PreferInfo:
1666 opAndSMLoc.first->setLoc(infoLoc);
1668 case ILH::FusedInfo:
1669 opAndSMLoc.first->setLoc(FusedLoc::get(
1670 infoLoc.getContext(),
1671 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1678 for (
auto opAndSMLoc : subOps)
1679 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1684 infoLoc = LocationAttr();
1685 currentSMLoc = SMLoc();
1690 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1693 void setInfoLoc(LocationAttr loc) {
1694 assert(!infoLoc &&
"Info location multiply specified");
1700 void notifyOperationInserted(Operation *op,
1701 mlir::IRRewriter::InsertPoint)
override {
1702 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1703 assert(isActive &&
"Not parsing a statement");
1704 subOps.push_back({op, currentSMLoc});
1709 bool isActive =
false;
1717 LocationAttr infoLoc;
1724 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1726 void operator=(
const LazyLocationListener &) =
delete;
1727 LazyLocationListener(
const LazyLocationListener &) =
delete;
1735struct InnerSymFixups {
1738 fixups.push_back({user, target});
1747 hw::InnerRefUserOpInterface innerRefUser;
1750 SmallVector<Fixup, 0> fixups;
1756 for (
auto &f : fixups) {
1759 return isnc.get(module);
1761 assert(ref &&
"unable to resolve inner symbol target");
1765 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1766 .Case<RWProbeOp>([ref](RWProbeOp op) {
1767 op.setTargetAttr(ref);
1770 .Default([](
auto *op) {
1771 return op->emitError(
"unknown inner-ref user requiring fixup");
1782struct FIRStmtParser :
public FIRParser {
1783 explicit FIRStmtParser(Block &blockToInsertInto,
1784 FIRModuleContext &moduleContext,
1785 InnerSymFixups &innerSymFixups,
1786 const SymbolTable &circuitSymTbl,
FIRVersion version,
1787 SymbolRefAttr layerSym = {})
1788 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1790 builder(UnknownLoc::
get(getContext()), getContext()),
1791 locationProcessor(this->builder), moduleContext(moduleContext),
1792 innerSymFixups(innerSymFixups), layerSym(layerSym),
1793 circuitSymTbl(circuitSymTbl) {
1794 builder.setInsertionPointToEnd(&blockToInsertInto);
1797 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1798 ParseResult parseSimpleStmtBlock(
unsigned indent);
1801 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1804 void emitInvalidate(Value val,
Flow flow);
1810 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1813 ParseResult parseOptionalInfo() {
1815 if (failed(parseOptionalInfoLocator(loc)))
1817 locationProcessor.setInfoLoc(loc);
1822 ParseResult parseExpImpl(Value &result,
const Twine &message,
1823 bool isLeadingStmt);
1824 ParseResult parseExp(Value &result,
const Twine &message) {
1825 return parseExpImpl(result, message,
false);
1827 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1828 return parseExpImpl(result, message,
true);
1830 ParseResult parseEnumExp(Value &result);
1831 ParseResult parsePathExp(Value &result);
1832 ParseResult parseRefExp(Value &result,
const Twine &message);
1833 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1834 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1835 const Twine &message);
1838 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1839 ParseResult parseIntrinsicStmt() {
1841 return parseIntrinsic(unused,
true);
1843 ParseResult parseIntrinsicExp(Value &result) {
1844 return parseIntrinsic(result,
false);
1846 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1848 template <
typename subop>
1849 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1850 ParseResult parseOptionalExpPostscript(Value &result,
1851 bool allowDynamic =
true);
1852 ParseResult parsePostFixFieldId(Value &result);
1853 ParseResult parsePostFixIntSubscript(Value &result);
1854 ParseResult parsePostFixDynamicSubscript(Value &result);
1855 ParseResult parseIntegerLiteralExp(Value &result);
1856 ParseResult parseListExp(Value &result);
1857 ParseResult parseListConcatExp(Value &result);
1859 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1860 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1862 auto loc = getToken().getLoc();
1863 locationProcessor.setLoc(loc);
1866 auto vals = std::array<Value, M>();
1867 auto ints = std::array<int64_t, N>();
1871 for (
size_t i = 0; i < M; ++i) {
1873 if (parseToken(FIRToken::comma,
"expected ','"))
1875 if (parseExp(vals[i],
"expected expression in primitive operand"))
1881 for (
size_t i = 0; i < N; ++i) {
1883 if (parseToken(FIRToken::comma,
"expected ','"))
1885 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
1890 if (parseToken(FIRToken::r_paren,
"expected ')'"))
1894 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
1898 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
1899 translateLocation(loc));
1904 auto op = builder.create<T>(type, vals[Ms]..., ints[Ns]...);
1905 result = op.getResult();
1909 template <
typename T,
unsigned M,
unsigned N>
1910 ParseResult parsePrimExp(Value &result) {
1911 auto ms = std::make_index_sequence<M>();
1912 auto ns = std::make_index_sequence<N>();
1913 return parsePrim<T, M, N>(ms, ns, result);
1916 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
1919 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
1920 SymbolRefAttr layerSym);
1921 ParseResult parseAttach();
1922 ParseResult parseMemPort(MemDirAttr direction);
1927 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
1928 ArrayRef<Value> specOperands,
1929 StringAttr &formatStringResult,
1930 SmallVectorImpl<Value> &operands);
1931 ParseResult parsePrintf();
1932 ParseResult parseFPrintf();
1933 ParseResult parseFFlush();
1934 ParseResult parseSkip();
1935 ParseResult parseStop();
1936 ParseResult parseAssert();
1937 ParseResult parseAssume();
1938 ParseResult parseCover();
1939 ParseResult parseWhen(
unsigned whenIndent);
1940 ParseResult parseMatch(
unsigned matchIndent);
1941 ParseResult parseRefDefine();
1942 ParseResult parseRefForce();
1943 ParseResult parseRefForceInitial();
1944 ParseResult parseRefRelease();
1945 ParseResult parseRefReleaseInitial();
1946 ParseResult parseRefRead(Value &result);
1947 ParseResult parseProbe(Value &result);
1948 ParseResult parsePropAssign();
1949 ParseResult parseRWProbe(Value &result);
1950 ParseResult parseLeadingExpStmt(Value lhs);
1951 ParseResult parseConnect();
1952 ParseResult parseInvalidate();
1953 ParseResult parseLayerBlockOrGroup(
unsigned indent);
1956 ParseResult parseInstance();
1957 ParseResult parseInstanceChoice();
1958 ParseResult parseObject();
1959 ParseResult parseCombMem();
1960 ParseResult parseSeqMem();
1961 ParseResult parseMem(
unsigned memIndent);
1962 ParseResult parseNode();
1963 ParseResult parseWire();
1964 ParseResult parseRegister(
unsigned regIndent);
1965 ParseResult parseRegisterWithReset();
1966 ParseResult parseContract(
unsigned blockIndent);
1969 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
1972 ImplicitLocOpBuilder builder;
1973 LazyLocationListener locationProcessor;
1976 FIRModuleContext &moduleContext;
1979 InnerSymFixups &innerSymFixups;
1983 SymbolRefAttr layerSym;
1985 const SymbolTable &circuitSymTbl;
1992void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
1993 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2000 auto props = tpe.getRecursiveTypeProperties();
2001 if (props.isPassive && !props.containsAnalog) {
2002 if (flow == Flow::Source)
2004 emitConnect(builder, val, builder.create<InvalidValueOp>(tpe));
2015 TypeSwitch<FIRRTLType>(tpe)
2016 .Case<BundleType>([&](
auto tpe) {
2017 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2018 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2020 OpBuilder::InsertionGuard guard(builder);
2021 builder.setInsertionPointAfterValue(val);
2022 subfield = builder.create<SubfieldOp>(val, i);
2024 emitInvalidate(subfield,
2025 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2028 .Case<FVectorType>([&](
auto tpe) {
2029 auto tpex = tpe.getElementType();
2030 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2031 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2033 OpBuilder::InsertionGuard guard(builder);
2034 builder.setInsertionPointAfterValue(val);
2035 subindex = builder.create<SubindexOp>(tpex, val, i);
2037 emitInvalidate(subindex, flow);
2065ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2066 bool isLeadingStmt) {
2067 auto token = getToken();
2068 auto kind = token.getKind();
2070 case FIRToken::lp_integer_add:
2071 case FIRToken::lp_integer_mul:
2072 case FIRToken::lp_integer_shr:
2073 case FIRToken::lp_integer_shl:
2074 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2083#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES) \
2084 case FIRToken::lp_##SPELLING: \
2085 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2088#include "FIRTokenKinds.def"
2090 case FIRToken::l_brace_bar:
2092 return emitError(
"unexpected enumeration as start of statement");
2093 if (parseEnumExp(result))
2096 case FIRToken::lp_read:
2098 return emitError(
"unexpected read() as start of statement");
2099 if (parseRefRead(result))
2102 case FIRToken::lp_probe:
2104 return emitError(
"unexpected probe() as start of statement");
2105 if (parseProbe(result))
2108 case FIRToken::lp_rwprobe:
2110 return emitError(
"unexpected rwprobe() as start of statement");
2111 if (parseRWProbe(result))
2115 case FIRToken::kw_UInt:
2116 case FIRToken::kw_SInt:
2117 if (parseIntegerLiteralExp(result))
2120 case FIRToken::kw_String: {
2121 if (requireFeature({3, 1, 0},
"Strings"))
2123 locationProcessor.setLoc(getToken().
getLoc());
2124 consumeToken(FIRToken::kw_String);
2126 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2127 parseGetSpelling(spelling) ||
2128 parseToken(FIRToken::string,
2129 "expected string literal in String expression") ||
2130 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2133 result = moduleContext.getCachedConstant<StringConstantOp>(
2134 builder, attr, builder.getType<StringType>(), attr);
2137 case FIRToken::kw_Integer: {
2138 if (requireFeature({3, 1, 0},
"Integers"))
2140 locationProcessor.setLoc(getToken().
getLoc());
2141 consumeToken(FIRToken::kw_Integer);
2143 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2144 parseIntLit(value,
"expected integer literal in Integer expression") ||
2145 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2147 APSInt apint(value,
false);
2148 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2149 builder, IntegerAttr::get(getContext(), apint),
2150 builder.getType<FIntegerType>(), apint);
2153 case FIRToken::kw_Bool: {
2156 locationProcessor.setLoc(getToken().
getLoc());
2157 consumeToken(FIRToken::kw_Bool);
2158 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2161 if (consumeIf(FIRToken::kw_true))
2163 else if (consumeIf(FIRToken::kw_false))
2166 return emitError(
"expected true or false in Bool expression");
2167 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2169 auto attr = builder.getBoolAttr(value);
2170 result = moduleContext.getCachedConstant<BoolConstantOp>(
2171 builder, attr, builder.getType<BoolType>(), value);
2174 case FIRToken::kw_Double: {
2177 locationProcessor.setLoc(getToken().
getLoc());
2178 consumeToken(FIRToken::kw_Double);
2179 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2181 auto spelling = getTokenSpelling();
2182 if (parseToken(FIRToken::floatingpoint,
2183 "expected floating point in Double expression") ||
2184 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2189 if (!llvm::to_float(spelling, d))
2190 return emitError(
"invalid double");
2191 auto attr = builder.getF64FloatAttr(d);
2192 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2193 builder, attr, builder.getType<DoubleType>(), attr);
2196 case FIRToken::kw_List: {
2197 if (requireFeature({4, 0, 0},
"Lists"))
2200 return emitError(
"unexpected List<>() as start of statement");
2201 if (parseListExp(result))
2206 case FIRToken::lp_list_concat: {
2208 return emitError(
"unexpected list_create() as start of statement");
2209 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2214 case FIRToken::lp_path:
2216 return emitError(
"unexpected path() as start of statement");
2221 case FIRToken::lp_intrinsic:
2222 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2223 parseIntrinsicExp(result))
2229 case FIRToken::identifier:
2230 case FIRToken::literal_identifier:
2233 auto loc = getToken().getLoc();
2235 if (parseId(name, message) ||
2236 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2240 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2243 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2248 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2249 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2250 parseOptionalInfo())
2253 locationProcessor.setLoc(loc);
2255 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2257 moduleContext.getUnbundledEntry(unbundledId);
2258 for (
auto elt : ubEntry)
2259 emitInvalidate(elt.second);
2267 StringRef fieldName;
2268 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2269 parseFieldId(fieldName,
"expected field name") ||
2270 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2278 case FIRToken::lp_shr:
2281 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2282 result = builder.create<PadPrimOp>(result, 1);
2288 return parseOptionalExpPostscript(result);
2298ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2299 bool allowDynamic) {
2304 if (consumeIf(FIRToken::period)) {
2305 if (parsePostFixFieldId(result))
2312 if (consumeIf(FIRToken::l_square)) {
2313 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2314 if (parsePostFixIntSubscript(result))
2319 return emitError(
"subaccess not allowed here");
2320 if (parsePostFixDynamicSubscript(result))
2330template <
typename subop>
2332FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2334 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2340 auto baseType = cast<FIRRTLType>(base.getType());
2341 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2344 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2350 locationProcessor.setLoc(loc);
2351 OpBuilder::InsertionGuard guard(builder);
2352 builder.setInsertionPointAfterValue(base);
2353 auto op = builder.create<subop>(resultType, base, indexNo);
2356 return value = op.getResult();
2363ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2364 auto loc = getToken().getLoc();
2365 SmallVector<StringRef, 3> fields;
2366 if (parseFieldIdSeq(fields,
"expected field name"))
2368 for (
auto fieldName : fields) {
2369 std::optional<unsigned> indexV;
2370 auto type = result.getType();
2371 if (
auto refTy = type_dyn_cast<RefType>(type))
2372 type = refTy.getType();
2373 if (
auto bundle = type_dyn_cast<BundleType>(type))
2374 indexV = bundle.getElementIndex(fieldName);
2375 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2376 indexV = bundle.getElementIndex(fieldName);
2377 else if (
auto klass = type_dyn_cast<ClassType>(type))
2378 indexV = klass.getElementIndex(fieldName);
2380 return emitError(loc,
"subfield requires bundle or object operand ");
2382 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2383 << result.getType();
2384 auto indexNo = *indexV;
2386 FailureOr<Value> subResult;
2387 if (type_isa<RefType>(result.getType()))
2388 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2389 else if (type_isa<ClassType>(type))
2390 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2391 else if (type_isa<BundleType>(type))
2392 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2394 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2396 if (failed(subResult))
2398 result = *subResult;
2407ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2408 auto loc = getToken().getLoc();
2410 if (parseIntLit(indexNo,
"expected index") ||
2411 parseToken(FIRToken::r_square,
"expected ']'"))
2415 return emitError(loc,
"invalid index specifier"), failure();
2417 FailureOr<Value> subResult;
2418 if (type_isa<RefType>(result.getType()))
2419 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2420 else if (type_isa<FVectorType>(result.getType()))
2421 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2423 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2425 if (failed(subResult))
2427 result = *subResult;
2435ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2436 auto loc = getToken().getLoc();
2438 if (parseExp(index,
"expected subscript index expression") ||
2439 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2443 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2445 return emitError(
"expected base type for index expression");
2446 indexType = indexType.getPassiveType();
2447 locationProcessor.setLoc(loc);
2452 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2455 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2456 translateLocation(loc));
2461 auto op = builder.create<SubaccessOp>(resultType, result, index);
2462 result = op.getResult();
2468ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2469 bool isSigned = getToken().is(FIRToken::kw_SInt);
2470 auto loc = getToken().getLoc();
2476 if (parseOptionalWidth(width) ||
2477 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2478 parseIntLit(value,
"expected integer value") ||
2479 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2484 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2486 IntegerType::SignednessSemantics signedness =
2487 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2489 if (!value.isZero())
2490 return emitError(loc,
"zero bit constant must be zero");
2491 value = value.trunc(0);
2492 }
else if (width != -1) {
2494 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2496 return emitError(loc,
"initializer too wide for declared width");
2497 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2501 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2502 auto attr = builder.getIntegerAttr(attrType, value);
2505 auto &entry = moduleContext.constantCache[{attr, type}];
2512 locationProcessor.setLoc(loc);
2513 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2518ParseResult FIRStmtParser::parseListExp(Value &result) {
2519 auto loc = getToken().getLoc();
2521 if (parseListType(type))
2523 auto listType = type_cast<ListType>(type);
2526 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2529 SmallVector<Value, 3> operands;
2530 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2532 locationProcessor.setLoc(loc);
2533 if (parseExp(operand,
"expected expression in List expression"))
2537 if (!isa<AnyRefType>(elementType) ||
2538 !isa<ClassType>(operand.getType()))
2539 return emitError(loc,
"unexpected expression of type ")
2540 << operand.getType() <<
" in List expression of type "
2542 operand = builder.create<ObjectAnyRefCastOp>(operand);
2545 operands.push_back(operand);
2550 locationProcessor.setLoc(loc);
2551 result = builder.create<ListCreateOp>(listType, operands);
2556ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2557 consumeToken(FIRToken::lp_list_concat);
2559 auto loc = getToken().getLoc();
2561 SmallVector<Value, 3> operands;
2562 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2564 locationProcessor.setLoc(loc);
2565 if (parseExp(operand,
"expected expression in List concat expression"))
2568 if (!type_isa<ListType>(operand.getType()))
2569 return emitError(loc,
"unexpected expression of type ")
2570 << operand.getType() <<
" in List concat expression";
2573 type = type_cast<ListType>(operand.getType());
2575 if (operand.getType() != type)
2576 return emitError(loc,
"unexpected expression of type ")
2577 << operand.getType() <<
" in List concat expression of type "
2580 operands.push_back(operand);
2585 if (operands.empty())
2586 return emitError(loc,
"need at least one List to concatenate");
2588 locationProcessor.setLoc(loc);
2589 result = builder.create<ListConcatOp>(type, operands);
2610std::optional<ParseResult>
2611FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2612 switch (getToken().getKind()) {
2615 return std::nullopt;
2617 case FIRToken::period:
2618 case FIRToken::l_square:
2619 case FIRToken::kw_is:
2620 case FIRToken::less_equal:
2626 auto loc = keyword.
getLoc();
2628 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2629 return ParseResult(failure());
2635 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2638 if (!consumeIf(FIRToken::period))
2639 return ParseResult(failure());
2641 StringRef fieldName;
2642 if (parseFieldId(fieldName,
"expected field name") ||
2643 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2644 return ParseResult(failure());
2648 if (parseOptionalExpPostscript(lhs))
2649 return ParseResult(failure());
2651 return parseLeadingExpStmt(lhs);
2657ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2660 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2663 auto subIndent = getIndentation();
2664 if (!subIndent.has_value())
2665 return emitError(
"expected statement to be on its own line"), failure();
2667 if (*subIndent <= indent)
2671 if (parseSimpleStmt(*subIndent))
2676ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2677 locationProcessor.startStatement();
2678 auto result = parseSimpleStmtImpl(stmtIndent);
2679 locationProcessor.endStatement(*
this);
2701ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2702 auto kind = getToken().getKind();
2705 case FIRToken::kw_invalidate:
2706 case FIRToken::kw_connect:
2707 case FIRToken::kw_regreset:
2711 kind = FIRToken::identifier;
2718 case FIRToken::kw_attach:
2719 return parseAttach();
2720 case FIRToken::kw_infer:
2721 return parseMemPort(MemDirAttr::Infer);
2722 case FIRToken::kw_read:
2723 return parseMemPort(MemDirAttr::Read);
2724 case FIRToken::kw_write:
2725 return parseMemPort(MemDirAttr::Write);
2726 case FIRToken::kw_rdwr:
2727 return parseMemPort(MemDirAttr::ReadWrite);
2728 case FIRToken::kw_connect:
2729 return parseConnect();
2730 case FIRToken::kw_propassign:
2731 if (requireFeature({3, 1, 0},
"properties"))
2733 return parsePropAssign();
2734 case FIRToken::kw_invalidate:
2735 return parseInvalidate();
2736 case FIRToken::lp_printf:
2737 return parsePrintf();
2738 case FIRToken::lp_fprintf:
2739 return parseFPrintf();
2740 case FIRToken::lp_fflush:
2741 return parseFFlush();
2742 case FIRToken::kw_skip:
2744 case FIRToken::lp_stop:
2746 case FIRToken::lp_assert:
2747 return parseAssert();
2748 case FIRToken::lp_assume:
2749 return parseAssume();
2750 case FIRToken::lp_cover:
2751 return parseCover();
2752 case FIRToken::kw_when:
2753 return parseWhen(stmtIndent);
2754 case FIRToken::kw_match:
2755 return parseMatch(stmtIndent);
2756 case FIRToken::kw_define:
2757 return parseRefDefine();
2758 case FIRToken::lp_force:
2759 return parseRefForce();
2760 case FIRToken::lp_force_initial:
2761 return parseRefForceInitial();
2762 case FIRToken::lp_release:
2763 return parseRefRelease();
2764 case FIRToken::lp_release_initial:
2765 return parseRefReleaseInitial();
2766 case FIRToken::kw_group:
2767 if (requireFeature({3, 2, 0},
"optional groups") ||
2768 removedFeature({3, 3, 0},
"optional groups"))
2770 return parseLayerBlockOrGroup(stmtIndent);
2771 case FIRToken::kw_layerblock:
2772 if (requireFeature({3, 3, 0},
"layers"))
2774 return parseLayerBlockOrGroup(stmtIndent);
2775 case FIRToken::lp_intrinsic:
2776 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2778 return parseIntrinsicStmt();
2782 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2789 return parseLeadingExpStmt(lhs);
2793 case FIRToken::kw_inst:
2794 return parseInstance();
2795 case FIRToken::kw_instchoice:
2796 return parseInstanceChoice();
2797 case FIRToken::kw_object:
2798 return parseObject();
2799 case FIRToken::kw_cmem:
2800 return parseCombMem();
2801 case FIRToken::kw_smem:
2802 return parseSeqMem();
2803 case FIRToken::kw_mem:
2804 return parseMem(stmtIndent);
2805 case FIRToken::kw_node:
2807 case FIRToken::kw_wire:
2809 case FIRToken::kw_reg:
2810 return parseRegister(stmtIndent);
2811 case FIRToken::kw_regreset:
2812 return parseRegisterWithReset();
2813 case FIRToken::kw_contract:
2814 return parseContract(stmtIndent);
2818ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2820 SymbolRefAttr layerSym) {
2822 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2823 moduleContext, &blockToInsertInto);
2828 UnbundledValueRestorer x(moduleContext.unbundledValues);
2832 auto subParser = std::make_unique<FIRStmtParser>(
2833 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
2837 auto stmtIndent = getIndentation();
2840 if (!stmtIndent.has_value())
2841 return subParser->parseSimpleStmt(indent);
2843 if (*stmtIndent <= indent)
2844 return emitError(
"statement must be indented more than previous statement"),
2848 return subParser->parseSimpleStmtBlock(indent);
2852ParseResult FIRStmtParser::parseAttach() {
2853 auto startTok = consumeToken(FIRToken::kw_attach);
2856 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2859 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
2862 SmallVector<Value, 4> operands;
2863 operands.push_back({});
2864 if (parseExp(operands.back(),
"expected operand in attach"))
2867 while (consumeIf(FIRToken::comma)) {
2868 operands.push_back({});
2869 if (parseExp(operands.back(),
"expected operand in attach"))
2872 if (parseToken(FIRToken::r_paren,
"expected close paren"))
2875 if (parseOptionalInfo())
2878 locationProcessor.setLoc(startTok.getLoc());
2879 builder.create<AttachOp>(operands);
2886ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2887 auto startTok = consumeToken();
2888 auto startLoc = startTok.getLoc();
2892 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2898 Value memory, indexExp, clock;
2899 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
2900 parseId(
id,
"expected result name") ||
2901 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
2902 parseId(memName,
"expected memory name") ||
2903 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2904 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2905 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
2906 parseExp(indexExp,
"expected index expression") ||
2907 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
2908 parseToken(FIRToken::comma,
"expected ','") ||
2909 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
2912 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2914 return emitError(startLoc,
2915 "memory port should have behavioral memory type");
2916 auto resultType = memVType.getElementType();
2918 ArrayAttr annotations = getConstants().emptyArrayAttr;
2919 locationProcessor.setLoc(startLoc);
2922 Value memoryPort, memoryData;
2924 OpBuilder::InsertionGuard guard(builder);
2925 builder.setInsertionPointAfterValue(memory);
2926 auto memoryPortOp = builder.create<MemoryPortOp>(
2927 resultType, CMemoryPortType::get(getContext()), memory, direction, id,
2929 memoryData = memoryPortOp.getResult(0);
2930 memoryPort = memoryPortOp.getResult(1);
2934 builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2936 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
2942ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
2943 StringRef formatString,
2944 ArrayRef<Value> specOperands,
2945 StringAttr &formatStringResult,
2946 SmallVectorImpl<Value> &operands) {
2950 SmallVector<Attribute, 4> specialSubstitutions;
2951 SmallString<64> validatedFormatString;
2953 validatedFormatString = formatString;
2954 operands.append(specOperands.begin(), specOperands.end());
2956 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
2957 auto c = formatString[i];
2962 validatedFormatString.push_back(c);
2965 SmallString<6> width;
2966 c = formatString[++i];
2969 c = formatString[++i];
2975 if (!width.empty()) {
2976 emitError(formatStringLoc) <<
"ASCII character format specifiers "
2977 "('%c') may not specify a width";
2985 validatedFormatString.append(width);
2986 operands.push_back(specOperands[opIdx++]);
2989 if (!width.empty()) {
2990 emitError(formatStringLoc)
2991 <<
"literal percents ('%%') may not specify a width";
2997 emitError(formatStringLoc)
2998 <<
"unknown printf substitution '%" << width << c <<
"'";
3001 validatedFormatString.push_back(c);
3009 if (formatString[i + 1] !=
'{') {
3010 validatedFormatString.push_back(c);
3016 while (formatString[i] !=
'}')
3018 if (formatString[i] !=
'}') {
3019 llvm::errs() <<
"expected '}' to terminate special substitution";
3023 auto specialString = formatString.slice(start, i);
3024 if (specialString ==
"SimulationTime") {
3025 operands.push_back(builder.create<TimeOp>());
3026 }
else if (specialString ==
"HierarchicalModuleName") {
3027 operands.push_back(builder.create<HierarchicalModuleNameOp>());
3029 emitError(formatStringLoc)
3030 <<
"unknown printf substitution '" << specialString
3031 <<
"' (did you misspell it?)";
3035 validatedFormatString.append(
"{{}}");
3040 validatedFormatString.push_back(c);
3045 formatStringResult =
3051ParseResult FIRStmtParser::parsePrintf() {
3052 auto startTok = consumeToken(FIRToken::lp_printf);
3054 Value clock, condition;
3055 StringRef formatString;
3056 if (parseExp(clock,
"expected clock expression in printf") ||
3057 parseToken(FIRToken::comma,
"expected ','") ||
3058 parseExp(condition,
"expected condition in printf") ||
3059 parseToken(FIRToken::comma,
"expected ','"))
3062 auto formatStringLoc = getToken().getLoc();
3063 if (parseGetSpelling(formatString) ||
3064 parseToken(FIRToken::string,
"expected format string in printf"))
3067 SmallVector<Value, 4> specOperands;
3068 while (consumeIf(FIRToken::comma)) {
3069 specOperands.push_back({});
3070 if (parseExp(specOperands.back(),
"expected operand in printf"))
3075 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3076 parseOptionalName(name) || parseOptionalInfo())
3079 locationProcessor.setLoc(startTok.getLoc());
3081 StringAttr formatStrUnescaped;
3082 SmallVector<Value> operands;
3083 if (parseFormatString(formatStringLoc, formatString, specOperands,
3084 formatStrUnescaped, operands))
3087 builder.create<PrintFOp>(clock, condition, formatStrUnescaped, operands,
3093ParseResult FIRStmtParser::parseFPrintf() {
3096 auto startTok = consumeToken(FIRToken::lp_fprintf);
3098 Value clock, condition;
3099 StringRef outputFile, formatString;
3100 if (parseExp(clock,
"expected clock expression in fprintf") ||
3101 parseToken(FIRToken::comma,
"expected ','") ||
3102 parseExp(condition,
"expected condition in fprintf") ||
3103 parseToken(FIRToken::comma,
"expected ','"))
3106 auto outputFileLoc = getToken().getLoc();
3107 if (parseGetSpelling(outputFile) ||
3108 parseToken(FIRToken::string,
"expected output file in fprintf"))
3111 SmallVector<Value, 4> outputFileSpecOperands;
3112 while (consumeIf(FIRToken::comma)) {
3114 if (getToken().getKind() == FIRToken::string)
3116 outputFileSpecOperands.push_back({});
3117 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3121 auto formatStringLoc = getToken().getLoc();
3122 if (parseGetSpelling(formatString) ||
3123 parseToken(FIRToken::string,
"expected format string in printf"))
3126 SmallVector<Value, 4> specOperands;
3127 while (consumeIf(FIRToken::comma)) {
3128 specOperands.push_back({});
3129 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3134 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3135 parseOptionalName(name) || parseOptionalInfo())
3138 locationProcessor.setLoc(startTok.getLoc());
3140 StringAttr outputFileNameStrUnescaped;
3141 SmallVector<Value> outputFileOperands;
3142 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3143 outputFileNameStrUnescaped, outputFileOperands))
3146 StringAttr formatStrUnescaped;
3147 SmallVector<Value> operands;
3148 if (parseFormatString(formatStringLoc, formatString, specOperands,
3149 formatStrUnescaped, operands))
3152 builder.create<FPrintFOp>(clock, condition, outputFileNameStrUnescaped,
3153 outputFileOperands, formatStrUnescaped, operands,
3159ParseResult FIRStmtParser::parseFFlush() {
3163 auto startTok = consumeToken(FIRToken::lp_fflush);
3165 Value clock, condition;
3166 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3167 parseToken(FIRToken::comma,
"expected ','") ||
3168 parseExp(condition,
"expected condition in 'fflush'"))
3171 locationProcessor.setLoc(startTok.getLoc());
3172 StringAttr outputFileNameStrUnescaped;
3173 SmallVector<Value> outputFileOperands;
3175 if (consumeIf(FIRToken::comma)) {
3176 SmallVector<Value, 4> outputFileSpecOperands;
3177 auto outputFileLoc = getToken().getLoc();
3178 StringRef outputFile;
3179 if (parseGetSpelling(outputFile) ||
3180 parseToken(FIRToken::string,
"expected output file in fflush"))
3183 while (consumeIf(FIRToken::comma)) {
3184 outputFileSpecOperands.push_back({});
3185 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3189 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3190 outputFileNameStrUnescaped, outputFileOperands))
3194 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3195 parseOptionalInfo())
3198 builder.create<FFlushOp>(clock, condition, outputFileNameStrUnescaped,
3199 outputFileOperands);
3204ParseResult FIRStmtParser::parseSkip() {
3205 auto startTok = consumeToken(FIRToken::kw_skip);
3209 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3212 if (parseOptionalInfo())
3215 locationProcessor.setLoc(startTok.getLoc());
3216 builder.create<SkipOp>();
3221ParseResult FIRStmtParser::parseStop() {
3222 auto startTok = consumeToken(FIRToken::lp_stop);
3224 Value clock, condition;
3227 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3228 parseToken(FIRToken::comma,
"expected ','") ||
3229 parseExp(condition,
"expected condition in 'stop'") ||
3230 parseToken(FIRToken::comma,
"expected ','") ||
3231 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3232 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3233 parseOptionalName(name) || parseOptionalInfo())
3236 locationProcessor.setLoc(startTok.getLoc());
3237 builder.create<StopOp>(clock, condition, builder.getI32IntegerAttr(exitCode),
3243ParseResult FIRStmtParser::parseAssert() {
3244 auto startTok = consumeToken(FIRToken::lp_assert);
3246 Value clock, predicate, enable;
3247 StringRef formatString;
3249 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3250 parseToken(FIRToken::comma,
"expected ','") ||
3251 parseExp(predicate,
"expected predicate in 'assert'") ||
3252 parseToken(FIRToken::comma,
"expected ','") ||
3253 parseExp(enable,
"expected enable in 'assert'") ||
3254 parseToken(FIRToken::comma,
"expected ','") ||
3255 parseGetSpelling(formatString) ||
3256 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3259 SmallVector<Value, 4> operands;
3260 while (!consumeIf(FIRToken::r_paren)) {
3261 operands.push_back({});
3262 if (parseToken(FIRToken::comma,
"expected ','") ||
3263 parseExp(operands.back(),
"expected operand in 'assert'"))
3267 if (parseOptionalName(name) || parseOptionalInfo())
3270 locationProcessor.setLoc(startTok.getLoc());
3272 builder.create<AssertOp>(clock, predicate, enable, formatStrUnescaped,
3273 operands, name.getValue());
3278ParseResult FIRStmtParser::parseAssume() {
3279 auto startTok = consumeToken(FIRToken::lp_assume);
3281 Value clock, predicate, enable;
3282 StringRef formatString;
3284 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3285 parseToken(FIRToken::comma,
"expected ','") ||
3286 parseExp(predicate,
"expected predicate in 'assume'") ||
3287 parseToken(FIRToken::comma,
"expected ','") ||
3288 parseExp(enable,
"expected enable in 'assume'") ||
3289 parseToken(FIRToken::comma,
"expected ','") ||
3290 parseGetSpelling(formatString) ||
3291 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3294 SmallVector<Value, 4> operands;
3295 while (!consumeIf(FIRToken::r_paren)) {
3296 operands.push_back({});
3297 if (parseToken(FIRToken::comma,
"expected ','") ||
3298 parseExp(operands.back(),
"expected operand in 'assume'"))
3302 if (parseOptionalName(name) || parseOptionalInfo())
3305 locationProcessor.setLoc(startTok.getLoc());
3307 builder.create<AssumeOp>(clock, predicate, enable, formatStrUnescaped,
3308 operands, name.getValue());
3313ParseResult FIRStmtParser::parseCover() {
3314 auto startTok = consumeToken(FIRToken::lp_cover);
3316 Value clock, predicate, enable;
3319 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3320 parseToken(FIRToken::comma,
"expected ','") ||
3321 parseExp(predicate,
"expected predicate in 'cover'") ||
3322 parseToken(FIRToken::comma,
"expected ','") ||
3323 parseExp(enable,
"expected enable in 'cover'") ||
3324 parseToken(FIRToken::comma,
"expected ','") ||
3325 parseGetSpelling(message) ||
3326 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3327 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3328 parseOptionalName(name) || parseOptionalInfo())
3331 locationProcessor.setLoc(startTok.getLoc());
3333 builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
3334 ValueRange{}, name.getValue());
3340ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3341 auto startTok = consumeToken(FIRToken::kw_when);
3345 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3349 if (parseExp(condition,
"expected condition in 'when'") ||
3350 parseToken(FIRToken::colon,
"expected ':' in when") ||
3351 parseOptionalInfo())
3354 locationProcessor.setLoc(startTok.getLoc());
3356 auto whenStmt = builder.create<WhenOp>(condition,
false);
3359 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3363 if (getToken().isNot(FIRToken::kw_else))
3368 auto elseIndent = getIndentation();
3369 if (elseIndent && *elseIndent < whenIndent)
3372 consumeToken(FIRToken::kw_else);
3375 whenStmt.createElseRegion();
3381 if (getToken().is(FIRToken::kw_when)) {
3383 auto subParser = std::make_unique<FIRStmtParser>(
3384 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3387 return subParser->parseSimpleStmt(whenIndent);
3391 LocationAttr elseLoc;
3392 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3393 parseOptionalInfoLocator(elseLoc) ||
3394 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3403ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3404 auto startLoc = getToken().getLoc();
3405 locationProcessor.setLoc(startLoc);
3407 if (parseEnumType(type))
3411 auto enumType = type_dyn_cast<FEnumType>(type);
3413 return emitError(startLoc,
3414 "expected enumeration type in enumeration expression");
3417 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3418 parseId(tag,
"expected enumeration tag"))
3422 if (consumeIf(FIRToken::r_paren)) {
3425 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3426 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3427 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3428 input = builder.create<ConstantOp>(type, attr);
3431 if (parseToken(FIRToken::comma,
"expected ','") ||
3432 parseExp(input,
"expected expression in enumeration value") ||
3433 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3437 value = builder.create<FEnumCreateOp>(enumType, tag, input);
3445ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3446 auto startTok = consumeToken(FIRToken::kw_match);
3448 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3452 if (parseExp(input,
"expected expression in 'match'") ||
3453 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3454 parseOptionalInfo())
3457 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3459 return mlir::emitError(
3461 "expected enumeration type for 'match' statement, but got ")
3464 locationProcessor.setLoc(startTok.getLoc());
3466 SmallVector<Attribute> tags;
3467 SmallVector<std::unique_ptr<Region>> regions;
3469 auto tagLoc = getToken().getLoc();
3472 auto caseIndent = getIndentation();
3473 if (!caseIndent || *caseIndent <= matchIndent)
3477 StringRef tagSpelling;
3478 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3480 auto tagIndex = enumType.getElementIndex(tagSpelling);
3482 return emitError(tagLoc,
"tag ")
3483 << tagSpelling <<
" not a member of enumeration " << enumType;
3484 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3485 tags.push_back(tag);
3488 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3491 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3496 UnbundledValueRestorer x(moduleContext.unbundledValues);
3499 if (consumeIf(FIRToken::l_paren)) {
3500 StringAttr identifier;
3501 if (parseId(identifier,
"expected identifier for 'case' binding"))
3505 auto dataType = enumType.getElementType(*tagIndex);
3506 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3508 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3512 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3516 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3517 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3520 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3524 auto subParser = std::make_unique<FIRStmtParser>(
3525 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3527 if (subParser->parseSimpleStmtBlock(*caseIndent))
3531 builder.create<MatchOp>(input, ArrayAttr::get(getContext(), tags), regions);
3537ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3538 auto token = getToken().getKind();
3539 if (token == FIRToken::lp_probe)
3540 return parseProbe(result);
3541 if (token == FIRToken::lp_rwprobe)
3542 return parseRWProbe(result);
3547 return parseStaticRefExp(result, message);
3554ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3555 const Twine &message) {
3556 auto parseIdOrInstance = [&]() -> ParseResult {
3558 auto loc = getToken().getLoc();
3560 if (parseId(
id, message) ||
3561 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3565 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3568 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3571 StringRef fieldName;
3573 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3574 parseFieldId(fieldName,
"expected field name") ||
3575 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3577 return failure(parseIdOrInstance() ||
3578 parseOptionalExpPostscript(result,
false));
3589ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3591 const Twine &message) {
3592 auto loc = getToken().getLoc();
3596 if (parseId(
id, message) ||
3597 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3609 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3611 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3613 StringRef fieldName;
3614 auto loc = getToken().getLoc();
3615 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3616 parseFieldId(fieldName,
"expected field name"))
3621 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3622 for (
auto &elt : ubEntry) {
3623 if (elt.first == fieldAttr) {
3626 auto &instResult = elt.second;
3629 auto *defining = instResult.getDefiningOp();
3631 if (isa<WireOp>(defining)) {
3632 result = instResult;
3637 auto type = instResult.getType();
3641 bool forceable =
static_cast<bool>(
3644 return emitError(loc,
"unable to force instance result of type ")
3648 auto annotations = getConstants().emptyArrayAttr;
3649 StringAttr sym = {};
3650 SmallString<64> name;
3651 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3652 locationProcessor.setLoc(loc);
3653 OpBuilder::InsertionGuard guard(builder);
3654 builder.setInsertionPoint(defining);
3655 auto bounce = builder.create<WireOp>(
3656 type, name, NameKindEnum::InterestingName, annotations, sym);
3657 auto bounceVal = bounce.getData();
3660 instResult.replaceAllUsesWith(bounceVal);
3663 builder.setInsertionPointAfter(defining);
3664 if (
foldFlow(instResult) == Flow::Source)
3671 result = instResult = bounce.getDataRaw();
3677 emitError(loc,
"use of invalid field name '")
3678 << fieldName <<
"' on bundle value";
3683 result = cast<Value>(symtabEntry);
3687 assert(isa<BlockArgument>(result) ||
3688 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3694 type = result.getType();
3696 if (consumeIf(FIRToken::period)) {
3697 SmallVector<StringRef, 3> fields;
3698 if (parseFieldIdSeq(fields,
"expected field name"))
3700 for (
auto fieldName : fields) {
3701 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3702 if (
auto index = bundle.getElementIndex(fieldName)) {
3703 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3704 type = bundle.getElementTypePreservingConst(*index);
3707 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3708 if (
auto index = bundle.getElementIndex(fieldName)) {
3709 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3710 type = bundle.getElementTypePreservingConst(*index);
3714 return emitError(loc,
"subfield requires bundle operand")
3715 <<
"got " << type <<
"\n";
3717 return emitError(loc,
3718 "unknown field '" + fieldName +
"' in bundle type ")
3723 if (consumeIf(FIRToken::l_square)) {
3724 auto loc = getToken().
getLoc();
3726 if (parseIntLit(index,
"expected index") ||
3727 parseToken(FIRToken::r_square,
"expected ']'"))
3731 return emitError(loc,
"invalid index specifier");
3733 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3734 if ((
unsigned)index < vector.getNumElements()) {
3735 refResult = refResult.
getSubField(vector.getFieldID(index));
3736 type = vector.getElementTypePreservingConst();
3739 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3740 if ((
unsigned)index < vector.getNumElements()) {
3741 refResult = refResult.
getSubField(vector.getFieldID(index));
3742 type = vector.getElementTypePreservingConst();
3746 return emitError(loc,
"subindex requires vector operand");
3748 return emitError(loc,
"out of range index '")
3749 << index <<
"' for vector type " << type;
3757ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3758 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3759 StringRef intrinsic;
3760 ArrayAttr parameters;
3763 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3764 parseOptionalParams(parameters))
3767 if (consumeIf(FIRToken::colon)) {
3768 if (
parseType(type,
"expected intrinsic return type"))
3770 }
else if (!isStatement)
3771 return emitError(
"expected ':' in intrinsic expression");
3773 SmallVector<Value> operands;
3774 auto loc = startTok.getLoc();
3775 if (consumeIf(FIRToken::comma)) {
3776 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3778 if (parseExp(operand,
"expected operand in intrinsic"))
3780 operands.push_back(operand);
3781 locationProcessor.setLoc(loc);
3786 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3791 if (parseOptionalInfo())
3794 locationProcessor.setLoc(loc);
3796 auto op = builder.create<GenericIntrinsicOp>(
3797 type, builder.getStringAttr(intrinsic), operands, parameters);
3799 result = op.getResult();
3804ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3805 if (!consumeIf(FIRToken::less))
3808 SmallVector<Attribute, 8> parameters;
3809 SmallPtrSet<StringAttr, 8> seen;
3810 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3814 if (parseParameter(name, value, loc))
3816 auto typedValue = dyn_cast<TypedAttr>(value);
3818 return emitError(loc)
3819 <<
"invalid value for parameter '" << name.getValue() <<
"'";
3820 if (!seen.insert(name).second)
3821 return emitError(loc,
"redefinition of parameter '" +
3822 name.getValue() +
"'");
3823 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3828 resultParameters = ArrayAttr::get(getContext(), parameters);
3834ParseResult FIRStmtParser::parsePathExp(Value &result) {
3835 auto startTok = consumeToken(FIRToken::lp_path);
3836 locationProcessor.setLoc(startTok.getLoc());
3838 if (parseGetSpelling(target) ||
3839 parseToken(FIRToken::string,
3840 "expected target string in path expression") ||
3841 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3843 result = builder.create<UnresolvedPathOp>(
3849ParseResult FIRStmtParser::parseRefDefine() {
3850 auto startTok = consumeToken(FIRToken::kw_define);
3853 if (parseStaticRefExp(target,
3854 "expected static reference expression in 'define'") ||
3855 parseToken(FIRToken::equal,
3856 "expected '=' after define reference expression") ||
3857 parseRefExp(src,
"expected reference expression in 'define'") ||
3858 parseOptionalInfo())
3862 if (!type_isa<RefType>(target.getType()))
3863 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3864 "'define' target (LHS), got ")
3865 << target.getType();
3866 if (!type_isa<RefType>(src.getType()))
3867 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3868 "'define' source (RHS), got ")
3873 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3874 return emitError(startTok.getLoc(),
3875 "cannot define into a sub-element of a reference");
3877 locationProcessor.setLoc(startTok.getLoc());
3880 return emitError(startTok.getLoc(),
"cannot define reference of type ")
3881 << target.getType() <<
" with incompatible reference of type "
3891ParseResult FIRStmtParser::parseRefRead(Value &result) {
3892 auto startTok = consumeToken(FIRToken::lp_read);
3895 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
3896 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
3899 locationProcessor.setLoc(startTok.getLoc());
3902 if (!type_isa<RefType>(ref.getType()))
3903 return emitError(startTok.getLoc(),
3904 "expected reference-type expression in 'read', got ")
3907 result = builder.create<RefResolveOp>(ref);
3913ParseResult FIRStmtParser::parseProbe(Value &result) {
3914 auto startTok = consumeToken(FIRToken::lp_probe);
3917 if (parseStaticRefExp(staticRef,
3918 "expected static reference expression in 'probe'") ||
3919 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
3922 locationProcessor.setLoc(startTok.getLoc());
3925 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3926 return emitError(startTok.getLoc(),
3927 "expected base-type expression in 'probe', got ")
3928 << staticRef.getType();
3932 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3933 MemoryDebugPortOp, MemoryPortAccessOp>(
3934 staticRef.getDefiningOp()))
3935 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3937 result = builder.create<RefSendOp>(staticRef);
3943ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3944 auto startTok = consumeToken(FIRToken::lp_rwprobe);
3947 Type parsedTargetType;
3948 if (parseRWProbeStaticRefExp(
3949 staticRef, parsedTargetType,
3950 "expected static reference expression in 'rwprobe'") ||
3951 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
3954 locationProcessor.setLoc(startTok.getLoc());
3960 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
3962 return emitError(startTok.getLoc(),
3963 "expected base-type expression in 'rwprobe', got ")
3964 << parsedTargetType;
3967 auto *definingOp = root.getDefiningOp();
3969 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3970 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
3971 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3975 return emitError(startTok.getLoc(),
"cannot force target of type ")
3979 auto op = builder.create<RWProbeOp>(forceableType,
3980 getConstants().placeholderInnerRef);
3987ParseResult FIRStmtParser::parseRefForce() {
3988 auto startTok = consumeToken(FIRToken::lp_force);
3990 Value clock, pred, dest, src;
3991 if (parseExp(clock,
"expected clock expression in force") ||
3992 parseToken(FIRToken::comma,
"expected ','") ||
3993 parseExp(pred,
"expected predicate expression in force") ||
3994 parseToken(FIRToken::comma,
"expected ','") ||
3995 parseRefExp(dest,
"expected destination reference expression in force") ||
3996 parseToken(FIRToken::comma,
"expected ','") ||
3997 parseExp(src,
"expected source expression in force") ||
3998 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
3999 parseOptionalInfo())
4003 auto ref = type_dyn_cast<RefType>(dest.getType());
4004 if (!ref || !ref.getForceable())
4007 "expected rwprobe-type expression for force destination, got ")
4009 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4011 return emitError(startTok.getLoc(),
4012 "expected base-type for force source, got ")
4014 if (!srcBaseType.isPassive())
4015 return emitError(startTok.getLoc(),
4016 "expected passive value for force source, got ")
4019 locationProcessor.setLoc(startTok.getLoc());
4022 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4023 if (noConstSrcType != ref.getType()) {
4025 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4027 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
4029 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4030 << src.getType() <<
" cannot target destination "
4034 builder.create<RefForceOp>(clock, pred, dest, src);
4040ParseResult FIRStmtParser::parseRefForceInitial() {
4041 auto startTok = consumeToken(FIRToken::lp_force_initial);
4045 dest,
"expected destination reference expression in force_initial") ||
4046 parseToken(FIRToken::comma,
"expected ','") ||
4047 parseExp(src,
"expected source expression in force_initial") ||
4048 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4049 parseOptionalInfo())
4053 auto ref = type_dyn_cast<RefType>(dest.getType());
4054 if (!ref || !ref.getForceable())
4055 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4056 "force_initial destination, got ")
4058 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4060 return emitError(startTok.getLoc(),
4061 "expected base-type expression for force_initial "
4064 if (!srcBaseType.isPassive())
4065 return emitError(startTok.getLoc(),
4066 "expected passive value for force_initial source, got ")
4069 locationProcessor.setLoc(startTok.getLoc());
4072 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4073 if (noConstSrcType != ref.getType()) {
4075 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4077 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
4079 return emitError(startTok.getLoc(),
4080 "incompatible force_initial source of type ")
4081 << src.getType() <<
" cannot target destination "
4085 auto value = APInt::getAllOnes(1);
4086 auto type = UIntType::get(builder.getContext(), 1);
4087 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4088 value.getBitWidth(),
4089 IntegerType::Unsigned),
4091 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4092 builder.create<RefForceInitialOp>(pred, dest, src);
4098ParseResult FIRStmtParser::parseRefRelease() {
4099 auto startTok = consumeToken(FIRToken::lp_release);
4101 Value clock, pred, dest;
4102 if (parseExp(clock,
"expected clock expression in release") ||
4103 parseToken(FIRToken::comma,
"expected ','") ||
4104 parseExp(pred,
"expected predicate expression in release") ||
4105 parseToken(FIRToken::comma,
"expected ','") ||
4107 "expected destination reference expression in release") ||
4108 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4109 parseOptionalInfo())
4113 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4114 !ref || !ref.getForceable())
4117 "expected rwprobe-type expression for release destination, got ")
4120 locationProcessor.setLoc(startTok.getLoc());
4122 builder.create<RefReleaseOp>(clock, pred, dest);
4128ParseResult FIRStmtParser::parseRefReleaseInitial() {
4129 auto startTok = consumeToken(FIRToken::lp_release_initial);
4134 "expected destination reference expression in release_initial") ||
4135 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4136 parseOptionalInfo())
4140 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4141 !ref || !ref.getForceable())
4142 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4143 "release_initial destination, got ")
4146 locationProcessor.setLoc(startTok.getLoc());
4148 auto value = APInt::getAllOnes(1);
4149 auto type = UIntType::get(builder.getContext(), 1);
4150 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4151 value.getBitWidth(),
4152 IntegerType::Unsigned),
4154 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4155 builder.create<RefReleaseInitialOp>(pred, dest);
4161ParseResult FIRStmtParser::parseConnect() {
4162 auto startTok = consumeToken(FIRToken::kw_connect);
4163 auto loc = startTok.getLoc();
4166 if (parseExp(lhs,
"expected connect expression") ||
4167 parseToken(FIRToken::comma,
"expected ','") ||
4168 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4171 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4172 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4173 if (!lhsType || !rhsType)
4174 return emitError(loc,
"cannot connect reference or property types");
4176 if (lhsType.containsReference() || rhsType.containsReference())
4177 return emitError(loc,
"cannot connect types containing references");
4180 return emitError(loc,
"cannot connect non-equivalent type ")
4181 << rhsType <<
" to " << lhsType;
4183 locationProcessor.setLoc(loc);
4189ParseResult FIRStmtParser::parsePropAssign() {
4190 auto startTok = consumeToken(FIRToken::kw_propassign);
4191 auto loc = startTok.getLoc();
4194 if (parseExp(lhs,
"expected propassign expression") ||
4195 parseToken(FIRToken::comma,
"expected ','") ||
4196 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4199 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4200 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4201 if (!lhsType || !rhsType)
4202 return emitError(loc,
"can only propassign property types");
4203 locationProcessor.setLoc(loc);
4204 if (lhsType != rhsType) {
4206 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4207 rhs = builder.create<ObjectAnyRefCastOp>(rhs);
4209 return emitError(loc,
"cannot propassign non-equivalent type ")
4210 << rhsType <<
" to " << lhsType;
4212 builder.create<PropAssignOp>(lhs, rhs);
4217ParseResult FIRStmtParser::parseInvalidate() {
4218 auto startTok = consumeToken(FIRToken::kw_invalidate);
4223 auto loc = getToken().getLoc();
4225 if (parseId(
id,
"expected static reference expression") ||
4226 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4231 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4232 if (parseOptionalExpPostscript(lhs,
false) ||
4233 parseOptionalInfo())
4236 locationProcessor.setLoc(startTok.getLoc());
4237 emitInvalidate(lhs);
4244 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4246 if (getToken().isNot(FIRToken::period)) {
4247 locationProcessor.setLoc(loc);
4249 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4251 for (
auto elt : ubEntry)
4252 emitInvalidate(elt.second);
4258 StringRef fieldName;
4259 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4260 parseFieldId(fieldName,
"expected field name") ||
4261 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4265 if (parseOptionalExpPostscript(lhs,
false) ||
4266 parseOptionalInfo())
4269 locationProcessor.setLoc(startTok.getLoc());
4270 emitInvalidate(lhs);
4274ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4276 auto startTok = consumeToken();
4277 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4278 "consumed an unexpected token");
4279 auto loc = startTok.getLoc();
4282 if (parseId(
id,
"expected layer identifer") ||
4283 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4284 parseOptionalInfo())
4287 locationProcessor.setLoc(loc);
4289 StringRef rootLayer;
4290 SmallVector<FlatSymbolRefAttr> nestedLayers;
4294 rootLayer = layerSym.getRootReference();
4295 auto nestedRefs = layerSym.getNestedReferences();
4296 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4297 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4300 auto layerBlockOp = builder.create<LayerBlockOp>(
4301 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4302 layerBlockOp->getRegion(0).push_back(
new Block());
4304 if (getIndentation() > indent)
4305 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4306 layerBlockOp.getLayerName()))
4314ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4315 auto loc = getToken().getLoc();
4318 if (consumeIf(FIRToken::kw_is)) {
4319 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4320 parseOptionalInfo())
4323 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4326 locationProcessor.setLoc(loc);
4327 emitInvalidate(lhs);
4331 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4334 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4338 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4341 locationProcessor.setLoc(loc);
4343 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4344 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4345 if (!lhsType || !rhsType)
4346 return emitError(loc,
"cannot connect reference or property types");
4348 if (lhsType.containsReference() || rhsType.containsReference())
4349 return emitError(loc,
"cannot connect types containing references");
4352 return emitError(loc,
"cannot connect non-equivalent type ")
4353 << rhsType <<
" to " << lhsType;
4362ParseResult FIRStmtParser::parseInstance() {
4363 auto startTok = consumeToken(FIRToken::kw_inst);
4367 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4371 StringRef moduleName;
4372 if (parseId(
id,
"expected instance name") ||
4373 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4374 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4377 locationProcessor.setLoc(startTok.getLoc());
4380 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4381 if (!referencedModule)
4384 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4386 auto annotations = getConstants().emptyArrayAttr;
4387 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4389 hw::InnerSymAttr sym = {};
4390 auto result = builder.create<InstanceOp>(
4391 referencedModule, id, NameKindEnum::InterestingName,
4392 annotations.getValue(), portAnnotations,
false,
false, sym);
4398 unbundledValueEntry.reserve(modulePorts.size());
4399 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4400 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4404 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4405 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4406 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4411ParseResult FIRStmtParser::parseInstanceChoice() {
4412 auto startTok = consumeToken(FIRToken::kw_instchoice);
4413 SMLoc loc = startTok.getLoc();
4416 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4423 StringRef defaultModuleName;
4424 StringRef optionGroupName;
4425 if (parseId(
id,
"expected instance name") ||
4426 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4427 parseId(defaultModuleName,
"expected module name") ||
4428 parseToken(FIRToken::comma,
"expected ','") ||
4429 parseId(optionGroupName,
"expected option group name") ||
4430 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4431 parseOptionalInfo())
4434 locationProcessor.setLoc(startTok.getLoc());
4438 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4442 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4445 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4447 return emitError(loc,
4448 "use of undefined option group '" + optionGroupName +
"'");
4450 auto baseIndent = getIndentation();
4451 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4452 while (getIndentation() == baseIndent) {
4454 StringRef caseModuleName;
4455 if (parseId(caseId,
"expected a case identifier") ||
4456 parseToken(FIRToken::equal_greater,
4457 "expected '=> in instance choice definition") ||
4458 parseId(caseModuleName,
"expected module name"))
4461 auto caseModule = getReferencedModule(loc, caseModuleName);
4465 for (
const auto &[defaultPort, casePort] :
4466 llvm::zip(modulePorts, caseModule.getPorts())) {
4467 if (defaultPort.name != casePort.name)
4468 return emitError(loc,
"instance case module port '")
4469 << casePort.name.getValue()
4470 <<
"' does not match the default module port '"
4471 << defaultPort.name.getValue() <<
"'";
4472 if (defaultPort.type != casePort.type)
4473 return emitError(loc,
"instance case port '")
4474 << casePort.name.getValue()
4475 <<
"' type does not match the default module port";
4479 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4481 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4482 caseModules.emplace_back(optionCase, caseModule);
4485 auto annotations = getConstants().emptyArrayAttr;
4486 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4490 auto result = builder.create<InstanceChoiceOp>(
4491 defaultModule, caseModules, id, NameKindEnum::InterestingName,
4492 annotations.getValue(), portAnnotations, sym);
4496 unbundledValueEntry.reserve(modulePorts.size());
4497 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4498 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4500 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4501 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4502 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4505FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4506 StringRef moduleName) {
4507 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4508 if (!referencedModule) {
4510 "use of undefined module name '" + moduleName +
"' in instance");
4513 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4514 emitError(loc,
"cannot create instance of class '" + moduleName +
4515 "', did you mean object?");
4518 return referencedModule;
4522ParseResult FIRStmtParser::parseObject() {
4523 auto startTok = consumeToken(FIRToken::kw_object);
4527 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4534 StringRef className;
4535 if (parseId(
id,
"expected object name") ||
4536 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4537 parseId(className,
"expected class name") || parseOptionalInfo())
4540 locationProcessor.setLoc(startTok.getLoc());
4543 const auto &classMap = getConstants().classMap;
4544 auto lookup = classMap.find(className);
4545 if (lookup == classMap.end())
4546 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4547 className +
"' in object");
4548 auto referencedClass = lookup->getSecond();
4549 auto result = builder.create<ObjectOp>(referencedClass, id);
4550 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4554ParseResult FIRStmtParser::parseCombMem() {
4556 auto startTok = consumeToken(FIRToken::kw_cmem);
4560 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4565 if (parseId(
id,
"expected cmem name") ||
4566 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4567 parseType(type,
"expected cmem type") || parseOptionalInfo())
4570 locationProcessor.setLoc(startTok.getLoc());
4573 auto vectorType = type_dyn_cast<FVectorType>(type);
4575 return emitError(
"cmem requires vector type");
4577 auto annotations = getConstants().emptyArrayAttr;
4578 StringAttr sym = {};
4579 auto result = builder.create<CombMemOp>(
4580 vectorType.getElementType(), vectorType.getNumElements(), id,
4581 NameKindEnum::InterestingName, annotations, sym);
4582 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4586ParseResult FIRStmtParser::parseSeqMem() {
4588 auto startTok = consumeToken(FIRToken::kw_smem);
4592 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4597 RUWAttr ruw = RUWAttr::Undefined;
4599 if (parseId(
id,
"expected smem name") ||
4600 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4604 if (consumeIf(FIRToken::comma)) {
4609 if (parseOptionalInfo()) {
4613 locationProcessor.setLoc(startTok.getLoc());
4616 auto vectorType = type_dyn_cast<FVectorType>(type);
4618 return emitError(
"smem requires vector type");
4620 auto annotations = getConstants().emptyArrayAttr;
4621 StringAttr sym = {};
4622 auto result = builder.create<SeqMemOp>(
4623 vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
4624 NameKindEnum::InterestingName, annotations, sym);
4625 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4637ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4638 auto startTok = consumeToken(FIRToken::kw_mem);
4642 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4646 if (parseId(
id,
"expected mem name") ||
4647 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4651 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4652 RUWAttr ruw = RUWAttr::Undefined;
4654 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4658 auto nextIndent = getIndentation();
4659 if (!nextIndent || *nextIndent <= memIndent)
4662 auto spelling = getTokenSpelling();
4663 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4664 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4667 if (spelling ==
"data-type") {
4669 return emitError(
"'mem' type specified multiple times"), failure();
4671 if (
parseType(type,
"expected type in data-type declaration"))
4675 if (spelling ==
"depth") {
4676 if (parseIntLit(depth,
"expected integer in depth specification"))
4680 if (spelling ==
"read-latency") {
4681 if (parseIntLit(readLatency,
"expected integer latency"))
4685 if (spelling ==
"write-latency") {
4686 if (parseIntLit(writeLatency,
"expected integer latency"))
4690 if (spelling ==
"read-under-write") {
4691 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4692 FIRToken::kw_undefined))
4693 return emitError(
"expected specifier"), failure();
4695 if (parseOptionalRUW(ruw))
4700 MemOp::PortKind portKind;
4701 if (spelling ==
"reader")
4702 portKind = MemOp::PortKind::Read;
4703 else if (spelling ==
"writer")
4704 portKind = MemOp::PortKind::Write;
4705 else if (spelling ==
"readwriter")
4706 portKind = MemOp::PortKind::ReadWrite;
4708 return emitError(
"unexpected field in 'mem' declaration"), failure();
4711 if (parseId(portName,
"expected port name"))
4713 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4715 return emitError(
"unexpected type, must be base type");
4716 ports.push_back({builder.getStringAttr(portName),
4717 MemOp::getTypeForPort(depth, baseType, portKind)});
4719 while (!getIndentation().has_value()) {
4720 if (parseId(portName,
"expected port name"))
4722 ports.push_back({builder.getStringAttr(portName),
4723 MemOp::getTypeForPort(depth, baseType, portKind)});
4734 llvm::array_pod_sort(ports.begin(), ports.end(),
4735 [](
const std::pair<StringAttr, Type> *lhs,
4736 const std::pair<StringAttr, Type> *rhs) ->
int {
4737 return lhs->first.getValue().compare(
4738 rhs->first.getValue());
4741 auto annotations = getConstants().emptyArrayAttr;
4742 SmallVector<Attribute, 4> resultNames;
4743 SmallVector<Type, 4> resultTypes;
4744 SmallVector<Attribute, 4> resultAnnotations;
4745 for (
auto p : ports) {
4746 resultNames.push_back(p.first);
4747 resultTypes.push_back(p.second);
4748 resultAnnotations.push_back(annotations);
4751 locationProcessor.setLoc(startTok.getLoc());
4753 auto result = builder.create<MemOp>(
4754 resultTypes, readLatency, writeLatency, depth, ruw,
4755 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
4756 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4757 MemoryInitAttr(), StringAttr());
4760 unbundledValueEntry.reserve(result.getNumResults());
4761 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4762 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4764 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4765 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4766 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4770ParseResult FIRStmtParser::parseNode() {
4771 auto startTok = consumeToken(FIRToken::kw_node);
4775 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4780 if (parseId(
id,
"expected node name") ||
4781 parseToken(FIRToken::equal,
"expected '=' in node") ||
4782 parseExp(initializer,
"expected expression for node") ||
4783 parseOptionalInfo())
4786 locationProcessor.setLoc(startTok.getLoc());
4798 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4799 auto initializerBaseType =
4800 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4801 if (type_isa<AnalogType>(initializerType) ||
4802 !(initializerBaseType && initializerBaseType.isPassive())) {
4803 emitError(startTok.getLoc())
4804 <<
"Node cannot be analog and must be passive or passive under a flip "
4805 << initializer.getType();
4809 auto annotations = getConstants().emptyArrayAttr;
4810 StringAttr sym = {};
4812 auto result = builder.create<NodeOp>(
4813 initializer, id, NameKindEnum::InterestingName, annotations, sym);
4814 return moduleContext.addSymbolEntry(
id, result.getResult(),
4819ParseResult FIRStmtParser::parseWire() {
4820 auto startTok = consumeToken(FIRToken::kw_wire);
4824 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4829 if (parseId(
id,
"expected wire name") ||
4830 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4831 parseType(type,
"expected wire type") || parseOptionalInfo())
4834 locationProcessor.setLoc(startTok.getLoc());
4836 auto annotations = getConstants().emptyArrayAttr;
4837 StringAttr sym = {};
4840 auto namekind = isa<PropertyType, RefType>(type)
4841 ? NameKindEnum::DroppableName
4842 : NameKindEnum::InterestingName;
4844 auto result = builder.create<WireOp>(type, id, namekind, annotations, sym);
4845 return moduleContext.addSymbolEntry(
id, result.getResult(),
4859ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4860 auto startTok = consumeToken(FIRToken::kw_reg);
4864 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4873 if (parseId(
id,
"expected reg name") ||
4874 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4876 parseToken(FIRToken::comma,
"expected ','") ||
4877 parseExp(clock,
"expected expression for register clock"))
4880 if (!type_isa<FIRRTLBaseType>(type))
4881 return emitError(startTok.getLoc(),
"register must have base type");
4884 Value resetSignal, resetValue;
4885 if (consumeIf(FIRToken::kw_with)) {
4886 if (removedFeature({3, 0, 0},
"'reg with' registers"))
4889 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
4897 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4899 auto indent = getIndentation();
4900 if (!indent || *indent <= regIndent)
4901 if (!hasExtraLParen)
4902 return emitError(
"expected indented reset specifier in reg"), failure();
4904 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
4905 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
4906 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
4907 parseExp(resetSignal,
"expected expression for reset signal") ||
4908 parseToken(FIRToken::comma,
"expected ','"))
4916 if (getTokenSpelling() ==
id) {
4918 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4920 resetSignal = Value();
4922 if (parseExp(resetValue,
"expected expression for reset value") ||
4923 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4927 if (hasExtraLParen &&
4928 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4934 if (parseOptionalInfo())
4937 locationProcessor.setLoc(startTok.getLoc());
4939 ArrayAttr annotations = getConstants().emptyArrayAttr;
4941 StringAttr sym = {};
4945 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4946 NameKindEnum::InterestingName, annotations, sym)
4950 .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4953 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4961ParseResult FIRStmtParser::parseRegisterWithReset() {
4962 auto startTok = consumeToken(FIRToken::kw_regreset);
4966 Value clock, resetSignal, resetValue;
4968 if (parseId(
id,
"expected reg name") ||
4969 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4971 parseToken(FIRToken::comma,
"expected ','") ||
4972 parseExp(clock,
"expected expression for register clock") ||
4973 parseToken(FIRToken::comma,
"expected ','") ||
4974 parseExp(resetSignal,
"expected expression for register reset") ||
4975 parseToken(FIRToken::comma,
"expected ','") ||
4976 parseExp(resetValue,
"expected expression for register reset value") ||
4977 parseOptionalInfo())
4980 if (!type_isa<FIRRTLBaseType>(type))
4981 return emitError(startTok.getLoc(),
"register must have base type");
4983 locationProcessor.setLoc(startTok.getLoc());
4987 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4988 NameKindEnum::InterestingName,
4989 getConstants().emptyArrayAttr, StringAttr{})
4992 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4997ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5001 auto startTok = consumeToken(FIRToken::kw_contract);
5004 SmallVector<StringRef> ids;
5005 SmallVector<SMLoc> locs;
5006 SmallVector<Value> values;
5007 SmallVector<Type> types;
5008 if (!consumeIf(FIRToken::colon)) {
5009 auto parseContractId = [&] {
5011 locs.push_back(getToken().
getLoc());
5012 if (parseId(
id,
"expected contract result name"))
5017 auto parseContractValue = [&] {
5019 if (parseExp(value,
"expected expression for contract result"))
5021 values.push_back(value);
5022 types.push_back(value.getType());
5025 if (parseListUntil(FIRToken::equal, parseContractId) ||
5026 parseListUntil(FIRToken::colon, parseContractValue))
5029 if (parseOptionalInfo())
5033 if (ids.size() != values.size())
5034 return emitError(startTok.getLoc())
5035 <<
"contract requires same number of results and expressions; got "
5036 << ids.size() <<
" results and " << values.size()
5037 <<
" expressions instead";
5039 locationProcessor.setLoc(startTok.getLoc());
5043 auto contract = builder.create<ContractOp>(types, values);
5044 auto &block = contract.getBody().emplaceBlock();
5048 FIRModuleContext::ContextScope scope(moduleContext, &block);
5049 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5050 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5051 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5054 if (getIndentation() > blockIndent)
5055 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5060 for (
auto [
id, loc, value, result] :
5061 llvm::zip(ids, locs, values, contract.getResults())) {
5063 moduleContext.removeSymbolEntry(
id);
5064 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5077struct FIRCircuitParser :
public FIRParser {
5078 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5080 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5083 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5084 mlir::TimingScope &ts);
5089 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5090 SmallVectorImpl<Attribute> &attrs);
5092 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5094 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5095 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5096 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5097 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5098 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5099 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5100 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5102 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5104 ParseResult parseLayerName(SymbolRefAttr &result);
5105 ParseResult parseOptionalEnabledLayers(ArrayAttr &result);
5106 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5107 SmallVectorImpl<SMLoc> &resultPortLocs,
5110 ParseResult parseRefList(ArrayRef<PortInfo> portList,
5111 ArrayAttr &internalPathsResult);
5113 ParseResult skipToModuleEnd(
unsigned indent);
5115 ParseResult parseTypeDecl();
5117 ParseResult parseOptionDecl(CircuitOp circuit);
5119 ParseResult parseLayer(CircuitOp circuit);
5121 struct DeferredModuleToParse {
5122 FModuleLike moduleOp;
5123 SmallVector<SMLoc> portLocs;
5128 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5129 DeferredModuleToParse &deferredModule,
5130 InnerSymFixups &fixups);
5132 SmallVector<DeferredModuleToParse, 0> deferredModules;
5134 SmallVector<InnerSymFixups, 0> moduleFixups;
5138 ModuleOp mlirModule;
5143FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5144 SmallVectorImpl<Attribute> &attrs) {
5146 auto annotations = json::parse(annotationsStr);
5147 if (
auto err = annotations.takeError()) {
5148 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5149 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5150 diag.attachNote() << a.message();
5155 json::Path::Root root;
5156 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5159 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5160 std::string jsonErrorMessage =
5161 "See inline comments for problem area in JSON:\n";
5162 llvm::raw_string_ostream s(jsonErrorMessage);
5163 root.printErrorContext(annotations.get(), s);
5164 diag.attachNote() << jsonErrorMessage;
5171ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5172 auto *context = getContext();
5173 SmallVector<StringRef> strings;
5176 if (parseId(name,
"expected layer name"))
5178 strings.push_back(name);
5179 }
while (consumeIf(FIRToken::period));
5181 SmallVector<FlatSymbolRefAttr> nested;
5182 nested.reserve(strings.size() - 1);
5183 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5184 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5186 result = SymbolRefAttr::get(context, strings[0], nested);
5190ParseResult FIRCircuitParser::parseOptionalEnabledLayers(ArrayAttr &result) {
5191 if (getToken().getKind() != FIRToken::kw_enablelayer) {
5192 result = ArrayAttr::get(getContext(), {});
5196 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5199 SmallVector<Attribute> layers;
5201 SymbolRefAttr layer;
5203 if (parseLayerName(layer))
5205 layers.push_back(layer);
5206 }
while (getToken().getKind() == FIRToken::kw_enablelayer);
5208 result = ArrayAttr::get(getContext(), layers);
5216FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5217 SmallVectorImpl<SMLoc> &resultPortLocs,
5220 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5222 getIndentation() > indent) {
5228 auto backtrackState = getLexer().getCursor();
5230 bool isOutput = getToken().is(FIRToken::kw_output);
5235 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5236 !getToken().isKeyword()) {
5237 backtrackState.restore(getLexer());
5244 if (parseId(name,
"expected port name") ||
5245 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5246 parseType(type,
"expected a type in port declaration") ||
5247 info.parseOptionalInfo())
5250 StringAttr innerSym = {};
5251 resultPorts.push_back(
5253 resultPortLocs.push_back(
info.getFIRLoc());
5258 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5259 PortInfo &port = std::get<0>(portAndLoc);
5260 auto &entry = portIds[port.
name];
5261 if (!entry.isValid()) {
5262 entry = std::get<1>(portAndLoc);
5266 emitError(std::get<1>(portAndLoc),
5267 "redefinition of name '" + port.
getName() +
"'")
5268 .attachNote(translateLocation(entry))
5269 <<
"previous definition here";
5278ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
5279 ArrayAttr &internalPathsResult) {
5280 struct RefStatementInfo {
5282 InternalPathAttr resolvedPath;
5286 SmallVector<RefStatementInfo> refStatements;
5287 SmallPtrSet<StringAttr, 8> seenNames;
5288 SmallPtrSet<StringAttr, 8> seenRefs;
5291 if (getToken().is(FIRToken::kw_ref) &&
5292 (requireFeature({2, 0, 0},
"ref statements") ||
5293 removedFeature({4, 0, 0},
"ref statements")))
5297 while (consumeIf(FIRToken::kw_ref)) {
5298 auto loc = getToken().getLoc();
5302 if (parseId(refName,
"expected ref name"))
5304 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
5306 loc,
"ref statements for aggregate elements not yet supported");
5307 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
5310 if (!seenRefs.insert(refName).second)
5311 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
5314 auto kind = getToken().getKind();
5315 if (kind != FIRToken::string)
5316 return emitError(loc,
"expected string in ref statement");
5317 auto resolved = InternalPathAttr::get(
5319 StringAttr::get(getContext(), getToken().getStringValue()));
5320 consumeToken(FIRToken::string);
5322 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
5326 SmallVector<Attribute> internalPaths(portList.size(),
5327 InternalPathAttr::get(getContext()));
5329 llvm::SmallBitVector usedRefs(refStatements.size());
5330 size_t matchedPaths = 0;
5331 for (
auto [idx, port] :
llvm::enumerate(portList)) {
5332 if (!type_isa<RefType>(port.
type))
5338 return mlir::emitError(
5340 "references in ports must be output on extmodule and intmodule");
5342 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
5343 return r.refName == pname;
5346 if (refStmtIt == refStatements.end()) {
5347 if (!refStatements.empty())
5348 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
5353 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
5354 internalPaths[idx] = refStmtIt->resolvedPath;
5358 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
5359 assert(matchedPaths < refStatements.size());
5361 auto idx = usedRefs.find_first_unset();
5363 return emitError(refStatements[idx].loc,
"unused ref statement");
5367 internalPathsResult = ArrayAttr::get(getContext(), internalPaths);
5373ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5375 switch (getToken().getKind()) {
5379 case FIRToken::error:
5383 case FIRToken::kw_class:
5384 case FIRToken::kw_declgroup:
5385 case FIRToken::kw_extclass:
5386 case FIRToken::kw_extmodule:
5387 case FIRToken::kw_intmodule:
5388 case FIRToken::kw_formal:
5389 case FIRToken::kw_module:
5390 case FIRToken::kw_public:
5391 case FIRToken::kw_layer:
5392 case FIRToken::kw_option:
5393 case FIRToken::kw_simulation:
5394 case FIRToken::kw_type:
5398 if (getIndentation() == indent)
5410ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5411 SmallVector<Attribute, 8> parameters;
5412 SmallPtrSet<StringAttr, 8> seen;
5413 while (consumeIf(FIRToken::kw_parameter)) {
5417 if (parseParameter(name, value, loc))
5419 auto typedValue = dyn_cast<TypedAttr>(value);
5421 return emitError(loc)
5422 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5423 if (!seen.insert(name).second)
5424 return emitError(loc,
5425 "redefinition of parameter '" + name.getValue() +
"'");
5426 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5428 resultParameters = ArrayAttr::get(getContext(), parameters);
5433ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5435 SmallVector<PortInfo, 8> portList;
5436 SmallVector<SMLoc> portLocs;
5442 consumeToken(FIRToken::kw_class);
5443 if (parseId(name,
"expected class name") ||
5444 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5448 if (name == circuit.getName())
5449 return mlir::emitError(
info.getLoc(),
5450 "class cannot be the top of a circuit");
5452 for (
auto &portInfo : portList)
5454 return
mlir::emitError(portInfo.loc,
5455 "ports on classes must be properties");
5458 auto builder = circuit.getBodyBuilder();
5459 auto classOp = builder.create<ClassOp>(
info.getLoc(), name, portList);
5460 classOp.setPrivate();
5461 deferredModules.emplace_back(
5462 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5465 getConstants().classMap[name.getValue()] = classOp;
5466 return skipToModuleEnd(indent);
5470ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5473 SmallVector<PortInfo, 8> portList;
5474 SmallVector<SMLoc> portLocs;
5480 consumeToken(FIRToken::kw_extclass);
5481 if (parseId(name,
"expected extclass name") ||
5482 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5486 if (name == circuit.getName())
5487 return mlir::emitError(
info.getLoc(),
5488 "extclass cannot be the top of a circuit");
5490 for (
auto &portInfo : portList)
5492 return
mlir::emitError(portInfo.loc,
5493 "ports on extclasses must be properties");
5496 auto builder = circuit.getBodyBuilder();
5497 auto extClassOp = builder.create<ExtClassOp>(
info.getLoc(), name, portList);
5500 getConstants().classMap[name.getValue()] = extClassOp;
5501 return skipToModuleEnd(indent);
5508ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5512 SmallVector<PortInfo, 8> portList;
5513 SmallVector<SMLoc> portLocs;
5515 consumeToken(FIRToken::kw_extmodule);
5516 if (parseId(name,
"expected extmodule name") ||
5517 parseOptionalEnabledLayers(layers) ||
5518 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5523 if (consumeIf(FIRToken::kw_defname)) {
5524 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5525 parseId(defName,
"expected defname name"))
5529 ArrayAttr parameters;
5530 ArrayAttr internalPaths;
5535 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5536 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5537 if (ftype.hasUninferredWidth())
5538 return emitError(loc,
"extmodule port must have known width");
5543 auto builder = circuit.getBodyBuilder();
5544 auto isMainModule = (name == circuit.getName());
5546 (isMainModule && getConstants().options.scalarizePublicModules) ||
5547 getConstants().options.scalarizeExtModules
5548 ? Convention::Scalarized
5549 : Convention::Internal;
5550 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5551 auto annotations = ArrayAttr::get(getContext(), {});
5552 auto extModuleOp = builder.create<FExtModuleOp>(
5553 info.getLoc(), name, conventionAttr, portList, defName, annotations,
5554 parameters, internalPaths, layers);
5555 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5556 : SymbolTable::Visibility::Private;
5557 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5565ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5570 SmallVector<PortInfo, 8> portList;
5571 SmallVector<SMLoc> portLocs;
5573 consumeToken(FIRToken::kw_intmodule);
5574 if (parseId(name,
"expected intmodule name") ||
5575 parseOptionalEnabledLayers(layers) ||
5576 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5578 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5579 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5580 parseId(intName,
"expected intrinsic name"))
5583 ArrayAttr parameters;
5584 ArrayAttr internalPaths;
5588 ArrayAttr annotations = getConstants().emptyArrayAttr;
5589 auto builder = circuit.getBodyBuilder();
5591 .create<FIntModuleOp>(
info.getLoc(), name, portList, intName, annotations,
5592 parameters, internalPaths, layers)
5598ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5601 SmallVector<PortInfo, 8> portList;
5602 SmallVector<SMLoc> portLocs;
5604 auto modLoc = getToken().getLoc();
5605 LocWithInfo
info(modLoc,
this);
5606 consumeToken(FIRToken::kw_module);
5607 if (parseId(name,
"expected module name") ||
5608 parseOptionalEnabledLayers(layers) ||
5609 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5614 if (name == circuit.getName()) {
5615 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5620 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5621 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5622 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5623 if (ftype.hasUninferredWidth())
5624 return emitError(loc,
"public module port must have known width");
5625 if (ftype.hasUninferredReset())
5626 return emitError(loc,
5627 "public module port must have concrete reset type");
5632 ArrayAttr annotations = getConstants().emptyArrayAttr;
5633 auto convention = Convention::Internal;
5634 if (isPublic && getConstants().options.scalarizePublicModules)
5635 convention = Convention::Scalarized;
5636 if (!isPublic && getConstants().options.scalarizeInternalModules)
5637 convention = Convention::Scalarized;
5638 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5639 auto builder = circuit.getBodyBuilder();
5640 auto moduleOp = builder.create<FModuleOp>(
info.getLoc(), name, conventionAttr,
5641 portList, annotations, layers);
5643 auto visibility = isPublic ? SymbolTable::Visibility::Public
5644 : SymbolTable::Visibility::Private;
5645 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5649 deferredModules.emplace_back(DeferredModuleToParse{
5650 moduleOp, portLocs, getLexer().getCursor(), indent});
5652 if (skipToModuleEnd(indent))
5658ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5659 consumeToken(FIRToken::kw_formal);
5660 return parseFormalLike<FormalOp>(circuit, indent);
5664ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5666 consumeToken(FIRToken::kw_simulation);
5667 return parseFormalLike<SimulationOp>(circuit, indent);
5674ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5676 StringRef id, moduleName;
5679 auto builder = circuit.getBodyBuilder();
5682 if (parseId(
id,
"expected test name") ||
5683 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5684 parseId(moduleName,
"expected module name"))
5688 NamedAttrList params;
5689 if (consumeIf(FIRToken::comma)) {
5691 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5692 return emitError(
"expected 'bound' after ','");
5694 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5695 parseIntLit(bound,
"expected integer bound after '='"))
5698 return emitError(
"bound must be a positive integer");
5699 if (
info.parseOptionalInfo())
5701 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5704 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5705 info.parseOptionalInfo())
5707 while (getIndentation() > indent) {
5708 StringAttr paramName;
5709 Attribute paramValue;
5711 if (parseParameter(paramName, paramValue, paramLoc,
5714 if (params.set(paramName, paramValue))
5715 return emitError(paramLoc,
"redefinition of parameter '" +
5716 paramName.getValue() +
"'");
5720 builder.create<Op>(
info.getLoc(), id, moduleName,
5721 params.getDictionary(getContext()));
5725ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5727 switch (getToken().getKind()) {
5728 case FIRToken::kw_class:
5729 return parseClass(circuit, indent);
5730 case FIRToken::kw_declgroup:
5731 if (requireFeature({3, 2, 0},
"optional groups") ||
5732 removedFeature({3, 3, 0},
"optional groups"))
5734 return parseLayer(circuit);
5735 case FIRToken::kw_extclass:
5736 return parseExtClass(circuit, indent);
5737 case FIRToken::kw_extmodule:
5738 return parseExtModule(circuit, indent);
5739 case FIRToken::kw_formal:
5740 if (requireFeature({4, 0, 0},
"formal tests"))
5742 return parseFormal(circuit, indent);
5743 case FIRToken::kw_intmodule:
5744 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
5745 removedFeature({4, 0, 0},
"intrinsic modules"))
5747 return parseIntModule(circuit, indent);
5748 case FIRToken::kw_layer:
5749 if (requireFeature({3, 3, 0},
"layers"))
5751 return parseLayer(circuit);
5752 case FIRToken::kw_module:
5753 return parseModule(circuit,
false, indent);
5754 case FIRToken::kw_public:
5755 if (requireFeature({3, 3, 0},
"public modules"))
5758 if (getToken().getKind() == FIRToken::kw_module)
5759 return parseModule(circuit,
true, indent);
5760 return emitError(getToken().
getLoc(),
"only modules may be public");
5761 case FIRToken::kw_simulation:
5764 return parseSimulation(circuit, indent);
5765 case FIRToken::kw_type:
5766 return parseTypeDecl();
5767 case FIRToken::kw_option:
5770 return parseOptionDecl(circuit);
5772 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
5777ParseResult FIRCircuitParser::parseTypeDecl() {
5781 auto loc = getToken().getLoc();
5783 if (getToken().isKeyword())
5784 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5785 <<
"' for type alias name";
5787 if (parseId(
id,
"expected type name") ||
5788 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5791 auto name = StringAttr::get(type.getContext(),
id);
5794 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5795 type = BaseTypeAliasType::get(name, base);
5798 <<
"type alias for non-base type " << type
5799 <<
" is currently not supported. Type alias is stripped immediately";
5801 if (!getConstants().aliasMap.insert({id, type}).second)
5802 return emitError(loc) <<
"type alias `" << name.getValue()
5803 <<
"` is already defined";
5808ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
5811 auto loc = getToken().getLoc();
5814 if (parseId(
id,
"expected an option group name") ||
5815 parseToken(FIRToken::colon,
5816 "expected ':' after option group definition") ||
5817 info.parseOptionalInfo())
5820 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
5821 auto optionOp = builder.create<OptionOp>(
info.getLoc(), id);
5822 auto *block =
new Block;
5823 optionOp.getBody().push_back(block);
5824 builder.setInsertionPointToEnd(block);
5826 auto baseIndent = getIndentation();
5828 while (getIndentation() == baseIndent) {
5830 LocWithInfo caseInfo(getToken().
getLoc(),
this);
5831 if (parseId(
id,
"expected an option case ID") ||
5832 caseInfo.parseOptionalInfo())
5835 if (!cases.insert(
id).second)
5836 return emitError(loc)
5837 <<
"duplicate option case definition '" <<
id <<
"'";
5839 builder.create<OptionCaseOp>(caseInfo.getLoc(), id);
5846ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
5847 auto baseIndent = getIndentation();
5850 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
5853 auto parseOne = [&](
Block *block) -> ParseResult {
5854 auto indent = getIndentation();
5855 StringRef id, convention;
5858 if (parseId(
id,
"expected layer name") ||
5859 parseToken(FIRToken::comma,
"expected ','") ||
5860 parseGetSpelling(convention))
5863 auto layerConvention = symbolizeLayerConvention(convention);
5864 if (!layerConvention) {
5865 emitError() <<
"unknown convention '" << convention
5866 <<
"' (did you misspell it?)";
5869 if (layerConvention == LayerConvention::Inline &&
5870 requireFeature({4, 1, 0},
"inline layers"))
5874 hw::OutputFileAttr outputDir;
5875 if (consumeIf(FIRToken::comma)) {
5876 if (getToken().getKind() == FIRToken::string) {
5877 auto text = getToken().getStringValue();
5879 return emitError() <<
"output directory must not be blank";
5880 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
5881 consumeToken(FIRToken::string);
5885 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
5886 info.parseOptionalInfo())
5888 auto builder = OpBuilder::atBlockEnd(block);
5890 auto layerOp = builder.create<LayerOp>(
info.getLoc(), id, *layerConvention);
5891 layerOp->getRegion(0).push_back(
new Block());
5893 layerOp->setAttr(
"output_file", outputDir);
5894 layerStack.push_back({indent, layerOp});
5898 if (parseOne(circuit.getBodyBlock()))
5902 while (getIndentation() > baseIndent) {
5903 switch (getToken().getKind()) {
5904 case FIRToken::kw_declgroup:
5905 case FIRToken::kw_layer: {
5908 while (layerStack.back().first >= getIndentation())
5909 layerStack.pop_back();
5910 auto parentLayer = layerStack.back().second;
5911 if (parseOne(&parentLayer.getBody().front()))
5916 return emitError(
"expected 'layer'"), failure();
5925FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
5926 DeferredModuleToParse &deferredModule,
5927 InnerSymFixups &fixups) {
5928 FModuleLike moduleOp = deferredModule.moduleOp;
5929 auto &body = moduleOp->getRegion(0).front();
5930 auto &portLocs = deferredModule.portLocs;
5934 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
5937 deferredModule.lexerCursor.restore(moduleBodyLexer);
5939 FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
5943 auto portList = moduleOp.getPorts();
5944 auto portArgs = body.getArguments();
5945 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
5946 PortInfo &port = std::get<0>(tuple);
5947 llvm::SMLoc loc = std::get<1>(tuple);
5948 BlockArgument portArg = std::get<2>(tuple);
5950 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
5954 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
5957 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
5963 size_t numVerifPrintfs = 0;
5964 std::optional<Location> printfLoc;
5966 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
5971 printfLoc = printFOp.getLoc();
5974 if (numVerifPrintfs > 0) {
5976 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
5978 <<
" printf-encoded verification operation(s), which are no longer "
5980 diag.attachNote(*printfLoc)
5981 <<
"example printf here, this is now just a printf and nothing more";
5982 diag.attachNote() <<
"For more information, see "
5983 "https://github.com/llvm/circt/issues/6970";
5997ParseResult FIRCircuitParser::parseCircuit(
5998 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
5999 mlir::TimingScope &ts) {
6001 auto indent = getIndentation();
6002 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6004 if (!indent.has_value())
6005 return emitError(
"'FIRRTL' must be first token on its line");
6006 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6007 parseVersionLit(
"expected version literal"))
6009 indent = getIndentation();
6011 if (!indent.has_value())
6012 return emitError(
"'circuit' must be first token on its line");
6013 unsigned circuitIndent = *indent;
6017 SMLoc inlineAnnotationsLoc;
6018 StringRef inlineAnnotations;
6021 if (parseToken(FIRToken::kw_circuit,
6022 "expected a top-level 'circuit' definition") ||
6023 parseId(name,
"expected circuit name") ||
6024 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6025 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6026 info.parseOptionalInfo())
6030 OpBuilder b(mlirModule.getBodyRegion());
6031 auto circuit = b.create<CircuitOp>(
info.getLoc(), name);
6034 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6040 SmallVector<Attribute> annos;
6041 if (!inlineAnnotations.empty())
6042 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6046 for (
auto *annotationsBuf : annotationsBufs)
6047 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6051 parseAnnotationTimer.stop();
6059 auto parseTimer = ts.nest(
"Parse modules");
6060 deferredModules.reserve(16);
6064 switch (getToken().getKind()) {
6072 case FIRToken::error:
6076 emitError(
"unexpected token in circuit");
6079 case FIRToken::kw_class:
6080 case FIRToken::kw_declgroup:
6081 case FIRToken::kw_extclass:
6082 case FIRToken::kw_extmodule:
6083 case FIRToken::kw_intmodule:
6084 case FIRToken::kw_layer:
6085 case FIRToken::kw_formal:
6086 case FIRToken::kw_module:
6087 case FIRToken::kw_option:
6088 case FIRToken::kw_public:
6089 case FIRToken::kw_simulation:
6090 case FIRToken::kw_type: {
6091 auto indent = getIndentation();
6092 if (!indent.has_value())
6093 return emitError(
"'module' must be first token on its line"), failure();
6094 unsigned definitionIndent = *indent;
6096 if (definitionIndent <= circuitIndent)
6097 return emitError(
"module should be indented more"), failure();
6099 if (parseToplevelDefinition(circuit, definitionIndent))
6113 (void)getLexer().translateLocation(
info.getFIRLoc());
6119 DenseMap<Attribute, Location> nameToOrigLoc;
6123 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6128 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6131 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6132 .attachNote(it.first->second)
6133 .append(
"see existing symbol definition here");
6139 SymbolTable circuitSymTbl(circuit);
6141 moduleFixups.resize(deferredModules.size());
6146 for (
auto &d : deferredModules)
6147 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6150 auto anyFailed = mlir::failableParallelForEachN(
6151 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6152 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6153 moduleFixups[index]))
6157 if (failed(anyFailed))
6162 for (
auto &fixups : moduleFixups) {
6163 if (failed(fixups.resolve(innerSymbolNamespaces)))
6169 auto parseLayerName = [&](StringRef name) -> Attribute {
6171 auto [head, rest] = name.split(
".");
6172 SmallVector<FlatSymbolRefAttr> nestedRefs;
6173 while (!rest.empty()) {
6175 std::tie(next, rest) = rest.split(
".");
6176 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6178 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6181 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6182 SmallVector<Attribute> attrArray;
6183 auto *context = getContext();
6184 for (
const auto &str : strArray)
6185 attrArray.push_back(getAttr(str));
6186 if (attrArray.empty())
6188 return ArrayAttr::get(context, attrArray);
6191 if (
auto enableLayers =
6192 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6193 circuit.setEnableLayersAttr(enableLayers);
6194 if (
auto disableLayers =
6195 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6196 circuit.setDisableLayersAttr(disableLayers);
6198 auto getStrAttr = [&](StringRef str) -> Attribute {
6199 return StringAttr::get(getContext(), str);
6202 if (
auto selectInstChoice =
6203 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6204 circuit.setSelectInstChoiceAttr(selectInstChoice);
6206 circuit.setDefaultLayerSpecialization(
6207 getConstants().options.defaultLayerSpecialization);
6220 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6221 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6222 unsigned fileID = 1;
6224 annotationsBufs.push_back(
6225 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6227 context->loadDialect<CHIRRTLDialect>();
6228 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6232 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6235 SharedParserConstants state(context, options);
6236 FIRLexer lexer(sourceMgr, context);
6238 .parseCircuit(annotationsBufs, ts))
6243 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6244 if (failed(verify(*module)))
6251 static mlir::TranslateToMLIRRegistration fromFIR(
6252 "import-firrtl",
"import .fir",
6253 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6254 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
bool isRecognizedPrintfEncodedVerif(PrintFOp printOp)
Classifier for legacy verif intent captured in printf + when's.
constexpr FIRVersion nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
The FIRRTL specification version.
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