25#include "mlir/IR/BuiltinOps.h"
26#include "mlir/IR/BuiltinTypes.h"
27#include "mlir/IR/Diagnostics.h"
28#include "mlir/IR/ImplicitLocOpBuilder.h"
29#include "mlir/IR/PatternMatch.h"
30#include "mlir/IR/Threading.h"
31#include "mlir/IR/Verifier.h"
32#include "mlir/Support/Timing.h"
33#include "mlir/Tools/mlir-translate/Translation.h"
34#include "llvm/ADT/PointerEmbeddedInt.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/SmallPtrSet.h"
37#include "llvm/ADT/StringExtras.h"
38#include "llvm/ADT/StringSet.h"
39#include "llvm/ADT/StringSwitch.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/JSON.h"
42#include "llvm/Support/SourceMgr.h"
43#include "llvm/Support/raw_ostream.h"
48using namespace firrtl;
49using namespace chirrtl;
53using mlir::LocationAttr;
66struct SharedParserConstants {
68 : context(context), options(options),
69 emptyArrayAttr(ArrayAttr::
get(context, {})),
70 loIdentifier(StringAttr::get(context,
"lo")),
71 hiIdentifier(StringAttr::get(context,
"hi")),
72 amountIdentifier(StringAttr::get(context,
"amount")),
74 hw::InnerRefAttr::get(StringAttr::get(context,
"module"),
75 StringAttr::get(context,
"placeholder"))) {}
78 MLIRContext *
const context;
84 llvm::StringMap<FIRRTLType> aliasMap;
87 llvm::DenseMap<StringRef, ClassLike> classMap;
90 const ArrayAttr emptyArrayAttr;
93 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
96 const hw::InnerRefAttr placeholderInnerRef;
99 SharedParserConstants(
const SharedParserConstants &) =
delete;
100 void operator=(
const SharedParserConstants &) =
delete;
113 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
115 : version(version), constants(constants), lexer(lexer),
116 locatorFilenameCache(constants.loIdentifier ) {
120 SharedParserConstants &getConstants()
const {
return constants; }
121 MLIRContext *getContext()
const {
return constants.context; }
123 FIRLexer &getLexer() {
return lexer; }
126 std::optional<unsigned> getIndentation()
const {
131 const FIRToken &getToken()
const {
return lexer.getToken(); }
132 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
139 InFlightDiagnostic emitError(
const Twine &message = {}) {
140 return emitError(getToken().getLoc(), message);
142 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
145 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
146 return emitWarning(getToken().getLoc(), message);
149 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
159 Location translateLocation(llvm::SMLoc loc) {
160 return lexer.translateLocation(loc);
165 ParseResult parseOptionalInfoLocator(LocationAttr &result);
169 ParseResult parseOptionalName(StringAttr &name);
175 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
176 return requireFeature(minimum, feature, getToken().getLoc());
179 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
180 if (version < minimum)
181 return emitError(loc)
182 << feature <<
" are a FIRRTL " << minimum
183 <<
"+ feature, but the specified FIRRTL version was " << version;
187 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
188 return removedFeature(removedVersion, feature, getToken().getLoc());
191 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
193 if (version >= removedVersion)
194 return emitError(loc)
195 << feature <<
" were removed in FIRRTL " << removedVersion
196 <<
", but the specified FIRRTL version was " << version;
206 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
215 if (getToken().isNot(kind))
225 FIRToken consumedToken = getToken();
226 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
227 "shouldn't advance past EOF or errors");
229 return consumedToken;
238 FIRToken consumedToken = getToken();
239 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
241 return consumedToken;
246 ParseResult parseGetSpelling(StringRef &spelling) {
247 spelling = getTokenSpelling();
253 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
258 const std::function<ParseResult()> &parseElement);
265 ParseResult parseIntLit(APInt &result,
const Twine &message);
266 ParseResult parseIntLit(int64_t &result,
const Twine &message);
267 ParseResult parseIntLit(int32_t &result,
const Twine &message);
270 ParseResult parseVersionLit(
const Twine &message);
273 template <
typename T>
274 ParseResult parseOptionalWidth(T &result);
277 ParseResult parseId(StringRef &result,
const Twine &message);
278 ParseResult parseId(StringAttr &result,
const Twine &message);
279 ParseResult parseFieldId(StringRef &result,
const Twine &message);
280 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
281 const Twine &message);
282 ParseResult parseEnumType(
FIRRTLType &result);
283 ParseResult parseListType(
FIRRTLType &result);
286 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
288 ParseResult parseRUW(RUWAttr &result);
289 ParseResult parseOptionalRUW(RUWAttr &result);
291 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
292 SMLoc &resultLoc,
bool allowAggregates =
false);
293 ParseResult parseParameterValue(Attribute &resultValue,
294 bool allowAggregates =
false);
300 FIRParser(
const FIRParser &) =
delete;
301 void operator=(
const FIRParser &) =
delete;
305 SharedParserConstants &constants;
309 StringAttr locatorFilenameCache;
311 FileLineColLoc fileLineColLocCache;
320InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
321 auto diag = mlir::emitError(translateLocation(loc), message);
325 if (getToken().is(FIRToken::error))
330InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
331 return mlir::emitWarning(translateLocation(loc), message);
341 const Twine &message) {
342 if (consumeIf(expectedToken))
344 return emitError(message);
351 const std::function<ParseResult()> &parseElement) {
352 if (consumeIf(rightToken))
358 while (consumeIf(FIRToken::comma)) {
363 if (parseToken(rightToken,
"expected ','"))
395 if (failed(
parser->parseOptionalInfoLocator(loc)))
399 switch (
parser->constants.options.infoLocatorHandling) {
400 case ILH::IgnoreInfo:
401 assert(0 &&
"Should not return info locations if ignoring");
403 case ILH::PreferInfo:
407 infoLoc = FusedLoc::get(loc.getContext(),
408 {loc, parser->translateLocation(firLoc)});
435ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
436 if (getToken().isNot(FIRToken::fileinfo))
439 auto loc = getToken().getLoc();
441 auto spelling = getTokenSpelling();
442 consumeToken(FIRToken::fileinfo);
446 constants.options.infoLocatorHandling ==
447 FIRParserOptions::InfoLocHandling::IgnoreInfo,
448 locatorFilenameCache, fileLineColLocCache, getContext());
451 if (!locationPair.first) {
452 mlir::emitWarning(translateLocation(loc),
453 "ignoring unknown @ info record format");
459 if (locationPair.first && constants.options.infoLocatorHandling ==
460 FIRParserOptions::InfoLocHandling::IgnoreInfo)
464 result = *locationPair.second;
472ParseResult FIRParser::parseOptionalName(StringAttr &name) {
474 if (getToken().isNot(FIRToken::colon)) {
475 name = StringAttr::get(getContext(),
"");
479 consumeToken(FIRToken::colon);
481 if (parseId(nameRef,
"expected result name"))
484 name = StringAttr::get(getContext(), nameRef);
495ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
497 if (getToken().isNot(FIRToken::inlineannotation))
500 loc = getToken().getLoc();
502 result = getTokenSpelling().drop_front(2).drop_back(1);
503 consumeToken(FIRToken::inlineannotation);
521ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
522 auto spelling = getTokenSpelling();
523 bool isNegative =
false;
524 switch (getToken().getKind()) {
525 case FIRToken::signed_integer:
526 isNegative = spelling[0] ==
'-';
527 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
528 spelling = spelling.drop_front();
530 case FIRToken::integer:
531 if (spelling.getAsInteger(10, result))
532 return emitError(message), failure();
536 if (result.isNegative())
537 result = result.zext(result.getBitWidth() + 1);
546 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
547 result = result.trunc(32);
551 case FIRToken::radix_specified_integer: {
552 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
554 if (spelling[0] ==
'-') {
556 spelling = spelling.drop_front();
558 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
563 spelling = spelling.drop_front(2);
564 if (spelling.getAsInteger(base, result))
565 return emitError(
"invalid character in integer literal"), failure();
566 if (result.isNegative())
567 result = result.zext(result.getBitWidth() + 1);
573 case FIRToken::string: {
576 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
579 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
580 spelling = spelling.drop_back().drop_front();
584 switch (spelling.empty() ?
' ' : spelling.front()) {
595 return emitError(
"expected base specifier (h/o/b) in integer literal"),
598 spelling = spelling.drop_front();
601 bool isNegative =
false;
602 if (!spelling.empty() && spelling.front() ==
'+')
603 spelling = spelling.drop_front();
604 else if (!spelling.empty() && spelling.front() ==
'-') {
606 spelling = spelling.drop_front();
610 if (spelling.empty())
611 return emitError(
"expected digits in integer literal"), failure();
613 if (spelling.getAsInteger(base, result))
614 return emitError(
"invalid character in integer literal"), failure();
619 if (result.isNegative())
620 result = result.zext(result.getBitWidth() + 1);
625 consumeToken(FIRToken::string);
630 return emitError(
"expected integer literal"), failure();
634ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
636 auto loc = getToken().getLoc();
637 if (parseIntLit(value, message))
640 result = (int64_t)value.getLimitedValue(INT64_MAX);
642 return emitError(loc,
"value is too big to handle"), failure();
646ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
648 auto loc = getToken().getLoc();
649 if (parseIntLit(value, message))
652 result = (int32_t)value.getLimitedValue(INT32_MAX);
654 return emitError(loc,
"value is too big to handle"), failure();
660ParseResult FIRParser::parseVersionLit(
const Twine &message) {
661 auto spelling = getTokenSpelling();
662 if (getToken().getKind() != FIRToken::version)
663 return emitError(message), failure();
665 auto [a, d] = spelling.split(
".");
666 auto [b, c] = d.split(
".");
667 APInt aInt, bInt, cInt;
668 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
669 c.getAsInteger(10, cInt))
670 return emitError(
"failed to parse version string"), failure();
671 version.major = aInt.getLimitedValue(UINT32_MAX);
672 version.minor = bInt.getLimitedValue(UINT32_MAX);
673 version.patch = cInt.getLimitedValue(UINT32_MAX);
674 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
675 return emitError(
"integers out of range"), failure();
679 consumeToken(FIRToken::version);
687ParseResult FIRParser::parseOptionalWidth(T &result) {
688 if (!consumeIf(FIRToken::less))
689 return result = -1, success();
692 auto widthLoc = getToken().getLoc();
693 if (parseIntLit(result,
"expected width") ||
694 parseToken(FIRToken::greater,
"expected >"))
698 return emitError(widthLoc,
"invalid width specifier"), failure();
707ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
708 switch (getToken().getKind()) {
710 case FIRToken::identifier:
711 case FIRToken::literal_identifier:
713#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
714#include "FIRTokenKinds.def"
719 if (getToken().getKind() == FIRToken::literal_identifier)
720 result = getTokenSpelling().drop_front().drop_back();
722 result = getTokenSpelling();
732ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
734 if (parseId(name, message))
737 result = StringAttr::get(getContext(), name);
746ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
748 result = getTokenSpelling();
749 if (consumeIf(FIRToken::integer))
755 if (parseId(result, message))
767ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
768 const Twine &message) {
770 StringRef tmp = getTokenSpelling();
772 if (consumeIf(FIRToken::integer)) {
773 result.push_back(tmp);
777 if (consumeIf(FIRToken::floatingpoint)) {
781 auto [a, b] = tmp.split(
".");
787 if (consumeIf(FIRToken::version)) {
789 auto [a, d] = tmp.split(
".");
790 auto [b, c] = d.split(
".");
798 if (parseId(tmp, message))
800 result.push_back(tmp);
806ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
807 if (parseToken(FIRToken::l_brace_bar,
808 "expected leading '{|' in enumeration type"))
810 SmallVector<FEnumType::EnumElement> elements;
811 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
812 auto fieldLoc = getToken().getLoc();
816 if (parseId(name,
"expected valid identifier for enumeration tag"))
821 if (consumeIf(FIRToken::colon)) {
823 if (
parseType(parsedType,
"expected enumeration type"))
825 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
827 return emitError(fieldLoc,
"field must be a base type");
830 type = UIntType::get(getContext(), 0);
832 elements.emplace_back(StringAttr::get(getContext(), name), type);
836 result = FEnumType::get(getContext(), elements);
840ParseResult FIRParser::parsePropertyType(
PropertyType &result,
841 const Twine &message) {
845 auto prop = type_dyn_cast<PropertyType>(type);
847 return emitError(
"expected property type");
853ParseResult FIRParser::parseListType(
FIRRTLType &result) {
854 consumeToken(FIRToken::kw_List);
857 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
858 parsePropertyType(
elementType,
"expected List element type") ||
859 parseToken(FIRToken::greater,
"expected '>' in List type"))
884ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
885 switch (getToken().getKind()) {
887 return emitError(message), failure();
889 case FIRToken::kw_Clock:
890 consumeToken(FIRToken::kw_Clock);
891 result = ClockType::get(getContext());
894 case FIRToken::kw_Inst: {
898 consumeToken(FIRToken::kw_Inst);
899 if (parseToken(FIRToken::less,
"expected < in Inst type"))
902 auto loc = getToken().getLoc();
904 if (parseId(
id,
"expected class name in Inst type"))
908 const auto &classMap = getConstants().classMap;
909 auto lookup = classMap.find(
id);
910 if (lookup == classMap.end())
911 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
913 auto classOp = lookup->second;
915 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
918 result = classOp.getInstanceType();
922 case FIRToken::kw_AnyRef: {
926 consumeToken(FIRToken::kw_AnyRef);
927 result = AnyRefType::get(getContext());
931 case FIRToken::kw_Reset:
932 consumeToken(FIRToken::kw_Reset);
933 result = ResetType::get(getContext());
936 case FIRToken::kw_AsyncReset:
937 consumeToken(FIRToken::kw_AsyncReset);
938 result = AsyncResetType::get(getContext());
941 case FIRToken::kw_UInt:
942 case FIRToken::kw_SInt:
943 case FIRToken::kw_Analog: {
944 auto kind = getToken().getKind();
949 if (parseOptionalWidth(width))
952 if (kind == FIRToken::kw_SInt)
953 result = SIntType::get(getContext(), width);
954 else if (kind == FIRToken::kw_UInt)
955 result = UIntType::get(getContext(), width);
957 assert(kind == FIRToken::kw_Analog);
958 result = AnalogType::get(getContext(), width);
963 case FIRToken::kw_Probe:
964 case FIRToken::kw_RWProbe: {
965 auto kind = getToken().getKind();
966 auto loc = getToken().getLoc();
971 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
972 parseType(type,
"expected probe data type"))
975 SmallVector<StringRef> layers;
976 if (consumeIf(FIRToken::comma)) {
977 if (requireFeature({4, 0, 0},
"colored probes"))
982 loc = getToken().getLoc();
983 if (parseId(layer,
"expected layer name"))
985 layers.push_back(layer);
986 }
while (consumeIf(FIRToken::period));
989 if (!consumeIf(FIRToken::greater))
990 return emitError(loc,
"expected '>' to end reference type");
992 bool forceable = kind == FIRToken::kw_RWProbe;
994 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
996 return emitError(loc,
"invalid probe inner type, must be base-type");
999 return emitError(loc,
"probe inner type must be passive");
1001 if (forceable &&
innerType.containsConst())
1002 return emitError(loc,
"rwprobe cannot contain const");
1004 SymbolRefAttr layer;
1005 if (!layers.empty()) {
1007 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1008 return FlatSymbolRefAttr::get(getContext(), a);
1010 layer = SymbolRefAttr::get(getContext(), layers.front(),
1011 llvm::to_vector(nestedLayers));
1014 result = RefType::get(innerType, forceable, layer);
1018 case FIRToken::l_brace: {
1019 consumeToken(FIRToken::l_brace);
1021 SmallVector<OpenBundleType::BundleElement, 4> elements;
1022 bool bundleCompatible =
true;
1023 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1024 bool isFlipped = consumeIf(FIRToken::kw_flip);
1026 StringRef fieldName;
1028 if (parseFieldId(fieldName,
"expected bundle field name") ||
1029 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1031 if (
parseType(type,
"expected bundle field type"))
1035 {StringAttr::get(getContext(), fieldName), isFlipped, type});
1036 bundleCompatible &= isa<BundleType::ElementType>(type);
1043 if (bundleCompatible) {
1044 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1045 return BundleType::BundleElement{
1046 element.name, element.isFlip,
1047 cast<BundleType::ElementType>(element.type)};
1049 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1051 result = OpenBundleType::get(getContext(), elements);
1055 case FIRToken::l_brace_bar: {
1056 if (parseEnumType(result))
1061 case FIRToken::identifier: {
1063 auto loc = getToken().getLoc();
1064 if (parseId(
id,
"expected a type alias name"))
1066 auto it = constants.aliasMap.find(
id);
1067 if (it == constants.aliasMap.end()) {
1068 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1071 result = it->second;
1075 case FIRToken::kw_const: {
1076 consumeToken(FIRToken::kw_const);
1077 auto nextToken = getToken();
1078 auto loc = nextToken.getLoc();
1081 if (nextToken.is(FIRToken::kw_const))
1082 return emitError(loc,
"'const' can only be specified once on a type");
1087 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1089 return emitError(loc,
"only hardware types can be 'const'");
1091 result = baseType.getConstType(
true);
1095 case FIRToken::kw_String:
1096 if (requireFeature({3, 1, 0},
"Strings"))
1098 consumeToken(FIRToken::kw_String);
1099 result = StringType::get(getContext());
1101 case FIRToken::kw_Integer:
1102 if (requireFeature({3, 1, 0},
"Integers"))
1104 consumeToken(FIRToken::kw_Integer);
1105 result = FIntegerType::get(getContext());
1107 case FIRToken::kw_Bool:
1110 consumeToken(FIRToken::kw_Bool);
1111 result = BoolType::get(getContext());
1113 case FIRToken::kw_Double:
1116 consumeToken(FIRToken::kw_Double);
1117 result = DoubleType::get(getContext());
1119 case FIRToken::kw_Path:
1122 consumeToken(FIRToken::kw_Path);
1123 result = PathType::get(getContext());
1125 case FIRToken::kw_List:
1126 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1132 while (consumeIf(FIRToken::l_square)) {
1133 auto sizeLoc = getToken().getLoc();
1135 if (parseIntLit(size,
"expected width") ||
1136 parseToken(FIRToken::r_square,
"expected ]"))
1140 return emitError(sizeLoc,
"invalid size specifier"), failure();
1142 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1144 result = FVectorType::get(baseType, size);
1146 result = OpenVectorType::get(result, size);
1153ParseResult FIRParser::parseRUW(RUWAttr &result) {
1154 switch (getToken().getKind()) {
1156 case FIRToken::kw_old:
1157 result = RUWAttr::Old;
1158 consumeToken(FIRToken::kw_old);
1160 case FIRToken::kw_new:
1161 result = RUWAttr::New;
1162 consumeToken(FIRToken::kw_new);
1164 case FIRToken::kw_undefined:
1165 result = RUWAttr::Undefined;
1166 consumeToken(FIRToken::kw_undefined);
1176ParseResult FIRParser::parseOptionalRUW(RUWAttr &result) {
1177 switch (getToken().getKind()) {
1181 case FIRToken::kw_old:
1182 result = RUWAttr::Old;
1183 consumeToken(FIRToken::kw_old);
1185 case FIRToken::kw_new:
1186 result = RUWAttr::New;
1187 consumeToken(FIRToken::kw_new);
1189 case FIRToken::kw_undefined:
1190 result = RUWAttr::Undefined;
1191 consumeToken(FIRToken::kw_undefined);
1199ParseResult FIRParser::parseParameter(StringAttr &resultName,
1200 Attribute &resultValue, SMLoc &resultLoc,
1201 bool allowAggregates) {
1202 auto loc = getToken().getLoc();
1206 if (parseId(name,
"expected parameter name") ||
1207 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1212 if (parseParameterValue(value, allowAggregates))
1215 resultName = StringAttr::get(getContext(), name);
1216 resultValue = value;
1227ParseResult FIRParser::parseParameterValue(Attribute &value,
1228 bool allowAggregates) {
1229 mlir::Builder builder(getContext());
1230 switch (getToken().getKind()) {
1233 case FIRToken::integer:
1234 case FIRToken::signed_integer: {
1236 if (parseIntLit(result,
"invalid integer parameter"))
1242 if (result.getBitWidth() < 32)
1243 result = result.sext(32);
1245 value = builder.getIntegerAttr(
1246 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1252 case FIRToken::string: {
1254 value = builder.getStringAttr(getToken().getStringValue());
1255 consumeToken(FIRToken::string);
1260 case FIRToken::verbatim_string: {
1262 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1263 value = hw::ParamVerbatimAttr::get(text);
1264 consumeToken(FIRToken::verbatim_string);
1269 case FIRToken::floatingpoint: {
1271 if (!llvm::to_float(getTokenSpelling(), v))
1272 return emitError(
"invalid float parameter syntax"), failure();
1274 value = builder.getF64FloatAttr(v);
1275 consumeToken(FIRToken::floatingpoint);
1280 case FIRToken::l_square: {
1281 if (!allowAggregates)
1282 return emitError(
"expected non-aggregate parameter value");
1285 SmallVector<Attribute> elements;
1286 auto parseElement = [&] {
1287 return parseParameterValue(elements.emplace_back(),
1290 if (parseListUntil(FIRToken::r_square, parseElement))
1293 value = builder.getArrayAttr(elements);
1298 case FIRToken::l_brace: {
1299 if (!allowAggregates)
1300 return emitError(
"expected non-aggregate parameter value");
1303 NamedAttrList fields;
1304 auto parseField = [&]() -> ParseResult {
1305 StringAttr fieldName;
1306 Attribute fieldValue;
1308 if (parseParameter(fieldName, fieldValue, fieldLoc,
1311 if (fields.set(fieldName, fieldValue))
1312 return emitError(fieldLoc)
1313 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1316 if (parseListUntil(FIRToken::r_brace, parseField))
1319 value = fields.getDictionary(getContext());
1324 return emitError(
"expected parameter value");
1339 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1347struct UnbundledValueRestorer {
1349 size_t startingSize;
1351 startingSize = list.size();
1353 ~UnbundledValueRestorer() { list.resize(startingSize); }
1362struct FIRModuleContext :
public FIRParser {
1363 explicit FIRModuleContext(SharedParserConstants &constants,
FIRLexer &lexer,
1365 : FIRParser(constants, lexer, version) {}
1371 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1374 template <
typename OpTy = ConstantOp,
typename... Args>
1375 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1376 Type type, Args &&...args) {
1377 auto &result = constantCache[{attr, type}];
1383 OpBuilder::InsertPoint savedIP;
1385 auto *parentOp = builder.getInsertionBlock()->getParentOp();
1386 if (!isa<FModuleLike>(parentOp)) {
1387 savedIP = builder.saveInsertionPoint();
1388 while (!isa<FModuleLike>(parentOp)) {
1389 builder.setInsertionPoint(parentOp);
1390 parentOp = builder.getInsertionBlock()->getParentOp();
1394 result = builder.create<OpTy>(type, std::forward<Args>(args)...);
1396 if (savedIP.isSet())
1397 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1408 Value &getCachedSubaccess(Value value,
unsigned index) {
1409 auto &result = subaccessCache[{value, index}];
1412 auto it = scopeMap.find(value.getParentBlock());
1413 if (it != scopeMap.end())
1414 it->second->scopedSubaccesses.push_back({result, index});
1424 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1425 bool insertNameIntoGlobalScope =
false);
1426 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1427 bool insertNameIntoGlobalScope =
false) {
1429 insertNameIntoGlobalScope);
1434 SMLoc loc,
bool fatal =
true);
1439 StringRef field, SMLoc loc);
1447 assert(index < unbundledValues.size());
1448 return unbundledValues[index];
1458 struct ContextScope {
1459 friend struct FIRModuleContext;
1460 ContextScope(FIRModuleContext &moduleContext, Block *block)
1461 : moduleContext(moduleContext), block(block),
1462 previousScope(moduleContext.currentScope) {
1463 moduleContext.currentScope =
this;
1464 moduleContext.scopeMap[block] =
this;
1469 for (
auto *entryPtr : scopedDecls)
1470 entryPtr->second.first = SMLoc();
1473 for (
auto subaccess : scopedSubaccesses)
1474 moduleContext.subaccessCache.erase(subaccess);
1476 moduleContext.scopeMap.erase(block);
1478 moduleContext.currentScope = previousScope;
1482 void operator=(
const ContextScope &) =
delete;
1483 ContextScope(
const ContextScope &) =
delete;
1485 FIRModuleContext &moduleContext;
1487 ContextScope *previousScope;
1488 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1489 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1503 DenseMap<Block *, ContextScope *> scopeMap;
1508 ContextScope *currentScope =
nullptr;
1519ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1521 bool insertNameIntoGlobalScope) {
1526 if (entryIt->second.first.isValid()) {
1527 emitError(loc,
"redefinition of name '" + name +
"'")
1528 .attachNote(translateLocation(entryIt->second.first))
1529 <<
"previous definition here";
1535 entryIt->second = {loc, entry};
1536 if (currentScope && !insertNameIntoGlobalScope)
1537 currentScope->scopedDecls.push_back(&*entryIt);
1545 StringRef name, SMLoc loc) {
1546 auto &entry = symbolTable[name];
1547 if (!entry.first.isValid())
1548 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1549 result = entry.second;
1550 assert(result &&
"name in symbol table without definition");
1554ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1556 SMLoc loc,
bool fatal) {
1557 if (!isa<Value>(entry)) {
1559 emitError(loc,
"bundle value should only be used from subfield");
1562 result = cast<Value>(entry);
1566ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1568 StringRef fieldName,
1570 if (!isa<UnbundledID>(entry)) {
1571 emitError(loc,
"value should not be used from subfield");
1575 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1577 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1578 assert(unbundledId < unbundledValues.size());
1580 for (
auto elt : ubEntry) {
1581 if (elt.first == fieldAttr) {
1582 result = elt.second;
1587 emitError(loc,
"use of invalid field name '")
1588 << fieldName <<
"' on bundle value";
1614struct LazyLocationListener :
public OpBuilder::Listener {
1615 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1616 assert(builder.getListener() ==
nullptr);
1617 builder.setListener(
this);
1620 ~LazyLocationListener() {
1621 assert(subOps.empty() &&
"didn't process parsed operations");
1622 assert(builder.getListener() ==
this);
1623 builder.setListener(
nullptr);
1626 void startStatement() {
1627 assert(!isActive &&
"Already processing a statement");
1633 void endStatement(FIRParser &parser) {
1634 assert(isActive &&
"Not parsing a statement");
1638 for (
auto opAndSMLoc : subOps) {
1642 switch (parser.getConstants().options.infoLocatorHandling) {
1643 case ILH::IgnoreInfo:
1645 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1647 case ILH::PreferInfo:
1648 opAndSMLoc.first->setLoc(infoLoc);
1650 case ILH::FusedInfo:
1651 opAndSMLoc.first->setLoc(FusedLoc::get(
1652 infoLoc.getContext(),
1653 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1660 for (
auto opAndSMLoc : subOps)
1661 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1666 infoLoc = LocationAttr();
1667 currentSMLoc = SMLoc();
1672 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1675 void setInfoLoc(LocationAttr loc) {
1676 assert(!infoLoc &&
"Info location multiply specified");
1682 void notifyOperationInserted(Operation *op,
1683 mlir::IRRewriter::InsertPoint)
override {
1684 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1685 assert(isActive &&
"Not parsing a statement");
1686 subOps.push_back({op, currentSMLoc});
1691 bool isActive =
false;
1699 LocationAttr infoLoc;
1706 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1708 void operator=(
const LazyLocationListener &) =
delete;
1709 LazyLocationListener(
const LazyLocationListener &) =
delete;
1717struct InnerSymFixups {
1720 fixups.push_back({user, target});
1729 hw::InnerRefUserOpInterface innerRefUser;
1732 SmallVector<Fixup, 0> fixups;
1738 for (
auto &f : fixups) {
1741 return isnc.get(module);
1743 assert(ref &&
"unable to resolve inner symbol target");
1747 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1748 .Case<RWProbeOp>([ref](RWProbeOp op) {
1749 op.setTargetAttr(ref);
1752 .Default([](
auto *op) {
1753 return op->emitError(
"unknown inner-ref user requiring fixup");
1764struct FIRStmtParser :
public FIRParser {
1765 explicit FIRStmtParser(Block &blockToInsertInto,
1766 FIRModuleContext &moduleContext,
1767 InnerSymFixups &innerSymFixups,
1768 const SymbolTable &circuitSymTbl,
FIRVersion version,
1769 SymbolRefAttr layerSym = {})
1770 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1772 builder(UnknownLoc::
get(getContext()), getContext()),
1773 locationProcessor(this->builder), moduleContext(moduleContext),
1774 innerSymFixups(innerSymFixups), layerSym(layerSym),
1775 circuitSymTbl(circuitSymTbl) {
1776 builder.setInsertionPointToEnd(&blockToInsertInto);
1779 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1780 ParseResult parseSimpleStmtBlock(
unsigned indent);
1783 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1786 void emitInvalidate(Value val,
Flow flow);
1792 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1795 ParseResult parseOptionalInfo() {
1797 if (failed(parseOptionalInfoLocator(loc)))
1799 locationProcessor.setInfoLoc(loc);
1804 ParseResult parseExpImpl(Value &result,
const Twine &message,
1805 bool isLeadingStmt);
1806 ParseResult parseExp(Value &result,
const Twine &message) {
1807 return parseExpImpl(result, message,
false);
1809 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1810 return parseExpImpl(result, message,
true);
1812 ParseResult parseEnumExp(Value &result);
1813 ParseResult parsePathExp(Value &result);
1814 ParseResult parseRefExp(Value &result,
const Twine &message);
1815 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1816 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1817 const Twine &message);
1820 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1821 ParseResult parseIntrinsicStmt() {
1823 return parseIntrinsic(unused,
true);
1825 ParseResult parseIntrinsicExp(Value &result) {
1826 return parseIntrinsic(result,
false);
1828 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1830 template <
typename subop>
1831 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1832 ParseResult parseOptionalExpPostscript(Value &result,
1833 bool allowDynamic =
true);
1834 ParseResult parsePostFixFieldId(Value &result);
1835 ParseResult parsePostFixIntSubscript(Value &result);
1836 ParseResult parsePostFixDynamicSubscript(Value &result);
1837 ParseResult parseIntegerLiteralExp(Value &result);
1838 ParseResult parseListExp(Value &result);
1839 ParseResult parseListConcatExp(Value &result);
1841 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1842 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1844 auto loc = getToken().getLoc();
1845 locationProcessor.setLoc(loc);
1848 auto vals = std::array<Value, M>();
1849 auto ints = std::array<int64_t, N>();
1853 for (
size_t i = 0; i < M; ++i) {
1855 if (parseToken(FIRToken::comma,
"expected ','"))
1857 if (parseExp(vals[i],
"expected expression in primitive operand"))
1863 for (
size_t i = 0; i < N; ++i) {
1865 if (parseToken(FIRToken::comma,
"expected ','"))
1867 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
1872 if (parseToken(FIRToken::r_paren,
"expected ')'"))
1876 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
1880 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
1881 translateLocation(loc));
1886 auto op = builder.create<T>(type, vals[Ms]..., ints[Ns]...);
1887 result = op.getResult();
1891 template <
typename T,
unsigned M,
unsigned N>
1892 ParseResult parsePrimExp(Value &result) {
1893 auto ms = std::make_index_sequence<M>();
1894 auto ns = std::make_index_sequence<N>();
1895 return parsePrim<T, M, N>(ms, ns, result);
1898 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
1901 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
1902 SymbolRefAttr layerSym);
1903 ParseResult parseAttach();
1904 ParseResult parseMemPort(MemDirAttr direction);
1905 ParseResult parsePrintf();
1906 ParseResult parseSkip();
1907 ParseResult parseStop();
1908 ParseResult parseAssert();
1909 ParseResult parseAssume();
1910 ParseResult parseCover();
1911 ParseResult parseWhen(
unsigned whenIndent);
1912 ParseResult parseMatch(
unsigned matchIndent);
1913 ParseResult parseRefDefine();
1914 ParseResult parseRefForce();
1915 ParseResult parseRefForceInitial();
1916 ParseResult parseRefRelease();
1917 ParseResult parseRefReleaseInitial();
1918 ParseResult parseRefRead(Value &result);
1919 ParseResult parseProbe(Value &result);
1920 ParseResult parsePropAssign();
1921 ParseResult parseRWProbe(Value &result);
1922 ParseResult parseLeadingExpStmt(Value lhs);
1923 ParseResult parseConnect();
1924 ParseResult parseInvalidate();
1925 ParseResult parseLayerBlockOrGroup(
unsigned indent);
1928 ParseResult parseInstance();
1929 ParseResult parseInstanceChoice();
1930 ParseResult parseObject();
1931 ParseResult parseCombMem();
1932 ParseResult parseSeqMem();
1933 ParseResult parseMem(
unsigned memIndent);
1934 ParseResult parseNode();
1935 ParseResult parseWire();
1936 ParseResult parseRegister(
unsigned regIndent);
1937 ParseResult parseRegisterWithReset();
1938 ParseResult parseContract(
unsigned blockIndent);
1941 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
1944 ImplicitLocOpBuilder builder;
1945 LazyLocationListener locationProcessor;
1948 FIRModuleContext &moduleContext;
1951 InnerSymFixups &innerSymFixups;
1955 SymbolRefAttr layerSym;
1957 const SymbolTable &circuitSymTbl;
1964void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
1965 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
1972 auto props = tpe.getRecursiveTypeProperties();
1973 if (props.isPassive && !props.containsAnalog) {
1974 if (flow == Flow::Source)
1976 emitConnect(builder, val, builder.create<InvalidValueOp>(tpe));
1987 TypeSwitch<FIRRTLType>(tpe)
1988 .Case<BundleType>([&](
auto tpe) {
1989 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
1990 auto &subfield = moduleContext.getCachedSubaccess(val, i);
1992 OpBuilder::InsertionGuard guard(builder);
1993 builder.setInsertionPointAfterValue(val);
1994 subfield = builder.create<SubfieldOp>(val, i);
1996 emitInvalidate(subfield,
1997 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2000 .Case<FVectorType>([&](
auto tpe) {
2001 auto tpex = tpe.getElementType();
2002 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2003 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2005 OpBuilder::InsertionGuard guard(builder);
2006 builder.setInsertionPointAfterValue(val);
2007 subindex = builder.create<SubindexOp>(tpex, val, i);
2009 emitInvalidate(subindex, flow);
2037ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2038 bool isLeadingStmt) {
2039 auto token = getToken();
2040 auto kind = token.getKind();
2042 case FIRToken::lp_integer_add:
2043 case FIRToken::lp_integer_mul:
2044 case FIRToken::lp_integer_shr:
2045 case FIRToken::lp_integer_shl:
2046 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2055#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES) \
2056 case FIRToken::lp_##SPELLING: \
2057 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2060#include "FIRTokenKinds.def"
2062 case FIRToken::l_brace_bar:
2064 return emitError(
"unexpected enumeration as start of statement");
2065 if (parseEnumExp(result))
2068 case FIRToken::lp_read:
2070 return emitError(
"unexpected read() as start of statement");
2071 if (parseRefRead(result))
2074 case FIRToken::lp_probe:
2076 return emitError(
"unexpected probe() as start of statement");
2077 if (parseProbe(result))
2080 case FIRToken::lp_rwprobe:
2082 return emitError(
"unexpected rwprobe() as start of statement");
2083 if (parseRWProbe(result))
2087 case FIRToken::kw_UInt:
2088 case FIRToken::kw_SInt:
2089 if (parseIntegerLiteralExp(result))
2092 case FIRToken::kw_String: {
2093 if (requireFeature({3, 1, 0},
"Strings"))
2095 locationProcessor.setLoc(getToken().getLoc());
2096 consumeToken(FIRToken::kw_String);
2098 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2099 parseGetSpelling(spelling) ||
2100 parseToken(FIRToken::string,
2101 "expected string literal in String expression") ||
2102 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2105 result = moduleContext.getCachedConstant<StringConstantOp>(
2106 builder, attr, builder.getType<StringType>(), attr);
2109 case FIRToken::kw_Integer: {
2110 if (requireFeature({3, 1, 0},
"Integers"))
2112 locationProcessor.setLoc(getToken().getLoc());
2113 consumeToken(FIRToken::kw_Integer);
2115 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2116 parseIntLit(value,
"expected integer literal in Integer expression") ||
2117 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2119 APSInt apint(value,
false);
2120 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2121 builder, IntegerAttr::get(getContext(), apint),
2122 builder.getType<FIntegerType>(), apint);
2125 case FIRToken::kw_Bool: {
2128 locationProcessor.setLoc(getToken().getLoc());
2129 consumeToken(FIRToken::kw_Bool);
2130 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2133 if (consumeIf(FIRToken::kw_true))
2135 else if (consumeIf(FIRToken::kw_false))
2138 return emitError(
"expected true or false in Bool expression");
2139 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2141 auto attr = builder.getBoolAttr(value);
2142 result = moduleContext.getCachedConstant<BoolConstantOp>(
2143 builder, attr, builder.getType<BoolType>(), value);
2146 case FIRToken::kw_Double: {
2149 locationProcessor.setLoc(getToken().getLoc());
2150 consumeToken(FIRToken::kw_Double);
2151 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2153 auto spelling = getTokenSpelling();
2154 if (parseToken(FIRToken::floatingpoint,
2155 "expected floating point in Double expression") ||
2156 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2161 if (!llvm::to_float(spelling, d))
2162 return emitError(
"invalid double");
2163 auto attr = builder.getF64FloatAttr(d);
2164 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2165 builder, attr, builder.getType<DoubleType>(), attr);
2168 case FIRToken::kw_List: {
2169 if (requireFeature({4, 0, 0},
"Lists"))
2172 return emitError(
"unexpected List<>() as start of statement");
2173 if (parseListExp(result))
2178 case FIRToken::lp_list_concat: {
2180 return emitError(
"unexpected list_create() as start of statement");
2181 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2186 case FIRToken::lp_path:
2188 return emitError(
"unexpected path() as start of statement");
2193 case FIRToken::lp_intrinsic:
2194 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2195 parseIntrinsicExp(result))
2201 case FIRToken::identifier:
2202 case FIRToken::literal_identifier:
2205 auto loc = getToken().getLoc();
2207 if (parseId(name, message) ||
2208 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2212 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2215 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2220 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2221 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2222 parseOptionalInfo())
2225 locationProcessor.setLoc(loc);
2227 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2229 moduleContext.getUnbundledEntry(unbundledId);
2230 for (
auto elt : ubEntry)
2231 emitInvalidate(elt.second);
2239 StringRef fieldName;
2240 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2241 parseFieldId(fieldName,
"expected field name") ||
2242 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2250 case FIRToken::lp_shr:
2253 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2254 result = builder.create<PadPrimOp>(result, 1);
2260 return parseOptionalExpPostscript(result);
2270ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2271 bool allowDynamic) {
2276 if (consumeIf(FIRToken::period)) {
2277 if (parsePostFixFieldId(result))
2284 if (consumeIf(FIRToken::l_square)) {
2285 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2286 if (parsePostFixIntSubscript(result))
2291 return emitError(
"subaccess not allowed here");
2292 if (parsePostFixDynamicSubscript(result))
2302template <
typename subop>
2304FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2306 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2312 auto baseType = cast<FIRRTLType>(base.getType());
2313 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2316 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2322 locationProcessor.setLoc(loc);
2323 OpBuilder::InsertionGuard guard(builder);
2324 builder.setInsertionPointAfterValue(base);
2325 auto op = builder.create<subop>(resultType, base, indexNo);
2328 return value = op.getResult();
2335ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2336 auto loc = getToken().getLoc();
2337 SmallVector<StringRef, 3> fields;
2338 if (parseFieldIdSeq(fields,
"expected field name"))
2340 for (
auto fieldName : fields) {
2341 std::optional<unsigned> indexV;
2342 auto type = result.getType();
2343 if (
auto refTy = type_dyn_cast<RefType>(type))
2344 type = refTy.getType();
2345 if (
auto bundle = type_dyn_cast<BundleType>(type))
2346 indexV = bundle.getElementIndex(fieldName);
2347 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2348 indexV = bundle.getElementIndex(fieldName);
2349 else if (
auto klass = type_dyn_cast<ClassType>(type))
2350 indexV = klass.getElementIndex(fieldName);
2352 return emitError(loc,
"subfield requires bundle or object operand ");
2354 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2355 << result.getType();
2356 auto indexNo = *indexV;
2358 FailureOr<Value> subResult;
2359 if (type_isa<RefType>(result.getType()))
2360 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2361 else if (type_isa<ClassType>(type))
2362 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2363 else if (type_isa<BundleType>(type))
2364 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2366 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2368 if (failed(subResult))
2370 result = *subResult;
2379ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2380 auto loc = getToken().getLoc();
2382 if (parseIntLit(indexNo,
"expected index") ||
2383 parseToken(FIRToken::r_square,
"expected ']'"))
2387 return emitError(loc,
"invalid index specifier"), failure();
2389 FailureOr<Value> subResult;
2390 if (type_isa<RefType>(result.getType()))
2391 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2392 else if (type_isa<FVectorType>(result.getType()))
2393 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2395 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2397 if (failed(subResult))
2399 result = *subResult;
2407ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2408 auto loc = getToken().getLoc();
2410 if (parseExp(index,
"expected subscript index expression") ||
2411 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2415 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2417 return emitError(
"expected base type for index expression");
2418 indexType = indexType.getPassiveType();
2419 locationProcessor.setLoc(loc);
2424 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2427 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2428 translateLocation(loc));
2433 auto op = builder.create<SubaccessOp>(resultType, result, index);
2434 result = op.getResult();
2440ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2441 bool isSigned = getToken().is(FIRToken::kw_SInt);
2442 auto loc = getToken().getLoc();
2448 if (parseOptionalWidth(width) ||
2449 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2450 parseIntLit(value,
"expected integer value") ||
2451 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2456 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2458 IntegerType::SignednessSemantics signedness =
2459 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2461 if (!value.isZero())
2462 return emitError(loc,
"zero bit constant must be zero");
2463 value = value.trunc(0);
2464 }
else if (width != -1) {
2466 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2468 return emitError(loc,
"initializer too wide for declared width");
2469 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2473 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2474 auto attr = builder.getIntegerAttr(attrType, value);
2477 auto &entry = moduleContext.constantCache[{attr, type}];
2484 locationProcessor.setLoc(loc);
2485 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2490ParseResult FIRStmtParser::parseListExp(Value &result) {
2491 auto loc = getToken().getLoc();
2493 if (parseListType(type))
2495 auto listType = type_cast<ListType>(type);
2498 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2501 SmallVector<Value, 3> operands;
2502 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2504 locationProcessor.setLoc(loc);
2505 if (parseExp(operand,
"expected expression in List expression"))
2509 if (!isa<AnyRefType>(elementType) ||
2510 !isa<ClassType>(operand.getType()))
2511 return emitError(loc,
"unexpected expression of type ")
2512 << operand.getType() <<
" in List expression of type "
2514 operand = builder.create<ObjectAnyRefCastOp>(operand);
2517 operands.push_back(operand);
2522 locationProcessor.setLoc(loc);
2523 result = builder.create<ListCreateOp>(listType, operands);
2528ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2529 consumeToken(FIRToken::lp_list_concat);
2531 auto loc = getToken().getLoc();
2533 SmallVector<Value, 3> operands;
2534 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2536 locationProcessor.setLoc(loc);
2537 if (parseExp(operand,
"expected expression in List concat expression"))
2540 if (!type_isa<ListType>(operand.getType()))
2541 return emitError(loc,
"unexpected expression of type ")
2542 << operand.getType() <<
" in List concat expression";
2545 type = type_cast<ListType>(operand.getType());
2547 if (operand.getType() != type)
2548 return emitError(loc,
"unexpected expression of type ")
2549 << operand.getType() <<
" in List concat expression of type "
2552 operands.push_back(operand);
2557 if (operands.empty())
2558 return emitError(loc,
"need at least one List to concatenate");
2560 locationProcessor.setLoc(loc);
2561 result = builder.create<ListConcatOp>(type, operands);
2582std::optional<ParseResult>
2583FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2584 switch (getToken().getKind()) {
2587 return std::nullopt;
2589 case FIRToken::period:
2590 case FIRToken::l_square:
2591 case FIRToken::kw_is:
2592 case FIRToken::less_equal:
2598 auto loc = keyword.
getLoc();
2600 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2601 return ParseResult(failure());
2607 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2610 if (!consumeIf(FIRToken::period))
2611 return ParseResult(failure());
2613 StringRef fieldName;
2614 if (parseFieldId(fieldName,
"expected field name") ||
2615 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2616 return ParseResult(failure());
2620 if (parseOptionalExpPostscript(lhs))
2621 return ParseResult(failure());
2623 return parseLeadingExpStmt(lhs);
2629ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2632 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2635 auto subIndent = getIndentation();
2636 if (!subIndent.has_value())
2637 return emitError(
"expected statement to be on its own line"), failure();
2639 if (*subIndent <= indent)
2643 if (parseSimpleStmt(*subIndent))
2648ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2649 locationProcessor.startStatement();
2650 auto result = parseSimpleStmtImpl(stmtIndent);
2651 locationProcessor.endStatement(*
this);
2673ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2674 auto kind = getToken().getKind();
2677 case FIRToken::kw_invalidate:
2678 case FIRToken::kw_connect:
2679 case FIRToken::kw_regreset:
2683 kind = FIRToken::identifier;
2690 case FIRToken::kw_attach:
2691 return parseAttach();
2692 case FIRToken::kw_infer:
2693 return parseMemPort(MemDirAttr::Infer);
2694 case FIRToken::kw_read:
2695 return parseMemPort(MemDirAttr::Read);
2696 case FIRToken::kw_write:
2697 return parseMemPort(MemDirAttr::Write);
2698 case FIRToken::kw_rdwr:
2699 return parseMemPort(MemDirAttr::ReadWrite);
2700 case FIRToken::kw_connect:
2701 return parseConnect();
2702 case FIRToken::kw_propassign:
2703 if (requireFeature({3, 1, 0},
"properties"))
2705 return parsePropAssign();
2706 case FIRToken::kw_invalidate:
2707 return parseInvalidate();
2708 case FIRToken::lp_printf:
2709 return parsePrintf();
2710 case FIRToken::kw_skip:
2712 case FIRToken::lp_stop:
2714 case FIRToken::lp_assert:
2715 return parseAssert();
2716 case FIRToken::lp_assume:
2717 return parseAssume();
2718 case FIRToken::lp_cover:
2719 return parseCover();
2720 case FIRToken::kw_when:
2721 return parseWhen(stmtIndent);
2722 case FIRToken::kw_match:
2723 return parseMatch(stmtIndent);
2724 case FIRToken::kw_define:
2725 return parseRefDefine();
2726 case FIRToken::lp_force:
2727 return parseRefForce();
2728 case FIRToken::lp_force_initial:
2729 return parseRefForceInitial();
2730 case FIRToken::lp_release:
2731 return parseRefRelease();
2732 case FIRToken::lp_release_initial:
2733 return parseRefReleaseInitial();
2734 case FIRToken::kw_group:
2735 if (requireFeature({3, 2, 0},
"optional groups") ||
2736 removedFeature({3, 3, 0},
"optional groups"))
2738 return parseLayerBlockOrGroup(stmtIndent);
2739 case FIRToken::kw_layerblock:
2740 if (requireFeature({3, 3, 0},
"layers"))
2742 return parseLayerBlockOrGroup(stmtIndent);
2743 case FIRToken::lp_intrinsic:
2744 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2746 return parseIntrinsicStmt();
2750 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2757 return parseLeadingExpStmt(lhs);
2761 case FIRToken::kw_inst:
2762 return parseInstance();
2763 case FIRToken::kw_instchoice:
2764 return parseInstanceChoice();
2765 case FIRToken::kw_object:
2766 return parseObject();
2767 case FIRToken::kw_cmem:
2768 return parseCombMem();
2769 case FIRToken::kw_smem:
2770 return parseSeqMem();
2771 case FIRToken::kw_mem:
2772 return parseMem(stmtIndent);
2773 case FIRToken::kw_node:
2775 case FIRToken::kw_wire:
2777 case FIRToken::kw_reg:
2778 return parseRegister(stmtIndent);
2779 case FIRToken::kw_regreset:
2780 return parseRegisterWithReset();
2781 case FIRToken::kw_contract:
2782 return parseContract(stmtIndent);
2786ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2788 SymbolRefAttr layerSym) {
2790 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2791 moduleContext, &blockToInsertInto);
2796 UnbundledValueRestorer x(moduleContext.unbundledValues);
2800 auto subParser = std::make_unique<FIRStmtParser>(
2801 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
2805 auto stmtIndent = getIndentation();
2808 if (!stmtIndent.has_value())
2809 return subParser->parseSimpleStmt(indent);
2811 if (*stmtIndent <= indent)
2812 return emitError(
"statement must be indented more than previous statement"),
2816 return subParser->parseSimpleStmtBlock(indent);
2820ParseResult FIRStmtParser::parseAttach() {
2821 auto startTok = consumeToken(FIRToken::kw_attach);
2824 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2827 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
2830 SmallVector<Value, 4> operands;
2831 operands.push_back({});
2832 if (parseExp(operands.back(),
"expected operand in attach"))
2835 while (consumeIf(FIRToken::comma)) {
2836 operands.push_back({});
2837 if (parseExp(operands.back(),
"expected operand in attach"))
2840 if (parseToken(FIRToken::r_paren,
"expected close paren"))
2843 if (parseOptionalInfo())
2846 locationProcessor.setLoc(startTok.getLoc());
2847 builder.create<AttachOp>(operands);
2854ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
2855 auto startTok = consumeToken();
2856 auto startLoc = startTok.getLoc();
2860 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2866 Value memory, indexExp, clock;
2867 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
2868 parseId(
id,
"expected result name") ||
2869 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
2870 parseId(memName,
"expected memory name") ||
2871 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
2872 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
2873 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
2874 parseExp(indexExp,
"expected index expression") ||
2875 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
2876 parseToken(FIRToken::comma,
"expected ','") ||
2877 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
2880 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
2882 return emitError(startLoc,
2883 "memory port should have behavioral memory type");
2884 auto resultType = memVType.getElementType();
2886 ArrayAttr annotations = getConstants().emptyArrayAttr;
2887 locationProcessor.setLoc(startLoc);
2890 Value memoryPort, memoryData;
2892 OpBuilder::InsertionGuard guard(builder);
2893 builder.setInsertionPointAfterValue(memory);
2894 auto memoryPortOp = builder.create<MemoryPortOp>(
2895 resultType, CMemoryPortType::get(getContext()), memory, direction, id,
2897 memoryData = memoryPortOp.getResult(0);
2898 memoryPort = memoryPortOp.getResult(1);
2902 builder.create<MemoryPortAccessOp>(memoryPort, indexExp, clock);
2904 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
2908ParseResult FIRStmtParser::parsePrintf() {
2909 auto startTok = consumeToken(FIRToken::lp_printf);
2911 Value clock, condition;
2912 StringRef formatString;
2913 if (parseExp(clock,
"expected clock expression in printf") ||
2914 parseToken(FIRToken::comma,
"expected ','") ||
2915 parseExp(condition,
"expected condition in printf") ||
2916 parseToken(FIRToken::comma,
"expected ','") ||
2917 parseGetSpelling(formatString) ||
2918 parseToken(FIRToken::string,
"expected format string in printf"))
2921 SmallVector<Value, 4> operands;
2922 while (consumeIf(FIRToken::comma)) {
2923 operands.push_back({});
2924 if (parseExp(operands.back(),
"expected operand in printf"))
2927 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2931 if (parseOptionalName(name))
2934 if (parseOptionalInfo())
2937 locationProcessor.setLoc(startTok.getLoc());
2940 builder.create<PrintFOp>(clock, condition,
2941 builder.getStringAttr(formatStrUnescaped), operands,
2947ParseResult FIRStmtParser::parseSkip() {
2948 auto startTok = consumeToken(FIRToken::kw_skip);
2952 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2955 if (parseOptionalInfo())
2958 locationProcessor.setLoc(startTok.getLoc());
2959 builder.create<SkipOp>();
2964ParseResult FIRStmtParser::parseStop() {
2965 auto startTok = consumeToken(FIRToken::lp_stop);
2967 Value clock, condition;
2970 if (parseExp(clock,
"expected clock expression in 'stop'") ||
2971 parseToken(FIRToken::comma,
"expected ','") ||
2972 parseExp(condition,
"expected condition in 'stop'") ||
2973 parseToken(FIRToken::comma,
"expected ','") ||
2974 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
2975 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
2976 parseOptionalName(name) || parseOptionalInfo())
2979 locationProcessor.setLoc(startTok.getLoc());
2980 builder.create<StopOp>(clock, condition, builder.getI32IntegerAttr(exitCode),
2986ParseResult FIRStmtParser::parseAssert() {
2987 auto startTok = consumeToken(FIRToken::lp_assert);
2989 Value clock, predicate, enable;
2990 StringRef formatString;
2992 if (parseExp(clock,
"expected clock expression in 'assert'") ||
2993 parseToken(FIRToken::comma,
"expected ','") ||
2994 parseExp(predicate,
"expected predicate in 'assert'") ||
2995 parseToken(FIRToken::comma,
"expected ','") ||
2996 parseExp(enable,
"expected enable in 'assert'") ||
2997 parseToken(FIRToken::comma,
"expected ','") ||
2998 parseGetSpelling(formatString) ||
2999 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3002 SmallVector<Value, 4> operands;
3003 while (!consumeIf(FIRToken::r_paren)) {
3004 operands.push_back({});
3005 if (parseToken(FIRToken::comma,
"expected ','") ||
3006 parseExp(operands.back(),
"expected operand in 'assert'"))
3010 if (parseOptionalName(name) || parseOptionalInfo())
3013 locationProcessor.setLoc(startTok.getLoc());
3015 builder.create<AssertOp>(clock, predicate, enable, formatStrUnescaped,
3016 operands, name.getValue());
3021ParseResult FIRStmtParser::parseAssume() {
3022 auto startTok = consumeToken(FIRToken::lp_assume);
3024 Value clock, predicate, enable;
3025 StringRef formatString;
3027 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3028 parseToken(FIRToken::comma,
"expected ','") ||
3029 parseExp(predicate,
"expected predicate in 'assume'") ||
3030 parseToken(FIRToken::comma,
"expected ','") ||
3031 parseExp(enable,
"expected enable in 'assume'") ||
3032 parseToken(FIRToken::comma,
"expected ','") ||
3033 parseGetSpelling(formatString) ||
3034 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3037 SmallVector<Value, 4> operands;
3038 while (!consumeIf(FIRToken::r_paren)) {
3039 operands.push_back({});
3040 if (parseToken(FIRToken::comma,
"expected ','") ||
3041 parseExp(operands.back(),
"expected operand in 'assume'"))
3045 if (parseOptionalName(name) || parseOptionalInfo())
3048 locationProcessor.setLoc(startTok.getLoc());
3050 builder.create<AssumeOp>(clock, predicate, enable, formatStrUnescaped,
3051 operands, name.getValue());
3056ParseResult FIRStmtParser::parseCover() {
3057 auto startTok = consumeToken(FIRToken::lp_cover);
3059 Value clock, predicate, enable;
3062 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3063 parseToken(FIRToken::comma,
"expected ','") ||
3064 parseExp(predicate,
"expected predicate in 'cover'") ||
3065 parseToken(FIRToken::comma,
"expected ','") ||
3066 parseExp(enable,
"expected enable in 'cover'") ||
3067 parseToken(FIRToken::comma,
"expected ','") ||
3068 parseGetSpelling(message) ||
3069 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3070 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3071 parseOptionalName(name) || parseOptionalInfo())
3074 locationProcessor.setLoc(startTok.getLoc());
3076 builder.create<CoverOp>(clock, predicate, enable, messageUnescaped,
3077 ValueRange{}, name.getValue());
3083ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3084 auto startTok = consumeToken(FIRToken::kw_when);
3088 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3092 if (parseExp(condition,
"expected condition in 'when'") ||
3093 parseToken(FIRToken::colon,
"expected ':' in when") ||
3094 parseOptionalInfo())
3097 locationProcessor.setLoc(startTok.getLoc());
3099 auto whenStmt = builder.create<WhenOp>(condition,
false);
3102 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3106 if (getToken().isNot(FIRToken::kw_else))
3111 auto elseIndent = getIndentation();
3112 if (elseIndent && *elseIndent < whenIndent)
3115 consumeToken(FIRToken::kw_else);
3118 whenStmt.createElseRegion();
3124 if (getToken().is(FIRToken::kw_when)) {
3126 auto subParser = std::make_unique<FIRStmtParser>(
3127 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3130 return subParser->parseSimpleStmt(whenIndent);
3134 LocationAttr elseLoc;
3135 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3136 parseOptionalInfoLocator(elseLoc) ||
3137 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3146ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3147 auto startLoc = getToken().getLoc();
3148 locationProcessor.setLoc(startLoc);
3150 if (parseEnumType(type))
3154 auto enumType = type_dyn_cast<FEnumType>(type);
3156 return emitError(startLoc,
3157 "expected enumeration type in enumeration expression");
3160 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3161 parseId(tag,
"expected enumeration tag"))
3165 if (consumeIf(FIRToken::r_paren)) {
3168 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3169 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3170 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3171 input = builder.create<ConstantOp>(type, attr);
3174 if (parseToken(FIRToken::comma,
"expected ','") ||
3175 parseExp(input,
"expected expression in enumeration value") ||
3176 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3180 value = builder.create<FEnumCreateOp>(enumType, tag, input);
3188ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3189 auto startTok = consumeToken(FIRToken::kw_match);
3191 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3195 if (parseExp(input,
"expected expression in 'match'") ||
3196 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3197 parseOptionalInfo())
3200 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3202 return mlir::emitError(
3204 "expected enumeration type for 'match' statement, but got ")
3207 locationProcessor.setLoc(startTok.getLoc());
3209 SmallVector<Attribute> tags;
3210 SmallVector<std::unique_ptr<Region>> regions;
3212 auto tagLoc = getToken().getLoc();
3215 auto caseIndent = getIndentation();
3216 if (!caseIndent || *caseIndent <= matchIndent)
3220 StringRef tagSpelling;
3221 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3223 auto tagIndex = enumType.getElementIndex(tagSpelling);
3225 return emitError(tagLoc,
"tag ")
3226 << tagSpelling <<
" not a member of enumeration " << enumType;
3227 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3228 tags.push_back(tag);
3231 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3234 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3239 UnbundledValueRestorer x(moduleContext.unbundledValues);
3242 if (consumeIf(FIRToken::l_paren)) {
3243 StringAttr identifier;
3244 if (parseId(identifier,
"expected identifier for 'case' binding"))
3248 auto dataType = enumType.getElementType(*tagIndex);
3249 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3251 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3255 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3259 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3260 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).getLoc());
3263 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3267 auto subParser = std::make_unique<FIRStmtParser>(
3268 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3270 if (subParser->parseSimpleStmtBlock(*caseIndent))
3274 builder.create<MatchOp>(input, ArrayAttr::get(getContext(), tags), regions);
3280ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3281 auto token = getToken().getKind();
3282 if (token == FIRToken::lp_probe)
3283 return parseProbe(result);
3284 if (token == FIRToken::lp_rwprobe)
3285 return parseRWProbe(result);
3290 return parseStaticRefExp(result, message);
3297ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3298 const Twine &message) {
3299 auto parseIdOrInstance = [&]() -> ParseResult {
3301 auto loc = getToken().getLoc();
3303 if (parseId(
id, message) ||
3304 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3308 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3311 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3314 StringRef fieldName;
3316 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3317 parseFieldId(fieldName,
"expected field name") ||
3318 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3320 return failure(parseIdOrInstance() ||
3321 parseOptionalExpPostscript(result,
false));
3332ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3334 const Twine &message) {
3335 auto loc = getToken().getLoc();
3339 if (parseId(
id, message) ||
3340 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3352 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3354 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3356 StringRef fieldName;
3357 auto loc = getToken().getLoc();
3358 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3359 parseFieldId(fieldName,
"expected field name"))
3364 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3365 for (
auto &elt : ubEntry) {
3366 if (elt.first == fieldAttr) {
3369 auto &instResult = elt.second;
3372 auto *defining = instResult.getDefiningOp();
3374 if (isa<WireOp>(defining)) {
3375 result = instResult;
3380 auto type = instResult.getType();
3384 bool forceable =
static_cast<bool>(
3387 return emitError(loc,
"unable to force instance result of type ")
3391 auto annotations = getConstants().emptyArrayAttr;
3392 StringAttr sym = {};
3393 SmallString<64> name;
3394 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3395 locationProcessor.setLoc(loc);
3396 OpBuilder::InsertionGuard guard(builder);
3397 builder.setInsertionPoint(defining);
3398 auto bounce = builder.create<WireOp>(
3399 type, name, NameKindEnum::InterestingName, annotations, sym);
3400 auto bounceVal = bounce.getData();
3403 instResult.replaceAllUsesWith(bounceVal);
3406 builder.setInsertionPointAfter(defining);
3407 if (
foldFlow(instResult) == Flow::Source)
3414 result = instResult = bounce.getDataRaw();
3420 emitError(loc,
"use of invalid field name '")
3421 << fieldName <<
"' on bundle value";
3426 result = cast<Value>(symtabEntry);
3430 assert(isa<BlockArgument>(result) ||
3431 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3437 type = result.getType();
3439 if (consumeIf(FIRToken::period)) {
3440 SmallVector<StringRef, 3> fields;
3441 if (parseFieldIdSeq(fields,
"expected field name"))
3443 for (
auto fieldName : fields) {
3444 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3445 if (
auto index = bundle.getElementIndex(fieldName)) {
3446 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3447 type = bundle.getElementTypePreservingConst(*index);
3450 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3451 if (
auto index = bundle.getElementIndex(fieldName)) {
3452 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3453 type = bundle.getElementTypePreservingConst(*index);
3457 return emitError(loc,
"subfield requires bundle operand")
3458 <<
"got " << type <<
"\n";
3460 return emitError(loc,
3461 "unknown field '" + fieldName +
"' in bundle type ")
3466 if (consumeIf(FIRToken::l_square)) {
3467 auto loc = getToken().
getLoc();
3469 if (parseIntLit(index,
"expected index") ||
3470 parseToken(FIRToken::r_square,
"expected ']'"))
3474 return emitError(loc,
"invalid index specifier");
3476 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3477 if ((
unsigned)index < vector.getNumElements()) {
3478 refResult = refResult.
getSubField(vector.getFieldID(index));
3479 type = vector.getElementTypePreservingConst();
3482 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3483 if ((
unsigned)index < vector.getNumElements()) {
3484 refResult = refResult.
getSubField(vector.getFieldID(index));
3485 type = vector.getElementTypePreservingConst();
3489 return emitError(loc,
"subindex requires vector operand");
3491 return emitError(loc,
"out of range index '")
3492 << index <<
"' for vector type " << type;
3500ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3501 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3502 StringRef intrinsic;
3503 ArrayAttr parameters;
3506 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3507 parseOptionalParams(parameters))
3510 if (consumeIf(FIRToken::colon)) {
3511 if (
parseType(type,
"expected intrinsic return type"))
3513 }
else if (!isStatement)
3514 return emitError(
"expected ':' in intrinsic expression");
3516 SmallVector<Value> operands;
3517 auto loc = startTok.getLoc();
3518 if (consumeIf(FIRToken::comma)) {
3519 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3521 if (parseExp(operand,
"expected operand in intrinsic"))
3523 operands.push_back(operand);
3524 locationProcessor.setLoc(loc);
3529 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3534 if (parseOptionalInfo())
3537 locationProcessor.setLoc(loc);
3539 auto op = builder.create<GenericIntrinsicOp>(
3540 type, builder.getStringAttr(intrinsic), operands, parameters);
3542 result = op.getResult();
3547ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3548 if (!consumeIf(FIRToken::less))
3551 SmallVector<Attribute, 8> parameters;
3552 SmallPtrSet<StringAttr, 8> seen;
3553 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3557 if (parseParameter(name, value, loc))
3559 auto typedValue = dyn_cast<TypedAttr>(value);
3561 return emitError(loc)
3562 <<
"invalid value for parameter '" << name.getValue() <<
"'";
3563 if (!seen.insert(name).second)
3564 return emitError(loc,
"redefinition of parameter '" +
3565 name.getValue() +
"'");
3566 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3571 resultParameters = ArrayAttr::get(getContext(), parameters);
3577ParseResult FIRStmtParser::parsePathExp(Value &result) {
3578 auto startTok = consumeToken(FIRToken::lp_path);
3579 locationProcessor.setLoc(startTok.getLoc());
3581 if (parseGetSpelling(target) ||
3582 parseToken(FIRToken::string,
3583 "expected target string in path expression") ||
3584 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3586 result = builder.create<UnresolvedPathOp>(
3592ParseResult FIRStmtParser::parseRefDefine() {
3593 auto startTok = consumeToken(FIRToken::kw_define);
3596 if (parseStaticRefExp(target,
3597 "expected static reference expression in 'define'") ||
3598 parseToken(FIRToken::equal,
3599 "expected '=' after define reference expression") ||
3600 parseRefExp(src,
"expected reference expression in 'define'") ||
3601 parseOptionalInfo())
3605 if (!type_isa<RefType>(target.getType()))
3606 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3607 "'define' target (LHS), got ")
3608 << target.getType();
3609 if (!type_isa<RefType>(src.getType()))
3610 return emitError(startTok.getLoc(),
"expected reference-type expression in "
3611 "'define' source (RHS), got ")
3616 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
3617 return emitError(startTok.getLoc(),
3618 "cannot define into a sub-element of a reference");
3620 locationProcessor.setLoc(startTok.getLoc());
3623 return emitError(startTok.getLoc(),
"cannot define reference of type ")
3624 << target.getType() <<
" with incompatible reference of type "
3634ParseResult FIRStmtParser::parseRefRead(Value &result) {
3635 auto startTok = consumeToken(FIRToken::lp_read);
3638 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
3639 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
3642 locationProcessor.setLoc(startTok.getLoc());
3645 if (!type_isa<RefType>(ref.getType()))
3646 return emitError(startTok.getLoc(),
3647 "expected reference-type expression in 'read', got ")
3650 result = builder.create<RefResolveOp>(ref);
3656ParseResult FIRStmtParser::parseProbe(Value &result) {
3657 auto startTok = consumeToken(FIRToken::lp_probe);
3660 if (parseStaticRefExp(staticRef,
3661 "expected static reference expression in 'probe'") ||
3662 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
3665 locationProcessor.setLoc(startTok.getLoc());
3668 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
3669 return emitError(startTok.getLoc(),
3670 "expected base-type expression in 'probe', got ")
3671 << staticRef.getType();
3675 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3676 MemoryDebugPortOp, MemoryPortAccessOp>(
3677 staticRef.getDefiningOp()))
3678 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3680 result = builder.create<RefSendOp>(staticRef);
3686ParseResult FIRStmtParser::parseRWProbe(Value &result) {
3687 auto startTok = consumeToken(FIRToken::lp_rwprobe);
3690 Type parsedTargetType;
3691 if (parseRWProbeStaticRefExp(
3692 staticRef, parsedTargetType,
3693 "expected static reference expression in 'rwprobe'") ||
3694 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
3697 locationProcessor.setLoc(startTok.getLoc());
3703 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
3705 return emitError(startTok.getLoc(),
3706 "expected base-type expression in 'rwprobe', got ")
3707 << parsedTargetType;
3710 auto *definingOp = root.getDefiningOp();
3712 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
3713 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
3714 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
3718 return emitError(startTok.getLoc(),
"cannot force target of type ")
3722 auto op = builder.create<RWProbeOp>(forceableType,
3723 getConstants().placeholderInnerRef);
3730ParseResult FIRStmtParser::parseRefForce() {
3731 auto startTok = consumeToken(FIRToken::lp_force);
3733 Value clock, pred, dest, src;
3734 if (parseExp(clock,
"expected clock expression in force") ||
3735 parseToken(FIRToken::comma,
"expected ','") ||
3736 parseExp(pred,
"expected predicate expression in force") ||
3737 parseToken(FIRToken::comma,
"expected ','") ||
3738 parseRefExp(dest,
"expected destination reference expression in force") ||
3739 parseToken(FIRToken::comma,
"expected ','") ||
3740 parseExp(src,
"expected source expression in force") ||
3741 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
3742 parseOptionalInfo())
3746 auto ref = type_dyn_cast<RefType>(dest.getType());
3747 if (!ref || !ref.getForceable())
3750 "expected rwprobe-type expression for force destination, got ")
3752 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3754 return emitError(startTok.getLoc(),
3755 "expected base-type for force source, got ")
3757 if (!srcBaseType.isPassive())
3758 return emitError(startTok.getLoc(),
3759 "expected passive value for force source, got ")
3762 locationProcessor.setLoc(startTok.getLoc());
3765 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3766 if (noConstSrcType != ref.getType()) {
3768 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
3770 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3772 return emitError(startTok.getLoc(),
"incompatible force source of type ")
3773 << src.getType() <<
" cannot target destination "
3777 builder.create<RefForceOp>(clock, pred, dest, src);
3783ParseResult FIRStmtParser::parseRefForceInitial() {
3784 auto startTok = consumeToken(FIRToken::lp_force_initial);
3788 dest,
"expected destination reference expression in force_initial") ||
3789 parseToken(FIRToken::comma,
"expected ','") ||
3790 parseExp(src,
"expected source expression in force_initial") ||
3791 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
3792 parseOptionalInfo())
3796 auto ref = type_dyn_cast<RefType>(dest.getType());
3797 if (!ref || !ref.getForceable())
3798 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3799 "force_initial destination, got ")
3801 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3803 return emitError(startTok.getLoc(),
3804 "expected base-type expression for force_initial "
3807 if (!srcBaseType.isPassive())
3808 return emitError(startTok.getLoc(),
3809 "expected passive value for force_initial source, got ")
3812 locationProcessor.setLoc(startTok.getLoc());
3815 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
3816 if (noConstSrcType != ref.getType()) {
3818 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
3820 dest = builder.create<RefCastOp>(compatibleRWProbe, dest);
3822 return emitError(startTok.getLoc(),
3823 "incompatible force_initial source of type ")
3824 << src.getType() <<
" cannot target destination "
3828 auto value = APInt::getAllOnes(1);
3829 auto type = UIntType::get(builder.getContext(), 1);
3830 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
3831 value.getBitWidth(),
3832 IntegerType::Unsigned),
3834 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
3835 builder.create<RefForceInitialOp>(pred, dest, src);
3841ParseResult FIRStmtParser::parseRefRelease() {
3842 auto startTok = consumeToken(FIRToken::lp_release);
3844 Value clock, pred, dest;
3845 if (parseExp(clock,
"expected clock expression in release") ||
3846 parseToken(FIRToken::comma,
"expected ','") ||
3847 parseExp(pred,
"expected predicate expression in release") ||
3848 parseToken(FIRToken::comma,
"expected ','") ||
3850 "expected destination reference expression in release") ||
3851 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
3852 parseOptionalInfo())
3856 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3857 !ref || !ref.getForceable())
3860 "expected rwprobe-type expression for release destination, got ")
3863 locationProcessor.setLoc(startTok.getLoc());
3865 builder.create<RefReleaseOp>(clock, pred, dest);
3871ParseResult FIRStmtParser::parseRefReleaseInitial() {
3872 auto startTok = consumeToken(FIRToken::lp_release_initial);
3877 "expected destination reference expression in release_initial") ||
3878 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
3879 parseOptionalInfo())
3883 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
3884 !ref || !ref.getForceable())
3885 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
3886 "release_initial destination, got ")
3889 locationProcessor.setLoc(startTok.getLoc());
3891 auto value = APInt::getAllOnes(1);
3892 auto type = UIntType::get(builder.getContext(), 1);
3893 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
3894 value.getBitWidth(),
3895 IntegerType::Unsigned),
3897 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
3898 builder.create<RefReleaseInitialOp>(pred, dest);
3904ParseResult FIRStmtParser::parseConnect() {
3905 auto startTok = consumeToken(FIRToken::kw_connect);
3906 auto loc = startTok.getLoc();
3909 if (parseExp(lhs,
"expected connect expression") ||
3910 parseToken(FIRToken::comma,
"expected ','") ||
3911 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
3914 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
3915 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
3916 if (!lhsType || !rhsType)
3917 return emitError(loc,
"cannot connect reference or property types");
3919 if (lhsType.containsReference() || rhsType.containsReference())
3920 return emitError(loc,
"cannot connect types containing references");
3923 return emitError(loc,
"cannot connect non-equivalent type ")
3924 << rhsType <<
" to " << lhsType;
3926 locationProcessor.setLoc(loc);
3932ParseResult FIRStmtParser::parsePropAssign() {
3933 auto startTok = consumeToken(FIRToken::kw_propassign);
3934 auto loc = startTok.getLoc();
3937 if (parseExp(lhs,
"expected propassign expression") ||
3938 parseToken(FIRToken::comma,
"expected ','") ||
3939 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
3942 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
3943 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
3944 if (!lhsType || !rhsType)
3945 return emitError(loc,
"can only propassign property types");
3946 locationProcessor.setLoc(loc);
3947 if (lhsType != rhsType) {
3949 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
3950 rhs = builder.create<ObjectAnyRefCastOp>(rhs);
3952 return emitError(loc,
"cannot propassign non-equivalent type ")
3953 << rhsType <<
" to " << lhsType;
3955 builder.create<PropAssignOp>(lhs, rhs);
3960ParseResult FIRStmtParser::parseInvalidate() {
3961 auto startTok = consumeToken(FIRToken::kw_invalidate);
3966 auto loc = getToken().getLoc();
3968 if (parseId(
id,
"expected static reference expression") ||
3969 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3974 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
3975 if (parseOptionalExpPostscript(lhs,
false) ||
3976 parseOptionalInfo())
3979 locationProcessor.setLoc(startTok.getLoc());
3980 emitInvalidate(lhs);
3987 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3989 if (getToken().isNot(FIRToken::period)) {
3990 locationProcessor.setLoc(loc);
3992 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
3994 for (
auto elt : ubEntry)
3995 emitInvalidate(elt.second);
4001 StringRef fieldName;
4002 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4003 parseFieldId(fieldName,
"expected field name") ||
4004 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4008 if (parseOptionalExpPostscript(lhs,
false) ||
4009 parseOptionalInfo())
4012 locationProcessor.setLoc(startTok.getLoc());
4013 emitInvalidate(lhs);
4017ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4019 auto startTok = consumeToken();
4020 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4021 "consumed an unexpected token");
4022 auto loc = startTok.getLoc();
4025 if (parseId(
id,
"expected layer identifer") ||
4026 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4027 parseOptionalInfo())
4030 locationProcessor.setLoc(loc);
4032 StringRef rootLayer;
4033 SmallVector<FlatSymbolRefAttr> nestedLayers;
4037 rootLayer = layerSym.getRootReference();
4038 auto nestedRefs = layerSym.getNestedReferences();
4039 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4040 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4043 auto layerBlockOp = builder.create<LayerBlockOp>(
4044 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4045 layerBlockOp->getRegion(0).push_back(
new Block());
4047 if (getIndentation() > indent)
4048 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4049 layerBlockOp.getLayerName()))
4057ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4058 auto loc = getToken().getLoc();
4061 if (consumeIf(FIRToken::kw_is)) {
4062 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4063 parseOptionalInfo())
4066 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4069 locationProcessor.setLoc(loc);
4070 emitInvalidate(lhs);
4074 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4077 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4081 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4084 locationProcessor.setLoc(loc);
4086 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4087 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4088 if (!lhsType || !rhsType)
4089 return emitError(loc,
"cannot connect reference or property types");
4091 if (lhsType.containsReference() || rhsType.containsReference())
4092 return emitError(loc,
"cannot connect types containing references");
4095 return emitError(loc,
"cannot connect non-equivalent type ")
4096 << rhsType <<
" to " << lhsType;
4105ParseResult FIRStmtParser::parseInstance() {
4106 auto startTok = consumeToken(FIRToken::kw_inst);
4110 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4114 StringRef moduleName;
4115 if (parseId(
id,
"expected instance name") ||
4116 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4117 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4120 locationProcessor.setLoc(startTok.getLoc());
4123 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4124 if (!referencedModule)
4127 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4129 auto annotations = getConstants().emptyArrayAttr;
4130 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4132 hw::InnerSymAttr sym = {};
4133 auto result = builder.create<InstanceOp>(
4134 referencedModule, id, NameKindEnum::InterestingName,
4135 annotations.getValue(), portAnnotations,
false, sym);
4141 unbundledValueEntry.reserve(modulePorts.size());
4142 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4143 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4147 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4148 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4149 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4154ParseResult FIRStmtParser::parseInstanceChoice() {
4155 auto startTok = consumeToken(FIRToken::kw_instchoice);
4156 SMLoc loc = startTok.getLoc();
4159 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4166 StringRef defaultModuleName;
4167 StringRef optionGroupName;
4168 if (parseId(
id,
"expected instance name") ||
4169 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4170 parseId(defaultModuleName,
"expected module name") ||
4171 parseToken(FIRToken::comma,
"expected ','") ||
4172 parseId(optionGroupName,
"expected option group name") ||
4173 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4174 parseOptionalInfo())
4177 locationProcessor.setLoc(startTok.getLoc());
4181 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4185 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4188 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4190 return emitError(loc,
4191 "use of undefined option group '" + optionGroupName +
"'");
4193 auto baseIndent = getIndentation();
4194 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4195 while (getIndentation() == baseIndent) {
4197 StringRef caseModuleName;
4198 if (parseId(caseId,
"expected a case identifier") ||
4199 parseToken(FIRToken::equal_greater,
4200 "expected '=> in instance choice definition") ||
4201 parseId(caseModuleName,
"expected module name"))
4204 auto caseModule = getReferencedModule(loc, caseModuleName);
4208 for (
const auto &[defaultPort, casePort] :
4209 llvm::zip(modulePorts, caseModule.getPorts())) {
4210 if (defaultPort.name != casePort.name)
4211 return emitError(loc,
"instance case module port '")
4212 << casePort.name.getValue()
4213 <<
"' does not match the default module port '"
4214 << defaultPort.name.getValue() <<
"'";
4215 if (defaultPort.type != casePort.type)
4216 return emitError(loc,
"instance case port '")
4217 << casePort.name.getValue()
4218 <<
"' type does not match the default module port";
4222 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4224 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4225 caseModules.emplace_back(optionCase, caseModule);
4228 auto annotations = getConstants().emptyArrayAttr;
4229 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4233 auto result = builder.create<InstanceChoiceOp>(
4234 defaultModule, caseModules, id, NameKindEnum::InterestingName,
4235 annotations.getValue(), portAnnotations, sym);
4239 unbundledValueEntry.reserve(modulePorts.size());
4240 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4241 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4243 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4244 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4245 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4248FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4249 StringRef moduleName) {
4250 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4251 if (!referencedModule) {
4253 "use of undefined module name '" + moduleName +
"' in instance");
4256 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4257 emitError(loc,
"cannot create instance of class '" + moduleName +
4258 "', did you mean object?");
4261 return referencedModule;
4265ParseResult FIRStmtParser::parseObject() {
4266 auto startTok = consumeToken(FIRToken::kw_object);
4270 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4277 StringRef className;
4278 if (parseId(
id,
"expected object name") ||
4279 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4280 parseId(className,
"expected class name") || parseOptionalInfo())
4283 locationProcessor.setLoc(startTok.getLoc());
4286 const auto &classMap = getConstants().classMap;
4287 auto lookup = classMap.find(className);
4288 if (lookup == classMap.end())
4289 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4290 className +
"' in object");
4291 auto referencedClass = lookup->getSecond();
4292 auto result = builder.create<ObjectOp>(referencedClass, id);
4293 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4297ParseResult FIRStmtParser::parseCombMem() {
4299 auto startTok = consumeToken(FIRToken::kw_cmem);
4303 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4308 if (parseId(
id,
"expected cmem name") ||
4309 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4310 parseType(type,
"expected cmem type") || parseOptionalInfo())
4313 locationProcessor.setLoc(startTok.getLoc());
4316 auto vectorType = type_dyn_cast<FVectorType>(type);
4318 return emitError(
"cmem requires vector type");
4320 auto annotations = getConstants().emptyArrayAttr;
4321 StringAttr sym = {};
4322 auto result = builder.create<CombMemOp>(
4323 vectorType.getElementType(), vectorType.getNumElements(), id,
4324 NameKindEnum::InterestingName, annotations, sym);
4325 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4329ParseResult FIRStmtParser::parseSeqMem() {
4331 auto startTok = consumeToken(FIRToken::kw_smem);
4335 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4340 RUWAttr ruw = RUWAttr::Undefined;
4342 if (parseId(
id,
"expected smem name") ||
4343 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4347 if (consumeIf(FIRToken::comma)) {
4352 if (parseOptionalInfo()) {
4356 locationProcessor.setLoc(startTok.getLoc());
4359 auto vectorType = type_dyn_cast<FVectorType>(type);
4361 return emitError(
"smem requires vector type");
4363 auto annotations = getConstants().emptyArrayAttr;
4364 StringAttr sym = {};
4365 auto result = builder.create<SeqMemOp>(
4366 vectorType.getElementType(), vectorType.getNumElements(), ruw, id,
4367 NameKindEnum::InterestingName, annotations, sym);
4368 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4380ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4381 auto startTok = consumeToken(FIRToken::kw_mem);
4385 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4389 if (parseId(
id,
"expected mem name") ||
4390 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4394 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4395 RUWAttr ruw = RUWAttr::Undefined;
4397 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4401 auto nextIndent = getIndentation();
4402 if (!nextIndent || *nextIndent <= memIndent)
4405 auto spelling = getTokenSpelling();
4406 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4407 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4410 if (spelling ==
"data-type") {
4412 return emitError(
"'mem' type specified multiple times"), failure();
4414 if (
parseType(type,
"expected type in data-type declaration"))
4418 if (spelling ==
"depth") {
4419 if (parseIntLit(depth,
"expected integer in depth specification"))
4423 if (spelling ==
"read-latency") {
4424 if (parseIntLit(readLatency,
"expected integer latency"))
4428 if (spelling ==
"write-latency") {
4429 if (parseIntLit(writeLatency,
"expected integer latency"))
4433 if (spelling ==
"read-under-write") {
4434 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4435 FIRToken::kw_undefined))
4436 return emitError(
"expected specifier"), failure();
4438 if (parseOptionalRUW(ruw))
4443 MemOp::PortKind portKind;
4444 if (spelling ==
"reader")
4445 portKind = MemOp::PortKind::Read;
4446 else if (spelling ==
"writer")
4447 portKind = MemOp::PortKind::Write;
4448 else if (spelling ==
"readwriter")
4449 portKind = MemOp::PortKind::ReadWrite;
4451 return emitError(
"unexpected field in 'mem' declaration"), failure();
4454 if (parseId(portName,
"expected port name"))
4456 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4458 return emitError(
"unexpected type, must be base type");
4459 ports.push_back({builder.getStringAttr(portName),
4460 MemOp::getTypeForPort(depth, baseType, portKind)});
4462 while (!getIndentation().has_value()) {
4463 if (parseId(portName,
"expected port name"))
4465 ports.push_back({builder.getStringAttr(portName),
4466 MemOp::getTypeForPort(depth, baseType, portKind)});
4477 llvm::array_pod_sort(ports.begin(), ports.end(),
4478 [](
const std::pair<StringAttr, Type> *lhs,
4479 const std::pair<StringAttr, Type> *rhs) ->
int {
4480 return lhs->first.getValue().compare(
4481 rhs->first.getValue());
4484 auto annotations = getConstants().emptyArrayAttr;
4485 SmallVector<Attribute, 4> resultNames;
4486 SmallVector<Type, 4> resultTypes;
4487 SmallVector<Attribute, 4> resultAnnotations;
4488 for (
auto p : ports) {
4489 resultNames.push_back(p.first);
4490 resultTypes.push_back(p.second);
4491 resultAnnotations.push_back(annotations);
4494 locationProcessor.setLoc(startTok.getLoc());
4496 auto result = builder.create<MemOp>(
4497 resultTypes, readLatency, writeLatency, depth, ruw,
4498 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
4499 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4500 MemoryInitAttr(), StringAttr());
4503 unbundledValueEntry.reserve(result.getNumResults());
4504 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4505 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4507 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4508 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4509 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4513ParseResult FIRStmtParser::parseNode() {
4514 auto startTok = consumeToken(FIRToken::kw_node);
4518 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4523 if (parseId(
id,
"expected node name") ||
4524 parseToken(FIRToken::equal,
"expected '=' in node") ||
4525 parseExp(initializer,
"expected expression for node") ||
4526 parseOptionalInfo())
4529 locationProcessor.setLoc(startTok.getLoc());
4541 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4542 auto initializerBaseType =
4543 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4544 if (type_isa<AnalogType>(initializerType) ||
4545 !(initializerBaseType && initializerBaseType.isPassive())) {
4546 emitError(startTok.getLoc())
4547 <<
"Node cannot be analog and must be passive or passive under a flip "
4548 << initializer.getType();
4552 auto annotations = getConstants().emptyArrayAttr;
4553 StringAttr sym = {};
4555 auto result = builder.create<NodeOp>(
4556 initializer, id, NameKindEnum::InterestingName, annotations, sym);
4557 return moduleContext.addSymbolEntry(
id, result.getResult(),
4562ParseResult FIRStmtParser::parseWire() {
4563 auto startTok = consumeToken(FIRToken::kw_wire);
4567 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4572 if (parseId(
id,
"expected wire name") ||
4573 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4574 parseType(type,
"expected wire type") || parseOptionalInfo())
4577 locationProcessor.setLoc(startTok.getLoc());
4579 auto annotations = getConstants().emptyArrayAttr;
4580 StringAttr sym = {};
4583 auto namekind = isa<PropertyType, RefType>(type)
4584 ? NameKindEnum::DroppableName
4585 : NameKindEnum::InterestingName;
4587 auto result = builder.create<WireOp>(type, id, namekind, annotations, sym);
4588 return moduleContext.addSymbolEntry(
id, result.getResult(),
4602ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4603 auto startTok = consumeToken(FIRToken::kw_reg);
4607 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4616 if (parseId(
id,
"expected reg name") ||
4617 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4619 parseToken(FIRToken::comma,
"expected ','") ||
4620 parseExp(clock,
"expected expression for register clock"))
4623 if (!type_isa<FIRRTLBaseType>(type))
4624 return emitError(startTok.getLoc(),
"register must have base type");
4627 Value resetSignal, resetValue;
4628 if (consumeIf(FIRToken::kw_with)) {
4629 if (removedFeature({3, 0, 0},
"'reg with' registers"))
4632 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
4640 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
4642 auto indent = getIndentation();
4643 if (!indent || *indent <= regIndent)
4644 if (!hasExtraLParen)
4645 return emitError(
"expected indented reset specifier in reg"), failure();
4647 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
4648 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
4649 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
4650 parseExp(resetSignal,
"expected expression for reset signal") ||
4651 parseToken(FIRToken::comma,
"expected ','"))
4659 if (getTokenSpelling() ==
id) {
4661 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4663 resetSignal = Value();
4665 if (parseExp(resetValue,
"expected expression for reset value") ||
4666 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4670 if (hasExtraLParen &&
4671 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
4677 if (parseOptionalInfo())
4680 locationProcessor.setLoc(startTok.getLoc());
4682 ArrayAttr annotations = getConstants().emptyArrayAttr;
4684 StringAttr sym = {};
4688 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4689 NameKindEnum::InterestingName, annotations, sym)
4693 .create<RegOp>(type, clock, id, NameKindEnum::InterestingName,
4696 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4704ParseResult FIRStmtParser::parseRegisterWithReset() {
4705 auto startTok = consumeToken(FIRToken::kw_regreset);
4709 Value clock, resetSignal, resetValue;
4711 if (parseId(
id,
"expected reg name") ||
4712 parseToken(FIRToken::colon,
"expected ':' in reg") ||
4714 parseToken(FIRToken::comma,
"expected ','") ||
4715 parseExp(clock,
"expected expression for register clock") ||
4716 parseToken(FIRToken::comma,
"expected ','") ||
4717 parseExp(resetSignal,
"expected expression for register reset") ||
4718 parseToken(FIRToken::comma,
"expected ','") ||
4719 parseExp(resetValue,
"expected expression for register reset value") ||
4720 parseOptionalInfo())
4723 if (!type_isa<FIRRTLBaseType>(type))
4724 return emitError(startTok.getLoc(),
"register must have base type");
4726 locationProcessor.setLoc(startTok.getLoc());
4730 .create<RegResetOp>(type, clock, resetSignal, resetValue, id,
4731 NameKindEnum::InterestingName,
4732 getConstants().emptyArrayAttr, StringAttr{})
4735 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4740ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
4744 auto startTok = consumeToken(FIRToken::kw_contract);
4747 SmallVector<StringRef> ids;
4748 SmallVector<SMLoc> locs;
4749 SmallVector<Value> values;
4750 SmallVector<Type> types;
4751 if (!consumeIf(FIRToken::colon)) {
4752 auto parseContractId = [&] {
4754 locs.push_back(getToken().getLoc());
4755 if (parseId(
id,
"expected contract result name"))
4760 auto parseContractValue = [&] {
4762 if (parseExp(value,
"expected expression for contract result"))
4764 values.push_back(value);
4765 types.push_back(value.getType());
4768 if (parseListUntil(FIRToken::equal, parseContractId) ||
4769 parseListUntil(FIRToken::colon, parseContractValue))
4772 if (parseOptionalInfo())
4776 if (ids.size() != values.size())
4777 return emitError(startTok.getLoc())
4778 <<
"contract requires same number of results and expressions; got "
4779 << ids.size() <<
" results and " << values.size()
4780 <<
" expressions instead";
4782 locationProcessor.setLoc(startTok.getLoc());
4786 auto contract = builder.create<ContractOp>(types, values);
4787 auto &block = contract.getBody().emplaceBlock();
4791 FIRModuleContext::ContextScope scope(moduleContext, &block);
4792 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
4793 auto arg = block.addArgument(type, LocWithInfo(loc,
this).getLoc());
4794 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
4797 if (getIndentation() > blockIndent)
4798 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
4803 for (
auto [
id, loc, value, result] :
4804 llvm::zip(ids, locs, values, contract.getResults()))
4805 if (failed(moduleContext.addSymbolEntry(id, result, loc)))
4818struct FIRCircuitParser :
public FIRParser {
4819 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
4821 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
4824 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
4825 mlir::TimingScope &ts);
4830 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4831 SmallVectorImpl<Attribute> &attrs);
4833 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
4835 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
4836 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
4837 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
4838 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
4839 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
4840 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
4842 ParseResult parseLayerName(SymbolRefAttr &result);
4843 ParseResult parseOptionalEnabledLayers(ArrayAttr &result);
4844 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4845 SmallVectorImpl<SMLoc> &resultPortLocs,
4848 ParseResult parseRefList(ArrayRef<PortInfo> portList,
4849 ArrayAttr &internalPathsResult);
4851 ParseResult skipToModuleEnd(
unsigned indent);
4853 ParseResult parseTypeDecl();
4855 ParseResult parseOptionDecl(CircuitOp circuit);
4857 ParseResult parseLayer(CircuitOp circuit);
4859 struct DeferredModuleToParse {
4860 FModuleLike moduleOp;
4861 SmallVector<SMLoc> portLocs;
4866 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
4867 DeferredModuleToParse &deferredModule,
4868 InnerSymFixups &fixups);
4870 SmallVector<DeferredModuleToParse, 0> deferredModules;
4872 SmallVector<InnerSymFixups, 0> moduleFixups;
4876 ModuleOp mlirModule;
4881FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
4882 SmallVectorImpl<Attribute> &attrs) {
4884 auto annotations = json::parse(annotationsStr);
4885 if (
auto err = annotations.takeError()) {
4886 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
4887 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
4888 diag.attachNote() << a.message();
4893 json::Path::Root root;
4894 llvm::StringMap<ArrayAttr> thisAnnotationMap;
4897 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
4898 std::string jsonErrorMessage =
4899 "See inline comments for problem area in JSON:\n";
4900 llvm::raw_string_ostream s(jsonErrorMessage);
4901 root.printErrorContext(annotations.get(), s);
4902 diag.attachNote() << jsonErrorMessage;
4909ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
4910 auto *context = getContext();
4911 SmallVector<StringRef> strings;
4914 if (parseId(name,
"expected layer name"))
4916 strings.push_back(name);
4917 }
while (consumeIf(FIRToken::period));
4919 SmallVector<FlatSymbolRefAttr> nested;
4920 nested.reserve(strings.size() - 1);
4921 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
4922 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
4924 result = SymbolRefAttr::get(context, strings[0], nested);
4928ParseResult FIRCircuitParser::parseOptionalEnabledLayers(ArrayAttr &result) {
4929 if (getToken().getKind() != FIRToken::kw_enablelayer) {
4930 result = ArrayAttr::get(getContext(), {});
4934 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
4937 SmallVector<Attribute> layers;
4939 SymbolRefAttr layer;
4941 if (parseLayerName(layer))
4943 layers.push_back(layer);
4944 }
while (getToken().getKind() == FIRToken::kw_enablelayer);
4946 result = ArrayAttr::get(getContext(), layers);
4954FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
4955 SmallVectorImpl<SMLoc> &resultPortLocs,
4958 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
4960 getIndentation() > indent) {
4966 auto backtrackState = getLexer().getCursor();
4968 bool isOutput = getToken().is(FIRToken::kw_output);
4973 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
4974 !getToken().isKeyword()) {
4975 backtrackState.restore(getLexer());
4981 LocWithInfo info(getToken().getLoc(),
this);
4982 if (parseId(name,
"expected port name") ||
4983 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
4984 parseType(type,
"expected a type in port declaration") ||
4985 info.parseOptionalInfo())
4988 StringAttr innerSym = {};
4989 resultPorts.push_back(
4990 {name, type,
direction::get(isOutput), innerSym, info.getLoc()});
4991 resultPortLocs.push_back(info.getFIRLoc());
4996 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
4997 PortInfo &port = std::get<0>(portAndLoc);
4998 auto &entry = portIds[port.
name];
4999 if (!entry.isValid()) {
5000 entry = std::get<1>(portAndLoc);
5004 emitError(std::get<1>(portAndLoc),
5005 "redefinition of name '" + port.
getName() +
"'")
5006 .attachNote(translateLocation(entry))
5007 <<
"previous definition here";
5016ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
5017 ArrayAttr &internalPathsResult) {
5018 struct RefStatementInfo {
5020 InternalPathAttr resolvedPath;
5024 SmallVector<RefStatementInfo> refStatements;
5025 SmallPtrSet<StringAttr, 8> seenNames;
5026 SmallPtrSet<StringAttr, 8> seenRefs;
5029 if (getToken().is(FIRToken::kw_ref) &&
5030 (requireFeature({2, 0, 0},
"ref statements") ||
5031 removedFeature({4, 0, 0},
"ref statements")))
5035 while (consumeIf(FIRToken::kw_ref)) {
5036 auto loc = getToken().getLoc();
5040 if (parseId(refName,
"expected ref name"))
5042 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
5044 loc,
"ref statements for aggregate elements not yet supported");
5045 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
5048 if (!seenRefs.insert(refName).second)
5049 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
5052 auto kind = getToken().getKind();
5053 if (kind != FIRToken::string)
5054 return emitError(loc,
"expected string in ref statement");
5055 auto resolved = InternalPathAttr::get(
5057 StringAttr::get(getContext(), getToken().getStringValue()));
5058 consumeToken(FIRToken::string);
5060 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
5064 SmallVector<Attribute> internalPaths(portList.size(),
5065 InternalPathAttr::get(getContext()));
5067 llvm::SmallBitVector usedRefs(refStatements.size());
5068 size_t matchedPaths = 0;
5069 for (
auto [idx, port] :
llvm::enumerate(portList)) {
5070 if (!type_isa<RefType>(port.
type))
5076 return mlir::emitError(
5078 "references in ports must be output on extmodule and intmodule");
5080 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
5081 return r.refName == pname;
5084 if (refStmtIt == refStatements.end()) {
5085 if (!refStatements.empty())
5086 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
5091 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
5092 internalPaths[idx] = refStmtIt->resolvedPath;
5096 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
5097 assert(matchedPaths < refStatements.size());
5099 auto idx = usedRefs.find_first_unset();
5101 return emitError(refStatements[idx].loc,
"unused ref statement");
5105 internalPathsResult = ArrayAttr::get(getContext(), internalPaths);
5111ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5113 switch (getToken().getKind()) {
5117 case FIRToken::error:
5121 case FIRToken::kw_class:
5122 case FIRToken::kw_declgroup:
5123 case FIRToken::kw_extclass:
5124 case FIRToken::kw_extmodule:
5125 case FIRToken::kw_intmodule:
5126 case FIRToken::kw_formal:
5127 case FIRToken::kw_module:
5128 case FIRToken::kw_public:
5129 case FIRToken::kw_layer:
5130 case FIRToken::kw_option:
5131 case FIRToken::kw_type:
5135 if (getIndentation() == indent)
5147ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5148 SmallVector<Attribute, 8> parameters;
5149 SmallPtrSet<StringAttr, 8> seen;
5150 while (consumeIf(FIRToken::kw_parameter)) {
5154 if (parseParameter(name, value, loc))
5156 auto typedValue = dyn_cast<TypedAttr>(value);
5158 return emitError(loc)
5159 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5160 if (!seen.insert(name).second)
5161 return emitError(loc,
5162 "redefinition of parameter '" + name.getValue() +
"'");
5163 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5165 resultParameters = ArrayAttr::get(getContext(), parameters);
5170ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5172 SmallVector<PortInfo, 8> portList;
5173 SmallVector<SMLoc> portLocs;
5174 LocWithInfo info(getToken().getLoc(),
this);
5179 consumeToken(FIRToken::kw_class);
5180 if (parseId(name,
"expected class name") ||
5181 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5182 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5185 if (name == circuit.getName())
5186 return mlir::emitError(info.getLoc(),
5187 "class cannot be the top of a circuit");
5189 for (
auto &portInfo : portList)
5191 return
mlir::emitError(portInfo.loc,
5192 "ports on classes must be properties");
5195 auto builder = circuit.getBodyBuilder();
5196 auto classOp = builder.create<ClassOp>(info.getLoc(), name, portList);
5197 classOp.setPrivate();
5198 deferredModules.emplace_back(
5199 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5202 getConstants().classMap[name.getValue()] = classOp;
5203 return skipToModuleEnd(indent);
5207ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5210 SmallVector<PortInfo, 8> portList;
5211 SmallVector<SMLoc> portLocs;
5212 LocWithInfo info(getToken().getLoc(),
this);
5217 consumeToken(FIRToken::kw_extclass);
5218 if (parseId(name,
"expected extclass name") ||
5219 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5220 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5223 if (name == circuit.getName())
5224 return mlir::emitError(info.getLoc(),
5225 "extclass cannot be the top of a circuit");
5227 for (
auto &portInfo : portList)
5229 return
mlir::emitError(portInfo.loc,
5230 "ports on extclasses must be properties");
5233 auto builder = circuit.getBodyBuilder();
5234 auto extClassOp = builder.create<ExtClassOp>(info.getLoc(), name, portList);
5237 getConstants().classMap[name.getValue()] = extClassOp;
5238 return skipToModuleEnd(indent);
5245ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5249 SmallVector<PortInfo, 8> portList;
5250 SmallVector<SMLoc> portLocs;
5251 LocWithInfo info(getToken().getLoc(),
this);
5252 consumeToken(FIRToken::kw_extmodule);
5253 if (parseId(name,
"expected extmodule name") ||
5254 parseOptionalEnabledLayers(layers) ||
5255 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5256 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5260 if (consumeIf(FIRToken::kw_defname)) {
5261 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5262 parseId(defName,
"expected defname name"))
5266 ArrayAttr parameters;
5267 ArrayAttr internalPaths;
5272 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5273 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5274 if (ftype.hasUninferredWidth())
5275 return emitError(loc,
"extmodule port must have known width");
5280 auto builder = circuit.getBodyBuilder();
5281 auto isMainModule = (name == circuit.getName());
5283 (isMainModule && getConstants().options.scalarizePublicModules) ||
5284 getConstants().options.scalarizeExtModules
5285 ? Convention::Scalarized
5286 : Convention::Internal;
5287 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5288 auto annotations = ArrayAttr::get(getContext(), {});
5289 auto extModuleOp = builder.create<FExtModuleOp>(
5290 info.getLoc(), name, conventionAttr, portList, defName, annotations,
5291 parameters, internalPaths, layers);
5292 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5293 : SymbolTable::Visibility::Private;
5294 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5302ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5307 SmallVector<PortInfo, 8> portList;
5308 SmallVector<SMLoc> portLocs;
5309 LocWithInfo info(getToken().getLoc(),
this);
5310 consumeToken(FIRToken::kw_intmodule);
5311 if (parseId(name,
"expected intmodule name") ||
5312 parseOptionalEnabledLayers(layers) ||
5313 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5314 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent) ||
5315 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5316 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5317 parseId(intName,
"expected intrinsic name"))
5320 ArrayAttr parameters;
5321 ArrayAttr internalPaths;
5325 ArrayAttr annotations = getConstants().emptyArrayAttr;
5326 auto builder = circuit.getBodyBuilder();
5328 .create<FIntModuleOp>(info.getLoc(), name, portList, intName, annotations,
5329 parameters, internalPaths, layers)
5335ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5338 SmallVector<PortInfo, 8> portList;
5339 SmallVector<SMLoc> portLocs;
5341 auto modLoc = getToken().getLoc();
5342 LocWithInfo info(modLoc,
this);
5343 consumeToken(FIRToken::kw_module);
5344 if (parseId(name,
"expected module name") ||
5345 parseOptionalEnabledLayers(layers) ||
5346 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5347 info.parseOptionalInfo() ||
parsePortList(portList, portLocs, indent))
5351 if (name == circuit.getName()) {
5352 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5357 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5358 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5359 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5360 if (ftype.hasUninferredWidth())
5361 return emitError(loc,
"public module port must have known width");
5362 if (ftype.hasUninferredReset())
5363 return emitError(loc,
5364 "public module port must have concrete reset type");
5369 ArrayAttr annotations = getConstants().emptyArrayAttr;
5370 auto convention = Convention::Internal;
5371 if (isPublic && getConstants().options.scalarizePublicModules)
5372 convention = Convention::Scalarized;
5373 if (!isPublic && getConstants().options.scalarizeInternalModules)
5374 convention = Convention::Scalarized;
5375 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5376 auto builder = circuit.getBodyBuilder();
5377 auto moduleOp = builder.create<FModuleOp>(info.getLoc(), name, conventionAttr,
5378 portList, annotations, layers);
5380 auto visibility = isPublic ? SymbolTable::Visibility::Public
5381 : SymbolTable::Visibility::Private;
5382 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5386 deferredModules.emplace_back(DeferredModuleToParse{
5387 moduleOp, portLocs, getLexer().getCursor(), indent});
5389 if (skipToModuleEnd(indent))
5396ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5397 consumeToken(FIRToken::kw_formal);
5398 StringRef id, moduleName;
5400 LocWithInfo info(getToken().getLoc(),
this);
5401 auto builder = circuit.getBodyBuilder();
5405 if (parseId(
id,
"expected formal test name") ||
5406 parseToken(FIRToken::kw_of,
"expected 'of' in formal test") ||
5407 parseId(moduleName,
"expected module name"))
5411 NamedAttrList params;
5412 if (consumeIf(FIRToken::comma)) {
5414 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5415 return emitError(
"expected 'bound' after ','");
5417 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5418 parseIntLit(bound,
"expected integer bound after '='"))
5421 return emitError(
"bound must be a positive integer");
5422 if (info.parseOptionalInfo())
5424 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5427 if (parseToken(FIRToken::colon,
"expected ':' in formal test") ||
5428 info.parseOptionalInfo())
5430 while (getIndentation() > indent) {
5431 StringAttr paramName;
5432 Attribute paramValue;
5434 if (parseParameter(paramName, paramValue, paramLoc,
5437 if (params.set(paramName, paramValue))
5438 return emitError(paramLoc,
"redefinition of parameter '" +
5439 paramName.getValue() +
"'");
5443 builder.create<firrtl::FormalOp>(info.getLoc(), id, moduleName,
5444 params.getDictionary(getContext()));
5448ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5450 switch (getToken().getKind()) {
5451 case FIRToken::kw_class:
5452 return parseClass(circuit, indent);
5453 case FIRToken::kw_declgroup:
5454 if (requireFeature({3, 2, 0},
"optional groups") ||
5455 removedFeature({3, 3, 0},
"optional groups"))
5457 return parseLayer(circuit);
5458 case FIRToken::kw_extclass:
5459 return parseExtClass(circuit, indent);
5460 case FIRToken::kw_extmodule:
5461 return parseExtModule(circuit, indent);
5462 case FIRToken::kw_formal:
5463 if (requireFeature({4, 0, 0},
"inline formal tests"))
5465 return parseFormal(circuit, indent);
5466 case FIRToken::kw_intmodule:
5467 if (requireFeature({1, 2, 0},
"inline formal tests") ||
5468 removedFeature({4, 0, 0},
"intrinsic modules"))
5470 return parseIntModule(circuit, indent);
5471 case FIRToken::kw_layer:
5472 if (requireFeature({3, 3, 0},
"layers"))
5474 return parseLayer(circuit);
5475 case FIRToken::kw_module:
5476 return parseModule(circuit,
false, indent);
5477 case FIRToken::kw_public:
5478 if (requireFeature({3, 3, 0},
"public modules"))
5481 if (getToken().getKind() == FIRToken::kw_module)
5482 return parseModule(circuit,
true, indent);
5483 return emitError(getToken().getLoc(),
"only modules may be public");
5484 case FIRToken::kw_type:
5485 return parseTypeDecl();
5486 case FIRToken::kw_option:
5489 return parseOptionDecl(circuit);
5491 return emitError(getToken().getLoc(),
"unknown toplevel definition");
5496ParseResult FIRCircuitParser::parseTypeDecl() {
5500 auto loc = getToken().getLoc();
5502 if (getToken().isKeyword())
5503 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5504 <<
"' for type alias name";
5506 if (parseId(
id,
"expected type name") ||
5507 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5510 auto name = StringAttr::get(type.getContext(),
id);
5513 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5514 type = BaseTypeAliasType::get(name, base);
5517 <<
"type alias for non-base type " << type
5518 <<
" is currently not supported. Type alias is stripped immediately";
5520 if (!getConstants().aliasMap.insert({id, type}).second)
5521 return emitError(loc) <<
"type alias `" << name.getValue()
5522 <<
"` is already defined";
5527ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
5530 auto loc = getToken().getLoc();
5532 LocWithInfo info(getToken().getLoc(),
this);
5533 if (parseId(
id,
"expected an option group name") ||
5534 parseToken(FIRToken::colon,
5535 "expected ':' after option group definition") ||
5536 info.parseOptionalInfo())
5539 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
5540 auto optionOp = builder.create<OptionOp>(info.getLoc(), id);
5541 auto *block =
new Block;
5542 optionOp.getBody().push_back(block);
5543 builder.setInsertionPointToEnd(block);
5545 auto baseIndent = getIndentation();
5547 while (getIndentation() == baseIndent) {
5549 LocWithInfo caseInfo(getToken().getLoc(),
this);
5550 if (parseId(
id,
"expected an option case ID") ||
5551 caseInfo.parseOptionalInfo())
5554 if (!cases.insert(
id).second)
5555 return emitError(loc)
5556 <<
"duplicate option case definition '" <<
id <<
"'";
5558 builder.create<OptionCaseOp>(caseInfo.getLoc(), id);
5565ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
5566 auto baseIndent = getIndentation();
5569 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
5572 auto parseOne = [&](
Block *block) -> ParseResult {
5573 auto indent = getIndentation();
5574 StringRef id, convention;
5575 LocWithInfo info(getToken().getLoc(),
this);
5577 if (parseId(
id,
"expected layer name") ||
5578 parseToken(FIRToken::comma,
"expected ','") ||
5579 parseGetSpelling(convention))
5582 auto layerConvention = symbolizeLayerConvention(convention);
5583 if (!layerConvention) {
5584 emitError() <<
"unknown convention '" << convention
5585 <<
"' (did you misspell it?)";
5588 if (layerConvention == LayerConvention::Inline &&
5589 requireFeature({4, 1, 0},
"inline layers"))
5593 hw::OutputFileAttr outputDir;
5594 if (consumeIf(FIRToken::comma)) {
5595 if (getToken().getKind() == FIRToken::string) {
5596 auto text = getToken().getStringValue();
5598 return emitError() <<
"output directory must not be blank";
5599 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
5600 consumeToken(FIRToken::string);
5604 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
5605 info.parseOptionalInfo())
5607 auto builder = OpBuilder::atBlockEnd(block);
5609 auto layerOp = builder.create<LayerOp>(info.getLoc(), id, *layerConvention);
5610 layerOp->getRegion(0).push_back(
new Block());
5612 layerOp->setAttr(
"output_file", outputDir);
5613 layerStack.push_back({indent, layerOp});
5617 if (parseOne(circuit.getBodyBlock()))
5621 while (getIndentation() > baseIndent) {
5622 switch (getToken().getKind()) {
5623 case FIRToken::kw_declgroup:
5624 case FIRToken::kw_layer: {
5627 while (layerStack.back().first >= getIndentation())
5628 layerStack.pop_back();
5629 auto parentLayer = layerStack.back().second;
5630 if (parseOne(&parentLayer.getBody().front()))
5635 return emitError(
"expected 'layer'"), failure();
5644FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
5645 DeferredModuleToParse &deferredModule,
5646 InnerSymFixups &fixups) {
5647 FModuleLike moduleOp = deferredModule.moduleOp;
5648 auto &body = moduleOp->getRegion(0).front();
5649 auto &portLocs = deferredModule.portLocs;
5653 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
5656 deferredModule.lexerCursor.restore(moduleBodyLexer);
5658 FIRModuleContext moduleContext(getConstants(), moduleBodyLexer, version);
5662 auto portList = moduleOp.getPorts();
5663 auto portArgs = body.getArguments();
5664 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
5665 PortInfo &port = std::get<0>(tuple);
5666 llvm::SMLoc loc = std::get<1>(tuple);
5667 BlockArgument portArg = std::get<2>(tuple);
5669 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
5673 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
5676 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
5682 size_t numVerifPrintfs = 0;
5683 std::optional<Location> printfLoc;
5685 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
5690 printfLoc = printFOp.getLoc();
5693 if (numVerifPrintfs > 0) {
5695 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
5697 <<
" printf-encoded verification operation(s), which are no longer "
5699 diag.attachNote(*printfLoc)
5700 <<
"example printf here, this is now just a printf and nothing more";
5701 diag.attachNote() <<
"For more information, see "
5702 "https://github.com/llvm/circt/issues/6970";
5716ParseResult FIRCircuitParser::parseCircuit(
5717 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
5718 mlir::TimingScope &ts) {
5720 auto indent = getIndentation();
5721 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
5723 if (!indent.has_value())
5724 return emitError(
"'FIRRTL' must be first token on its line");
5725 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
5726 parseVersionLit(
"expected version literal"))
5728 indent = getIndentation();
5730 if (!indent.has_value())
5731 return emitError(
"'circuit' must be first token on its line");
5732 unsigned circuitIndent = *indent;
5734 LocWithInfo info(getToken().getLoc(),
this);
5736 SMLoc inlineAnnotationsLoc;
5737 StringRef inlineAnnotations;
5740 if (parseToken(FIRToken::kw_circuit,
5741 "expected a top-level 'circuit' definition") ||
5742 parseId(name,
"expected circuit name") ||
5743 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
5744 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
5745 info.parseOptionalInfo())
5749 OpBuilder b(mlirModule.getBodyRegion());
5750 auto circuit = b.create<CircuitOp>(info.getLoc(), name);
5753 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
5759 SmallVector<Attribute> annos;
5760 if (!inlineAnnotations.empty())
5761 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
5765 for (
auto *annotationsBuf : annotationsBufs)
5766 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
5770 parseAnnotationTimer.stop();
5778 auto parseTimer = ts.nest(
"Parse modules");
5779 deferredModules.reserve(16);
5783 switch (getToken().getKind()) {
5791 case FIRToken::error:
5795 emitError(
"unexpected token in circuit");
5798 case FIRToken::kw_class:
5799 case FIRToken::kw_declgroup:
5800 case FIRToken::kw_extclass:
5801 case FIRToken::kw_extmodule:
5802 case FIRToken::kw_intmodule:
5803 case FIRToken::kw_layer:
5804 case FIRToken::kw_formal:
5805 case FIRToken::kw_module:
5806 case FIRToken::kw_option:
5807 case FIRToken::kw_public:
5808 case FIRToken::kw_type: {
5809 auto indent = getIndentation();
5810 if (!indent.has_value())
5811 return emitError(
"'module' must be first token on its line"), failure();
5812 unsigned definitionIndent = *indent;
5814 if (definitionIndent <= circuitIndent)
5815 return emitError(
"module should be indented more"), failure();
5817 if (parseToplevelDefinition(circuit, definitionIndent))
5831 (void)getLexer().translateLocation(info.getFIRLoc());
5837 DenseMap<Attribute, Location> nameToOrigLoc;
5841 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
5846 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
5849 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
5850 .attachNote(it.first->second)
5851 .append(
"see existing symbol definition here");
5857 SymbolTable circuitSymTbl(circuit);
5859 moduleFixups.resize(deferredModules.size());
5864 for (
auto &d : deferredModules)
5865 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
5868 auto anyFailed = mlir::failableParallelForEachN(
5869 getContext(), 0, deferredModules.size(), [&](
size_t index) {
5870 if (parseModuleBody(circuitSymTbl, deferredModules[index],
5871 moduleFixups[index]))
5875 if (failed(anyFailed))
5880 for (
auto &fixups : moduleFixups) {
5881 if (failed(fixups.resolve(innerSymbolNamespaces)))
5887 auto parseLayerName = [&](StringRef name) -> Attribute {
5889 auto [head, rest] = name.split(
".");
5890 SmallVector<FlatSymbolRefAttr> nestedRefs;
5891 while (!rest.empty()) {
5893 std::tie(next, rest) = rest.split(
".");
5894 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
5896 return SymbolRefAttr::get(getContext(), head, nestedRefs);
5899 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
5900 SmallVector<Attribute> attrArray;
5901 auto *context = getContext();
5902 for (
const auto &str : strArray)
5903 attrArray.push_back(getAttr(str));
5904 if (attrArray.empty())
5906 return ArrayAttr::get(context, attrArray);
5909 if (
auto enableLayers =
5910 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
5911 circuit.setEnableLayersAttr(enableLayers);
5912 if (
auto disableLayers =
5913 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
5914 circuit.setDisableLayersAttr(disableLayers);
5916 auto getStrAttr = [&](StringRef str) -> Attribute {
5917 return StringAttr::get(getContext(), str);
5920 if (
auto selectInstChoice =
5921 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
5922 circuit.setSelectInstChoiceAttr(selectInstChoice);
5924 circuit.setDefaultLayerSpecialization(
5925 getConstants().options.defaultLayerSpecialization);
5938 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
5939 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
5940 unsigned fileID = 1;
5942 annotationsBufs.push_back(
5943 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
5945 context->loadDialect<CHIRRTLDialect>();
5946 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
5950 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
5953 SharedParserConstants state(context, options);
5954 FIRLexer lexer(sourceMgr, context);
5956 .parseCircuit(annotationsBufs, ts))
5961 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
5962 if (failed(verify(*module)))
5969 static mlir::TranslateToMLIRRegistration fromFIR(
5970 "import-firrtl",
"import .fir",
5971 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
5972 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
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 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