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/LogicalResult.h"
43#include "llvm/Support/SourceMgr.h"
44#include "llvm/Support/raw_ostream.h"
49using namespace firrtl;
50using namespace chirrtl;
54using mlir::LocationAttr;
67struct SharedParserConstants {
71 loIdentifier(StringAttr::get(
context,
"lo")),
72 hiIdentifier(StringAttr::get(
context,
"hi")),
73 amountIdentifier(StringAttr::get(
context,
"amount")),
75 hw::InnerRefAttr::get(StringAttr::get(
context,
"module"),
76 StringAttr::get(
context,
"placeholder"))) {}
85 llvm::StringMap<FIRRTLType> aliasMap;
88 llvm::DenseMap<StringRef, ClassLike> classMap;
91 llvm::DenseMap<StringRef, DomainOp> domainMap;
94 const ArrayAttr emptyArrayAttr;
97 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
100 const hw::InnerRefAttr placeholderInnerRef;
103 SharedParserConstants(
const SharedParserConstants &) =
delete;
104 void operator=(
const SharedParserConstants &) =
delete;
117 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
119 : version(version), constants(constants), lexer(lexer),
120 locatorFilenameCache(constants.loIdentifier ) {
124 SharedParserConstants &getConstants()
const {
return constants; }
125 MLIRContext *getContext()
const {
return constants.context; }
127 FIRLexer &getLexer() {
return lexer; }
130 std::optional<unsigned> getIndentation()
const {
135 const FIRToken &getToken()
const {
return lexer.getToken(); }
136 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
143 InFlightDiagnostic emitError(
const Twine &message = {}) {
144 return emitError(getToken().
getLoc(), message);
146 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
149 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
150 return emitWarning(getToken().
getLoc(), message);
153 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
163 Location translateLocation(llvm::SMLoc loc) {
164 return lexer.translateLocation(loc);
169 ParseResult parseOptionalInfoLocator(LocationAttr &result);
173 ParseResult parseOptionalName(StringAttr &name);
179 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
180 return requireFeature(minimum, feature, getToken().
getLoc());
183 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
184 if (version < minimum)
185 return emitError(loc)
186 << feature <<
" are a FIRRTL " << minimum
187 <<
"+ feature, but the specified FIRRTL version was " << version;
191 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
192 return removedFeature(removedVersion, feature, getToken().
getLoc());
195 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
197 if (version >= removedVersion)
198 return emitError(loc)
199 << feature <<
" were removed in FIRRTL " << removedVersion
200 <<
", but the specified FIRRTL version was " << version;
210 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
219 if (getToken().isNot(kind))
229 FIRToken consumedToken = getToken();
230 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
231 "shouldn't advance past EOF or errors");
233 return consumedToken;
242 FIRToken consumedToken = getToken();
243 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
245 return consumedToken;
250 ParseResult parseGetSpelling(StringRef &spelling) {
251 spelling = getTokenSpelling();
257 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
262 const std::function<ParseResult()> &parseElement);
269 ParseResult parseIntLit(APInt &result,
const Twine &message);
270 ParseResult parseIntLit(int64_t &result,
const Twine &message);
271 ParseResult parseIntLit(int32_t &result,
const Twine &message);
274 ParseResult parseVersionLit(
const Twine &message);
277 ParseResult parseWidth(int32_t &result);
280 ParseResult parseId(StringRef &result,
const Twine &message);
281 ParseResult parseId(StringAttr &result,
const Twine &message);
282 ParseResult parseFieldId(StringRef &result,
const Twine &message);
283 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
284 const Twine &message);
285 ParseResult parseEnumType(
FIRRTLType &result);
286 ParseResult parseListType(
FIRRTLType &result);
287 ParseResult parseRegistryType(
FIRRTLType &result);
290 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
292 ParseResult parseRUW(RUWBehavior &result);
293 ParseResult parseOptionalRUW(RUWBehavior &result);
295 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
296 SMLoc &resultLoc,
bool allowAggregates =
false);
297 ParseResult parseParameterValue(Attribute &resultValue,
298 bool allowAggregates =
false);
304 FIRParser(
const FIRParser &) =
delete;
305 void operator=(
const FIRParser &) =
delete;
309 SharedParserConstants &constants;
313 StringAttr locatorFilenameCache;
315 FileLineColLoc fileLineColLocCache;
324InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
325 auto diag = mlir::emitError(translateLocation(loc), message);
329 if (getToken().is(FIRToken::error))
334InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
335 return mlir::emitWarning(translateLocation(loc), message);
345 const Twine &message) {
346 if (consumeIf(expectedToken))
348 return emitError(message);
355 const std::function<ParseResult()> &parseElement) {
356 if (consumeIf(rightToken))
362 while (consumeIf(FIRToken::comma)) {
367 if (parseToken(rightToken,
"expected ','"))
399 if (failed(
parser->parseOptionalInfoLocator(loc)))
403 switch (
parser->constants.options.infoLocatorHandling) {
404 case ILH::IgnoreInfo:
405 assert(0 &&
"Should not return info locations if ignoring");
407 case ILH::PreferInfo:
411 infoLoc = FusedLoc::get(loc.getContext(),
412 {loc, parser->translateLocation(firLoc)});
439ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
440 if (getToken().isNot(FIRToken::fileinfo))
443 auto loc = getToken().getLoc();
445 auto spelling = getTokenSpelling();
446 consumeToken(FIRToken::fileinfo);
450 constants.options.infoLocatorHandling ==
451 FIRParserOptions::InfoLocHandling::IgnoreInfo,
452 locatorFilenameCache, fileLineColLocCache, getContext());
455 if (!locationPair.first) {
456 mlir::emitWarning(translateLocation(loc),
457 "ignoring unknown @ info record format");
463 if (locationPair.first && constants.options.infoLocatorHandling ==
464 FIRParserOptions::InfoLocHandling::IgnoreInfo)
468 result = *locationPair.second;
476ParseResult FIRParser::parseOptionalName(StringAttr &name) {
478 if (getToken().isNot(FIRToken::colon)) {
479 name = StringAttr::get(getContext(),
"");
483 consumeToken(FIRToken::colon);
485 if (parseId(nameRef,
"expected result name"))
488 name = StringAttr::get(getContext(), nameRef);
499ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
501 if (getToken().isNot(FIRToken::inlineannotation))
504 loc = getToken().getLoc();
506 result = getTokenSpelling().drop_front(2).drop_back(1);
507 consumeToken(FIRToken::inlineannotation);
525ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
526 auto spelling = getTokenSpelling();
527 bool isNegative =
false;
528 switch (getToken().getKind()) {
529 case FIRToken::signed_integer:
530 isNegative = spelling[0] ==
'-';
531 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
532 spelling = spelling.drop_front();
534 case FIRToken::integer:
535 if (spelling.getAsInteger(10, result))
536 return emitError(message), failure();
540 if (result.isNegative())
541 result = result.zext(result.getBitWidth() + 1);
550 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
551 result = result.trunc(32);
555 case FIRToken::radix_specified_integer: {
556 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
558 if (spelling[0] ==
'-') {
560 spelling = spelling.drop_front();
562 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
567 spelling = spelling.drop_front(2);
568 if (spelling.getAsInteger(base, result))
569 return emitError(
"invalid character in integer literal"), failure();
570 if (result.isNegative())
571 result = result.zext(result.getBitWidth() + 1);
577 case FIRToken::string: {
580 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
583 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
584 spelling = spelling.drop_back().drop_front();
588 switch (spelling.empty() ?
' ' : spelling.front()) {
599 return emitError(
"expected base specifier (h/o/b) in integer literal"),
602 spelling = spelling.drop_front();
605 bool isNegative =
false;
606 if (!spelling.empty() && spelling.front() ==
'+')
607 spelling = spelling.drop_front();
608 else if (!spelling.empty() && spelling.front() ==
'-') {
610 spelling = spelling.drop_front();
614 if (spelling.empty())
615 return emitError(
"expected digits in integer literal"), failure();
617 if (spelling.getAsInteger(base, result))
618 return emitError(
"invalid character in integer literal"), failure();
623 if (result.isNegative())
624 result = result.zext(result.getBitWidth() + 1);
629 consumeToken(FIRToken::string);
634 return emitError(
"expected integer literal"), failure();
638ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
640 auto loc = getToken().getLoc();
641 if (parseIntLit(value, message))
644 result = (int64_t)value.getLimitedValue(INT64_MAX);
646 return emitError(loc,
"value is too big to handle"), failure();
650ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
652 auto loc = getToken().getLoc();
653 if (parseIntLit(value, message))
656 result = (int32_t)value.getLimitedValue(INT32_MAX);
658 return emitError(loc,
"value is too big to handle"), failure();
664ParseResult FIRParser::parseVersionLit(
const Twine &message) {
665 auto spelling = getTokenSpelling();
666 if (getToken().getKind() != FIRToken::version)
667 return emitError(message), failure();
670 return emitError(
"failed to parse version string"), failure();
675 consumeToken(FIRToken::version);
681ParseResult FIRParser::parseWidth(int32_t &result) {
682 auto widthLoc = getToken().getLoc();
683 if (parseIntLit(result,
"expected width") ||
684 parseToken(FIRToken::greater,
"expected '>'"))
687 return emitError(widthLoc,
"invalid width specifier"), failure();
695ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
696 switch (getToken().getKind()) {
698 case FIRToken::identifier:
699 case FIRToken::literal_identifier:
701#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
702#include "FIRTokenKinds.def"
707 if (getToken().getKind() == FIRToken::literal_identifier)
708 result = getTokenSpelling().drop_front().drop_back();
710 result = getTokenSpelling();
720ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
722 if (parseId(name, message))
725 result = StringAttr::get(getContext(), name);
734ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
736 result = getTokenSpelling();
737 if (consumeIf(FIRToken::integer))
743 if (parseId(result, message))
755ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
756 const Twine &message) {
758 StringRef tmp = getTokenSpelling();
760 if (consumeIf(FIRToken::integer)) {
761 result.push_back(tmp);
765 if (consumeIf(FIRToken::floatingpoint)) {
769 auto [a, b] = tmp.split(
".");
775 if (consumeIf(FIRToken::version)) {
777 auto [a,
d] = tmp.split(
".");
778 auto [b, c] =
d.split(
".");
786 if (parseId(tmp, message))
788 result.push_back(tmp);
794ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
795 if (parseToken(FIRToken::l_brace_bar,
796 "expected leading '{|' in enumeration type"))
798 SmallVector<StringAttr> names;
799 SmallVector<APInt> values;
800 SmallVector<FIRRTLBaseType> types;
801 SmallVector<SMLoc> locs;
802 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
803 auto fieldLoc = getToken().getLoc();
804 locs.push_back(fieldLoc);
808 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
810 auto name = StringAttr::get(getContext(), nameStr);
811 names.push_back(name);
817 if (consumeIf(FIRToken::equal)) {
818 if (parseIntLit(value,
"expected integer value for enumeration tag"))
820 if (value.isNegative())
821 return emitError(fieldLoc,
"enum tag value must be non-negative");
822 }
else if (values.empty()) {
828 auto &prev = values.back();
829 if (prev.isMaxValue())
830 value = prev.zext(prev.getBitWidth() + 1);
835 values.push_back(std::move(value));
839 if (consumeIf(FIRToken::colon)) {
841 if (
parseType(parsedType,
"expected enumeration type"))
843 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
845 return emitError(fieldLoc,
"field must be a base type");
848 type = UIntType::get(getContext(), 0);
850 types.push_back(type);
852 auto r = type.getRecursiveTypeProperties();
854 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
855 if (r.containsAnalog)
856 return emitError(fieldLoc)
857 <<
"enum field " << name <<
" contains analog";
858 if (r.hasUninferredWidth)
859 return emitError(fieldLoc)
860 <<
"enum field " << name <<
" has uninferred width";
861 if (r.hasUninferredReset)
862 return emitError(fieldLoc)
863 <<
"enum field " << name <<
" has uninferred reset";
869 SmallPtrSet<StringAttr, 4> nameSet;
870 for (
auto [name, loc] :
llvm::zip(names, locs))
871 if (!nameSet.insert(name).second)
872 return emitError(loc,
873 "duplicate variant name in enum: " + name.getValue());
876 unsigned bitwidth = 0;
877 for (
auto &value : values)
878 bitwidth = std::max(bitwidth, value.getActiveBits());
880 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
884 SmallPtrSet<IntegerAttr, 4> valueSet;
885 SmallVector<FEnumType::EnumElement, 4> elements;
886 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
887 auto tagValue = value.zextOrTrunc(bitwidth);
888 auto attr = IntegerAttr::get(tagType, tagValue);
890 if (!valueSet.insert(attr).second)
891 return emitError(loc,
"duplicate variant value in enum: ") << attr;
892 elements.push_back({name, attr, type});
895 llvm::sort(elements);
896 result = FEnumType::get(getContext(), elements);
900ParseResult FIRParser::parsePropertyType(
PropertyType &result,
901 const Twine &message) {
902 auto loc = getToken().getLoc();
907 auto prop = type_dyn_cast<PropertyType>(type);
909 return emitError(loc,
"expected property type");
915ParseResult FIRParser::parseListType(
FIRRTLType &result) {
916 consumeToken(FIRToken::kw_List);
919 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
920 parsePropertyType(
elementType,
"expected List element type") ||
921 parseToken(FIRToken::greater,
"expected '>' in List type"))
929ParseResult FIRParser::parseRegistryType(
FIRRTLType &result) {
930 consumeToken(FIRToken::kw_Registry);
933 if (parseToken(FIRToken::less,
"expected '<' in Registry type") ||
934 parsePropertyType(
elementType,
"expected Registry element type") ||
935 parseToken(FIRToken::greater,
"expected '>' in Registry type"))
938 result = RegistryType::get(getContext(),
elementType);
962ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
963 switch (getToken().getKind()) {
965 return emitError(message), failure();
967 case FIRToken::kw_Clock:
968 consumeToken(FIRToken::kw_Clock);
969 result = ClockType::get(getContext());
972 case FIRToken::kw_Inst: {
973 if (requireFeature({6, 0, 0},
"Inst types"))
976 consumeToken(FIRToken::kw_Inst);
977 if (parseToken(FIRToken::less,
"expected < in Inst type"))
980 auto loc = getToken().getLoc();
982 if (parseId(
id,
"expected class name in Inst type"))
986 const auto &classMap = getConstants().classMap;
987 auto lookup = classMap.find(
id);
988 if (lookup == classMap.end())
989 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
991 auto classOp = lookup->second;
993 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
996 result = classOp.getInstanceType();
1000 case FIRToken::kw_AnyRef: {
1001 if (requireFeature({6, 0, 0},
"AnyRef types"))
1004 consumeToken(FIRToken::kw_AnyRef);
1005 result = AnyRefType::get(getContext());
1009 case FIRToken::kw_Reset:
1010 consumeToken(FIRToken::kw_Reset);
1011 result = ResetType::get(getContext());
1014 case FIRToken::kw_AsyncReset:
1015 consumeToken(FIRToken::kw_AsyncReset);
1016 result = AsyncResetType::get(getContext());
1019 case FIRToken::kw_UInt:
1020 consumeToken(FIRToken::kw_UInt);
1022 result = UIntType::get(getContext(), -1);
1025 case FIRToken::kw_SInt:
1026 consumeToken(FIRToken::kw_SInt);
1028 result = SIntType::get(getContext(), -1);
1031 case FIRToken::kw_Analog:
1032 consumeToken(FIRToken::kw_Analog);
1034 result = AnalogType::get(getContext(), -1);
1037 case FIRToken::langle_UInt:
1038 case FIRToken::langle_SInt:
1039 case FIRToken::langle_Analog: {
1042 auto kind = getToken().getKind();
1046 if (parseWidth(width))
1049 if (kind == FIRToken::langle_SInt)
1050 result = SIntType::get(getContext(), width);
1051 else if (kind == FIRToken::langle_UInt)
1052 result = UIntType::get(getContext(), width);
1054 assert(kind == FIRToken::langle_Analog);
1055 result = AnalogType::get(getContext(), width);
1060 case FIRToken::kw_Domain: {
1066 auto loc = getToken().getLoc();
1067 StringRef domainKindStr;
1068 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type") ||
1069 parseId(domainKindStr,
"expected domain kind"))
1073 const auto &domainMap = getConstants().domainMap;
1074 auto lookup = domainMap.find(domainKindStr);
1075 if (lookup == domainMap.end())
1076 return emitError(loc) <<
"unknown domain '" << domainKindStr <<
"'";
1078 result = DomainType::getFromDomainOp(lookup->second);
1082 case FIRToken::kw_Probe:
1083 case FIRToken::kw_RWProbe: {
1084 auto kind = getToken().getKind();
1085 auto loc = getToken().getLoc();
1090 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1091 parseType(type,
"expected probe data type"))
1094 SmallVector<StringRef> layers;
1095 if (consumeIf(FIRToken::comma)) {
1096 if (requireFeature({4, 0, 0},
"colored probes"))
1101 loc = getToken().getLoc();
1102 if (parseId(layer,
"expected layer name"))
1104 layers.push_back(layer);
1105 }
while (consumeIf(FIRToken::period));
1108 if (!consumeIf(FIRToken::greater))
1109 return emitError(loc,
"expected '>' to end reference type");
1111 bool forceable = kind == FIRToken::kw_RWProbe;
1113 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1115 return emitError(loc,
"invalid probe inner type, must be base-type");
1118 return emitError(loc,
"probe inner type must be passive");
1120 if (forceable &&
innerType.containsConst())
1121 return emitError(loc,
"rwprobe cannot contain const");
1123 SymbolRefAttr layer;
1124 if (!layers.empty()) {
1126 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1127 return FlatSymbolRefAttr::get(getContext(), a);
1129 layer = SymbolRefAttr::get(getContext(), layers.front(),
1130 llvm::to_vector(nestedLayers));
1133 result = RefType::get(innerType, forceable, layer);
1137 case FIRToken::l_brace: {
1138 consumeToken(FIRToken::l_brace);
1140 SmallVector<OpenBundleType::BundleElement, 4> elements;
1141 SmallPtrSet<StringAttr, 4> nameSet;
1142 bool bundleCompatible =
true;
1143 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1144 bool isFlipped = consumeIf(FIRToken::kw_flip);
1146 auto loc = getToken().getLoc();
1147 StringRef fieldNameStr;
1148 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1149 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1151 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1154 if (!nameSet.insert(fieldName).second)
1155 return emitError(loc,
"duplicate field name in bundle: " +
1156 fieldName.getValue());
1159 if (
parseType(type,
"expected bundle field type"))
1162 elements.push_back({fieldName, isFlipped, type});
1163 bundleCompatible &= isa<BundleType::ElementType>(type);
1170 if (bundleCompatible) {
1171 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1172 return BundleType::BundleElement{
1173 element.name, element.isFlip,
1174 cast<BundleType::ElementType>(element.type)};
1176 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1178 result = OpenBundleType::get(getContext(), elements);
1182 case FIRToken::l_brace_bar: {
1183 if (parseEnumType(result))
1188 case FIRToken::identifier: {
1190 auto loc = getToken().getLoc();
1191 if (parseId(
id,
"expected a type alias name"))
1193 auto it = constants.aliasMap.find(
id);
1194 if (it == constants.aliasMap.end()) {
1195 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1198 result = it->second;
1202 case FIRToken::kw_const: {
1203 consumeToken(FIRToken::kw_const);
1204 auto nextToken = getToken();
1205 auto loc = nextToken.getLoc();
1208 if (nextToken.is(FIRToken::kw_const))
1209 return emitError(loc,
"'const' can only be specified once on a type");
1214 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1216 return emitError(loc,
"only hardware types can be 'const'");
1218 result = baseType.getConstType(
true);
1222 case FIRToken::kw_String:
1223 if (requireFeature({3, 1, 0},
"Strings"))
1225 consumeToken(FIRToken::kw_String);
1226 result = StringType::get(getContext());
1228 case FIRToken::kw_Integer:
1229 if (requireFeature({3, 1, 0},
"Integers"))
1231 consumeToken(FIRToken::kw_Integer);
1232 result = FIntegerType::get(getContext());
1234 case FIRToken::kw_Bool:
1235 if (requireFeature({6, 0, 0},
"Bools"))
1237 consumeToken(FIRToken::kw_Bool);
1238 result = BoolType::get(getContext());
1240 case FIRToken::kw_Double:
1241 if (requireFeature({6, 0, 0},
"Doubles"))
1243 consumeToken(FIRToken::kw_Double);
1244 result = DoubleType::get(getContext());
1246 case FIRToken::kw_Path:
1247 if (requireFeature({6, 0, 0},
"Paths"))
1249 consumeToken(FIRToken::kw_Path);
1250 result = PathType::get(getContext());
1252 case FIRToken::kw_List:
1253 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1257 case FIRToken::langle_List: {
1260 if (requireFeature({4, 0, 0},
"Lists"))
1265 if (parsePropertyType(
elementType,
"expected List element type") ||
1266 parseToken(FIRToken::greater,
"expected '>' in List type"))
1269 result = ListType::get(getContext(),
elementType);
1273 case FIRToken::kw_Registry:
1275 parseRegistryType(result))
1279 case FIRToken::langle_Registry: {
1287 if (parsePropertyType(
elementType,
"expected Registry element type") ||
1288 parseToken(FIRToken::greater,
"expected '>' in Registry type"))
1291 result = RegistryType::get(getContext(),
elementType);
1297 while (consumeIf(FIRToken::l_square)) {
1298 auto sizeLoc = getToken().getLoc();
1300 if (parseIntLit(size,
"expected width") ||
1301 parseToken(FIRToken::r_square,
"expected ]"))
1305 return emitError(sizeLoc,
"invalid size specifier"), failure();
1307 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1309 result = FVectorType::get(baseType, size);
1311 result = OpenVectorType::get(result, size);
1318ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1319 switch (getToken().getKind()) {
1321 case FIRToken::kw_old:
1322 result = RUWBehavior::Old;
1323 consumeToken(FIRToken::kw_old);
1325 case FIRToken::kw_new:
1326 result = RUWBehavior::New;
1327 consumeToken(FIRToken::kw_new);
1329 case FIRToken::kw_undefined:
1330 result = RUWBehavior::Undefined;
1331 consumeToken(FIRToken::kw_undefined);
1341ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1342 switch (getToken().getKind()) {
1346 case FIRToken::kw_old:
1347 result = RUWBehavior::Old;
1348 consumeToken(FIRToken::kw_old);
1350 case FIRToken::kw_new:
1351 result = RUWBehavior::New;
1352 consumeToken(FIRToken::kw_new);
1354 case FIRToken::kw_undefined:
1355 result = RUWBehavior::Undefined;
1356 consumeToken(FIRToken::kw_undefined);
1364ParseResult FIRParser::parseParameter(StringAttr &resultName,
1365 Attribute &resultValue, SMLoc &resultLoc,
1366 bool allowAggregates) {
1367 auto loc = getToken().getLoc();
1371 if (parseId(name,
"expected parameter name") ||
1372 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1377 if (parseParameterValue(value, allowAggregates))
1380 resultName = StringAttr::get(getContext(), name);
1381 resultValue = value;
1392ParseResult FIRParser::parseParameterValue(Attribute &value,
1393 bool allowAggregates) {
1394 mlir::Builder builder(getContext());
1395 switch (getToken().getKind()) {
1398 case FIRToken::integer:
1399 case FIRToken::signed_integer: {
1401 if (parseIntLit(result,
"invalid integer parameter"))
1407 if (result.getBitWidth() < 32)
1408 result = result.sext(32);
1410 value = builder.getIntegerAttr(
1411 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1417 case FIRToken::string: {
1419 value = builder.getStringAttr(getToken().getStringValue());
1420 consumeToken(FIRToken::string);
1425 case FIRToken::verbatim_string: {
1427 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1428 value = hw::ParamVerbatimAttr::get(text);
1429 consumeToken(FIRToken::verbatim_string);
1434 case FIRToken::floatingpoint: {
1436 if (!llvm::to_float(getTokenSpelling(), v))
1437 return emitError(
"invalid float parameter syntax"), failure();
1439 value = builder.getF64FloatAttr(v);
1440 consumeToken(FIRToken::floatingpoint);
1445 case FIRToken::l_square: {
1446 if (!allowAggregates)
1447 return emitError(
"expected non-aggregate parameter value");
1450 SmallVector<Attribute> elements;
1451 auto parseElement = [&] {
1452 return parseParameterValue(elements.emplace_back(),
1455 if (parseListUntil(FIRToken::r_square, parseElement))
1458 value = builder.getArrayAttr(elements);
1463 case FIRToken::l_brace: {
1464 if (!allowAggregates)
1465 return emitError(
"expected non-aggregate parameter value");
1468 NamedAttrList fields;
1469 auto parseField = [&]() -> ParseResult {
1470 StringAttr fieldName;
1471 Attribute fieldValue;
1473 if (parseParameter(fieldName, fieldValue, fieldLoc,
1476 if (fields.set(fieldName, fieldValue))
1477 return emitError(fieldLoc)
1478 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1481 if (parseListUntil(FIRToken::r_brace, parseField))
1484 value = fields.getDictionary(getContext());
1489 return emitError(
"expected parameter value");
1504 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1512struct UnbundledValueRestorer {
1514 size_t startingSize;
1516 startingSize = list.size();
1518 ~UnbundledValueRestorer() { list.resize(startingSize); }
1527struct FIRModuleContext :
public FIRParser {
1528 explicit FIRModuleContext(Block *topLevelBlock,
1529 SharedParserConstants &constants,
FIRLexer &lexer,
1531 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1534 template <
typename OpTy = ConstantOp,
typename... Args>
1535 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1536 Type type, Args &&...args) {
1537 auto &result = constantCache[{attr, type}];
1543 OpBuilder::InsertPoint savedIP;
1546 if (builder.getInsertionBlock() != topLevelBlock) {
1547 savedIP = builder.saveInsertionPoint();
1548 auto *block = builder.getInsertionBlock();
1550 auto *op = block->getParentOp();
1551 if (!op || !op->getBlock()) {
1553 builder.setInsertionPointToEnd(topLevelBlock);
1556 if (op->getBlock() == topLevelBlock) {
1557 builder.setInsertionPoint(op);
1560 block = op->getBlock();
1564 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1566 if (savedIP.isSet())
1567 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1578 Value &getCachedSubaccess(Value value,
unsigned index) {
1579 auto &result = subaccessCache[{value, index}];
1582 auto it = scopeMap.find(value.getParentBlock());
1583 if (it != scopeMap.end())
1584 it->second->scopedSubaccesses.push_back({result, index});
1594 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1595 bool insertNameIntoGlobalScope =
false);
1596 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1597 bool insertNameIntoGlobalScope =
false) {
1599 insertNameIntoGlobalScope);
1603 void removeSymbolEntry(StringRef name);
1607 SMLoc loc,
bool fatal =
true);
1612 StringRef field, SMLoc loc);
1620 assert(index < unbundledValues.size());
1621 return unbundledValues[index];
1631 struct ContextScope {
1632 friend struct FIRModuleContext;
1633 ContextScope(FIRModuleContext &moduleContext, Block *block)
1634 : moduleContext(moduleContext), block(block),
1635 previousScope(moduleContext.currentScope) {
1636 moduleContext.currentScope =
this;
1637 moduleContext.scopeMap[block] =
this;
1642 for (
auto *entryPtr : scopedDecls)
1643 entryPtr->second.first = SMLoc();
1646 for (
auto subaccess : scopedSubaccesses)
1647 moduleContext.subaccessCache.erase(subaccess);
1649 moduleContext.scopeMap.erase(block);
1651 moduleContext.currentScope = previousScope;
1655 void operator=(
const ContextScope &) =
delete;
1656 ContextScope(
const ContextScope &) =
delete;
1658 FIRModuleContext &moduleContext;
1660 ContextScope *previousScope;
1661 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1662 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1667 Block *topLevelBlock;
1673 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1685 DenseMap<Block *, ContextScope *> scopeMap;
1690 ContextScope *currentScope =
nullptr;
1696void FIRModuleContext::removeSymbolEntry(StringRef name) {
1697 symbolTable.erase(name);
1706ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1708 bool insertNameIntoGlobalScope) {
1711 auto [entryIt, inserted] =
1716 if (entryIt->second.first.isValid()) {
1718 emitError(loc,
"redefinition of name '" + name +
"' ")
1719 .attachNote(translateLocation(entryIt->second.first))
1720 <<
"previous definition here.";
1723 emitError(loc,
"redefinition of name '" + name +
"' ")
1724 <<
"- FIRRTL has flat namespace and requires all "
1725 <<
"declarations in a module to have unique names.";
1732 entryIt->second = {loc, entry};
1733 if (currentScope && !insertNameIntoGlobalScope)
1734 currentScope->scopedDecls.push_back(&*entryIt);
1741 StringRef name, SMLoc loc) {
1742 auto &entry = symbolTable[name];
1743 if (!entry.first.isValid())
1744 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1745 result = entry.second;
1746 assert(result &&
"name in symbol table without definition");
1750ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1752 SMLoc loc,
bool fatal) {
1753 if (!isa<Value>(entry)) {
1755 emitError(loc,
"bundle value should only be used from subfield");
1758 result = cast<Value>(entry);
1762ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1764 StringRef fieldName,
1766 if (!isa<UnbundledID>(entry)) {
1767 emitError(loc,
"value should not be used from subfield");
1771 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1773 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1774 assert(unbundledId < unbundledValues.size());
1776 for (
auto elt : ubEntry) {
1777 if (elt.first == fieldAttr) {
1778 result = elt.second;
1783 emitError(loc,
"use of invalid field name '")
1784 << fieldName <<
"' on bundle value";
1810struct LazyLocationListener :
public OpBuilder::Listener {
1811 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1812 assert(builder.getListener() ==
nullptr);
1813 builder.setListener(
this);
1816 ~LazyLocationListener() {
1817 assert(subOps.empty() &&
"didn't process parsed operations");
1818 assert(builder.getListener() ==
this);
1819 builder.setListener(
nullptr);
1822 void startStatement() {
1823 assert(!isActive &&
"Already processing a statement");
1832 Location
getLoc(FIRParser &parser, SMLoc loc) {
1834 switch (parser.getConstants().options.infoLocatorHandling) {
1835 case ILH::IgnoreInfo:
1838 case ILH::PreferInfo:
1842 case ILH::FusedInfo:
1844 return FusedLoc::get(infoLoc.getContext(),
1845 {infoLoc, parser.translateLocation(loc)});
1848 return parser.translateLocation(loc);
1853 void endStatement(FIRParser &parser) {
1854 assert(isActive &&
"Not parsing a statement");
1858 for (
auto opAndSMLoc : subOps)
1859 opAndSMLoc.first->setLoc(
getLoc(parser, opAndSMLoc.second));
1863 infoLoc = LocationAttr();
1864 currentSMLoc = SMLoc();
1869 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1872 void setInfoLoc(LocationAttr loc) {
1873 assert(!infoLoc &&
"Info location multiply specified");
1879 void notifyOperationInserted(Operation *op,
1880 mlir::IRRewriter::InsertPoint)
override {
1881 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1882 assert(isActive &&
"Not parsing a statement");
1883 subOps.push_back({op, currentSMLoc});
1888 bool isActive =
false;
1896 LocationAttr infoLoc;
1903 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1905 void operator=(
const LazyLocationListener &) =
delete;
1906 LazyLocationListener(
const LazyLocationListener &) =
delete;
1914struct InnerSymFixups {
1917 fixups.push_back({user, target});
1926 hw::InnerRefUserOpInterface innerRefUser;
1929 SmallVector<Fixup, 0> fixups;
1935 for (
auto &f : fixups) {
1938 return isnc.get(module);
1940 assert(ref &&
"unable to resolve inner symbol target");
1944 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1945 .Case<RWProbeOp>([ref](RWProbeOp op) {
1946 op.setTargetAttr(ref);
1949 .Default([](
auto *op) {
1950 return op->emitError(
"unknown inner-ref user requiring fixup");
1961struct FIRStmtParser :
public FIRParser {
1962 explicit FIRStmtParser(Block &blockToInsertInto,
1963 FIRModuleContext &moduleContext,
1964 InnerSymFixups &innerSymFixups,
1965 const SymbolTable &circuitSymTbl,
FIRVersion version,
1966 SymbolRefAttr layerSym = {})
1967 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1969 builder(UnknownLoc::
get(getContext()), getContext()),
1970 locationProcessor(this->builder), moduleContext(moduleContext),
1971 innerSymFixups(innerSymFixups), layerSym(layerSym),
1972 circuitSymTbl(circuitSymTbl) {
1973 builder.setInsertionPointToEnd(&blockToInsertInto);
1976 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1977 ParseResult parseSimpleStmtBlock(
unsigned indent);
1980 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1983 void emitInvalidate(Value val,
Flow flow);
1989 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1992 ParseResult parseOptionalInfo() {
1994 if (failed(parseOptionalInfoLocator(loc)))
1996 locationProcessor.setInfoLoc(loc);
2001 ParseResult parseExpImpl(Value &result,
const Twine &message,
2002 bool isLeadingStmt);
2003 ParseResult parseExp(Value &result,
const Twine &message) {
2004 return parseExpImpl(result, message,
false);
2006 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
2007 return parseExpImpl(result, message,
true);
2009 ParseResult parseEnumExp(Value &result);
2010 ParseResult parsePathExp(Value &result);
2011 ParseResult parseDomainExp(Value &result);
2012 ParseResult parseRefExp(Value &result,
const Twine &message);
2013 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
2014 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
2015 const Twine &message);
2018 ParseResult parseIntrinsic(Value &result,
bool isStatement);
2019 ParseResult parseIntrinsicStmt() {
2021 return parseIntrinsic(unused,
true);
2023 ParseResult parseIntrinsicExp(Value &result) {
2024 return parseIntrinsic(result,
false);
2026 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
2028 template <
typename subop>
2029 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
2030 ParseResult parseOptionalExpPostscript(Value &result,
2031 bool allowDynamic =
true);
2032 ParseResult parsePostFixFieldId(Value &result);
2033 ParseResult parsePostFixIntSubscript(Value &result);
2034 ParseResult parsePostFixDynamicSubscript(Value &result);
2036 parseIntegerLiteralExp(Value &result,
bool isSigned,
2037 std::optional<int32_t> allocatedWidth = {});
2038 ParseResult parseListExp(Value &result);
2039 ParseResult parseListConcatExp(Value &result);
2040 ParseResult parseCatExp(Value &result);
2041 ParseResult parseStringConcatExp(Value &result);
2042 ParseResult parsePropEqExp(Value &result);
2043 ParseResult parseUnsafeDomainCast(Value &result);
2044 ParseResult parseUnknownProperty(Value &result);
2046 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
2047 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2049 auto loc = getToken().getLoc();
2050 locationProcessor.setLoc(loc);
2053 auto vals = std::array<Value, M>();
2054 auto ints = std::array<int64_t, N>();
2058 for (
size_t i = 0; i < M; ++i) {
2060 if (parseToken(FIRToken::comma,
"expected ','"))
2062 if (parseExp(vals[i],
"expected expression in primitive operand"))
2068 for (
size_t i = 0; i < N; ++i) {
2070 if (parseToken(FIRToken::comma,
"expected ','"))
2072 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2077 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2081 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2085 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2086 translateLocation(loc));
2091 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2092 result = op.getResult();
2096 template <
typename T,
unsigned M,
unsigned N>
2097 ParseResult parsePrimExp(Value &result) {
2098 auto ms = std::make_index_sequence<M>();
2099 auto ns = std::make_index_sequence<N>();
2100 return parsePrim<T, M, N>(ms, ns, result);
2103 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2106 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2107 SymbolRefAttr layerSym);
2108 ParseResult parseAttach();
2109 ParseResult parseMemPort(MemDirAttr direction);
2115 ArrayRef<Value> specOperands,
2116 StringAttr &formatStringResult,
2117 SmallVectorImpl<Value> &operands);
2118 ParseResult parsePrintf();
2119 ParseResult parseFPrintf();
2120 ParseResult parseFFlush();
2121 ParseResult parseSkip();
2122 ParseResult parseStop();
2123 ParseResult parseAssert();
2124 ParseResult parseAssume();
2125 ParseResult parseCover();
2126 ParseResult parseWhen(
unsigned whenIndent);
2127 ParseResult parseMatch(
unsigned matchIndent);
2128 ParseResult parseDomainInstantiation();
2129 ParseResult parseDomainDefine();
2130 ParseResult parseRefDefine();
2131 ParseResult parseRefForce();
2132 ParseResult parseRefForceInitial();
2133 ParseResult parseRefRelease();
2134 ParseResult parseRefReleaseInitial();
2135 ParseResult parseRefRead(Value &result);
2136 ParseResult parseProbe(Value &result);
2137 ParseResult parsePropAssert();
2138 ParseResult parsePropAssign();
2139 ParseResult parseRWProbe(Value &result);
2140 ParseResult parseLeadingExpStmt(Value lhs);
2141 ParseResult parseConnect();
2142 ParseResult parseInvalidate();
2143 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2146 ParseResult parseInstance();
2147 ParseResult parseInstanceChoice();
2148 ParseResult parseObject();
2149 ParseResult parseCombMem();
2150 ParseResult parseSeqMem();
2151 ParseResult parseMem(
unsigned memIndent);
2152 ParseResult parseNode();
2153 ParseResult parseWire();
2154 ParseResult parseRegister(
unsigned regIndent);
2155 ParseResult parseRegisterWithReset();
2156 ParseResult parseContract(
unsigned blockIndent);
2159 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2162 ImplicitLocOpBuilder builder;
2163 LazyLocationListener locationProcessor;
2166 FIRModuleContext &moduleContext;
2169 InnerSymFixups &innerSymFixups;
2173 SymbolRefAttr layerSym;
2175 const SymbolTable &circuitSymTbl;
2182void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2183 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2190 auto props = tpe.getRecursiveTypeProperties();
2191 if (props.isPassive && !props.containsAnalog) {
2192 if (flow == Flow::Source)
2194 emitConnect(builder, val, InvalidValueOp::create(builder, tpe),
2195 getConstants().options.warnOnTruncation);
2206 TypeSwitch<FIRRTLType>(tpe)
2207 .Case<BundleType>([&](
auto tpe) {
2208 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2209 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2211 OpBuilder::InsertionGuard guard(builder);
2212 builder.setInsertionPointAfterValue(val);
2213 subfield = SubfieldOp::create(builder, val, i);
2215 emitInvalidate(subfield,
2216 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2219 .Case<FVectorType>([&](
auto tpe) {
2220 auto tpex = tpe.getElementType();
2221 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2222 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2224 OpBuilder::InsertionGuard guard(builder);
2225 builder.setInsertionPointAfterValue(val);
2226 subindex = SubindexOp::create(builder, tpex, val, i);
2228 emitInvalidate(subindex, flow);
2256ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2257 bool isLeadingStmt) {
2258 auto token = getToken();
2259 auto kind = token.getKind();
2261 case FIRToken::lp_integer_add:
2262 case FIRToken::lp_integer_mul:
2263 case FIRToken::lp_integer_shr:
2264 case FIRToken::lp_integer_shl:
2265 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2274#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2276 case FIRToken::lp_##SPELLING: \
2277 if (requireFeature(VERSION, FEATURE)) \
2279 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2282#include "FIRTokenKinds.def"
2284 case FIRToken::l_brace_bar:
2286 return emitError(
"unexpected enumeration as start of statement");
2287 if (parseEnumExp(result))
2290 case FIRToken::lp_read:
2292 return emitError(
"unexpected read() as start of statement");
2293 if (parseRefRead(result))
2296 case FIRToken::lp_probe:
2298 return emitError(
"unexpected probe() as start of statement");
2299 if (parseProbe(result))
2302 case FIRToken::lp_rwprobe:
2304 return emitError(
"unexpected rwprobe() as start of statement");
2305 if (parseRWProbe(result))
2309 case FIRToken::langle_UInt:
2310 case FIRToken::langle_SInt: {
2313 bool isSigned = getToken().is(FIRToken::langle_SInt);
2316 if (parseWidth(width))
2320 if (parseIntegerLiteralExp(result, isSigned, width))
2325 case FIRToken::lp_UInt:
2326 if (parseIntegerLiteralExp(result,
false))
2329 case FIRToken::lp_SInt:
2330 if (parseIntegerLiteralExp(result,
true))
2333 case FIRToken::lp_String: {
2334 if (requireFeature({3, 1, 0},
"Strings"))
2336 locationProcessor.setLoc(getToken().
getLoc());
2337 consumeToken(FIRToken::lp_String);
2339 if (parseGetSpelling(spelling) ||
2340 parseToken(FIRToken::string,
2341 "expected string literal in String expression") ||
2342 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2345 result = moduleContext.getCachedConstant<StringConstantOp>(
2346 builder, attr, builder.getType<StringType>(), attr);
2349 case FIRToken::lp_Integer: {
2350 if (requireFeature({3, 1, 0},
"Integers"))
2352 locationProcessor.setLoc(getToken().
getLoc());
2353 consumeToken(FIRToken::lp_Integer);
2355 if (parseIntLit(value,
"expected integer literal in Integer expression") ||
2356 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2358 APSInt apint(value,
false);
2359 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2360 builder, IntegerAttr::get(getContext(), apint),
2361 builder.getType<FIntegerType>(), apint);
2364 case FIRToken::lp_Bool: {
2365 if (requireFeature({6, 0, 0},
"Bools"))
2367 locationProcessor.setLoc(getToken().
getLoc());
2368 consumeToken(FIRToken::lp_Bool);
2370 if (consumeIf(FIRToken::kw_true))
2372 else if (consumeIf(FIRToken::kw_false))
2375 return emitError(
"expected true or false in Bool expression");
2376 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2378 auto attr = builder.getBoolAttr(value);
2379 result = moduleContext.getCachedConstant<BoolConstantOp>(
2380 builder, attr, builder.getType<BoolType>(), value);
2383 case FIRToken::lp_Double: {
2384 if (requireFeature({6, 0, 0},
"Doubles"))
2386 locationProcessor.setLoc(getToken().
getLoc());
2387 consumeToken(FIRToken::lp_Double);
2388 auto spelling = getTokenSpelling();
2389 if (parseToken(FIRToken::floatingpoint,
2390 "expected floating point in Double expression") ||
2391 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2396 if (!llvm::to_float(spelling, d))
2397 return emitError(
"invalid double");
2398 auto attr = builder.getF64FloatAttr(d);
2399 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2400 builder, attr, builder.getType<DoubleType>(), attr);
2403 case FIRToken::lp_List:
2404 case FIRToken::langle_List: {
2405 if (requireFeature({4, 0, 0},
"Lists"))
2408 return emitError(
"unexpected List<>() as start of statement");
2409 if (parseListExp(result))
2414 case FIRToken::lp_list_concat: {
2416 return emitError(
"unexpected list_create() as start of statement");
2417 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2422 case FIRToken::lp_path:
2424 return emitError(
"unexpected path() as start of statement");
2425 if (requireFeature({6, 0, 0},
"Paths") || parsePathExp(result))
2429 case FIRToken::lp_intrinsic:
2430 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2431 parseIntrinsicExp(result))
2435 case FIRToken::lp_cat:
2436 if (parseCatExp(result))
2440 case FIRToken::lp_string_concat:
2441 if (parseStringConcatExp(result))
2445 case FIRToken::lp_prop_eq:
2446 if (requireFeature({6, 0, 0},
"property equality") ||
2447 parsePropEqExp(result))
2451 case FIRToken::lp_unsafe_domain_cast:
2453 parseUnsafeDomainCast(result))
2456 case FIRToken::lp_Unknown:
2457 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2458 parseUnknownProperty(result))
2464 case FIRToken::identifier:
2465 case FIRToken::literal_identifier:
2466 case FIRToken::kw_UInt:
2467 case FIRToken::kw_SInt:
2468 case FIRToken::kw_String:
2469 case FIRToken::kw_Integer:
2470 case FIRToken::kw_Bool:
2471 case FIRToken::kw_Double:
2472 case FIRToken::kw_List:
2475 auto loc = getToken().getLoc();
2477 if (parseId(name, message) ||
2478 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2482 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2485 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2490 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2491 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2492 parseOptionalInfo())
2495 locationProcessor.setLoc(loc);
2497 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2499 moduleContext.getUnbundledEntry(unbundledId);
2500 for (
auto elt : ubEntry)
2501 emitInvalidate(elt.second);
2509 StringRef fieldName;
2510 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2511 parseFieldId(fieldName,
"expected field name") ||
2512 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2520 case FIRToken::lp_shr:
2523 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2524 result = PadPrimOp::create(builder, result, 1);
2530 return parseOptionalExpPostscript(result);
2540ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2541 bool allowDynamic) {
2546 if (consumeIf(FIRToken::period)) {
2547 if (parsePostFixFieldId(result))
2554 if (consumeIf(FIRToken::l_square)) {
2555 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2556 if (parsePostFixIntSubscript(result))
2561 return emitError(
"subaccess not allowed here");
2562 if (parsePostFixDynamicSubscript(result))
2572template <
typename subop>
2574FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2576 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2582 auto baseType = cast<FIRRTLType>(base.getType());
2583 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2586 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2592 locationProcessor.setLoc(loc);
2593 OpBuilder::InsertionGuard guard(builder);
2594 builder.setInsertionPointAfterValue(base);
2595 auto op = subop::create(builder, resultType, base, indexNo);
2598 return value = op.getResult();
2605ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2606 auto loc = getToken().getLoc();
2607 SmallVector<StringRef, 3> fields;
2608 if (parseFieldIdSeq(fields,
"expected field name"))
2610 for (
auto fieldName : fields) {
2611 std::optional<unsigned> indexV;
2612 auto type = result.getType();
2613 if (
auto refTy = type_dyn_cast<RefType>(type))
2614 type = refTy.getType();
2615 if (
auto bundle = type_dyn_cast<BundleType>(type))
2616 indexV = bundle.getElementIndex(fieldName);
2617 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2618 indexV = bundle.getElementIndex(fieldName);
2619 else if (
auto klass = type_dyn_cast<ClassType>(type))
2620 indexV = klass.getElementIndex(fieldName);
2621 else if (
auto domain = type_dyn_cast<DomainType>(type))
2622 indexV = domain.getFieldIndex(fieldName);
2624 return emitError(loc,
2625 "subfield requires bundle, object, or domain operand ");
2627 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2628 << result.getType();
2629 auto indexNo = *indexV;
2631 FailureOr<Value> subResult;
2632 if (type_isa<RefType>(result.getType()))
2633 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2634 else if (type_isa<ClassType>(type))
2635 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2636 else if (type_isa<DomainType>(type))
2637 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2638 else if (type_isa<BundleType>(type))
2639 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2641 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2643 if (failed(subResult))
2645 result = *subResult;
2654ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2655 auto loc = getToken().getLoc();
2657 if (parseIntLit(indexNo,
"expected index") ||
2658 parseToken(FIRToken::r_square,
"expected ']'"))
2662 return emitError(loc,
"invalid index specifier"), failure();
2664 FailureOr<Value> subResult;
2665 if (type_isa<RefType>(result.getType()))
2666 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2667 else if (type_isa<FVectorType>(result.getType()))
2668 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2670 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2672 if (failed(subResult))
2674 result = *subResult;
2682ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2683 auto loc = getToken().getLoc();
2685 if (parseExp(index,
"expected subscript index expression") ||
2686 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2690 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2692 return emitError(
"expected base type for index expression");
2693 indexType = indexType.getPassiveType();
2694 locationProcessor.setLoc(loc);
2699 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2702 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2703 translateLocation(loc));
2708 auto op = SubaccessOp::create(builder, resultType, result, index);
2709 result = op.getResult();
2720FIRStmtParser::parseIntegerLiteralExp(Value &result,
bool isSigned,
2721 std::optional<int32_t> allocatedWidth) {
2722 auto loc = getToken().getLoc();
2725 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2730 int32_t width = allocatedWidth.value_or(-1);
2736 parseToken(FIRToken::l_paren,
"expected '(' in integer expression"))
2739 if (parseIntLit(value,
"expected integer value") ||
2740 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2745 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2747 IntegerType::SignednessSemantics signedness =
2748 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2750 if (!value.isZero())
2751 return emitError(loc,
"zero bit constant must be zero");
2752 value = value.trunc(0);
2753 }
else if (width != -1) {
2755 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2757 return emitError(loc,
"initializer too wide for declared width");
2758 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2762 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2763 auto attr = builder.getIntegerAttr(attrType, value);
2765 locationProcessor.setLoc(loc);
2766 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2771ParseResult FIRStmtParser::parseListExp(Value &result) {
2772 auto loc = getToken().getLoc();
2773 bool hasLAngle = getToken().is(FIRToken::langle_List);
2774 bool hasLParen = getToken().is(FIRToken::lp_List);
2779 if (!hasLAngle && parseToken(FIRToken::less,
"expected '<' in List type"))
2782 if (parsePropertyType(
elementType,
"expected List element type") ||
2783 parseToken(FIRToken::greater,
"expected '>' in List type"))
2786 auto listType = ListType::get(getContext(),
elementType);
2790 parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2793 SmallVector<Value, 3> operands;
2794 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2796 locationProcessor.setLoc(loc);
2797 if (parseExp(operand,
"expected expression in List expression"))
2801 if (!isa<AnyRefType>(elementType) ||
2802 !isa<ClassType>(operand.getType()))
2803 return emitError(loc,
"unexpected expression of type ")
2804 << operand.getType() <<
" in List expression of type "
2806 operand = ObjectAnyRefCastOp::create(builder, operand);
2809 operands.push_back(operand);
2814 locationProcessor.setLoc(loc);
2815 result = ListCreateOp::create(builder, listType, operands);
2820ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2821 consumeToken(FIRToken::lp_list_concat);
2823 auto loc = getToken().getLoc();
2825 SmallVector<Value, 3> operands;
2826 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2828 locationProcessor.setLoc(loc);
2829 if (parseExp(operand,
"expected expression in List concat expression"))
2832 if (!type_isa<ListType>(operand.getType()))
2833 return emitError(loc,
"unexpected expression of type ")
2834 << operand.getType() <<
" in List concat expression";
2837 type = type_cast<ListType>(operand.getType());
2839 if (operand.getType() != type)
2840 return emitError(loc,
"unexpected expression of type ")
2841 << operand.getType() <<
" in List concat expression of type "
2844 operands.push_back(operand);
2849 if (operands.empty())
2850 return emitError(loc,
"need at least one List to concatenate");
2852 locationProcessor.setLoc(loc);
2853 result = ListConcatOp::create(builder, type, operands);
2858ParseResult FIRStmtParser::parseCatExp(Value &result) {
2859 consumeToken(FIRToken::lp_cat);
2861 auto loc = getToken().getLoc();
2862 SmallVector<Value, 3> operands;
2863 std::optional<bool> isSigned;
2864 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2866 locationProcessor.setLoc(loc);
2867 auto operandLoc = getToken().getLoc();
2868 if (parseExp(operand,
"expected expression in cat expression"))
2870 if (!type_isa<IntType>(operand.getType())) {
2871 auto diag = emitError(loc,
"all operands must be Int type");
2872 diag.attachNote(translateLocation(operandLoc))
2873 <<
"non-integer operand is here";
2877 isSigned = type_isa<SIntType>(operand.getType());
2878 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2879 auto diag = emitError(loc,
"all operands must have same signedness");
2880 diag.attachNote(translateLocation(operandLoc))
2881 <<
"operand with different signedness is here";
2885 operands.push_back(operand);
2890 if (operands.size() != 2) {
2891 if (requireFeature({6, 0, 0},
"variadic cat", loc))
2895 locationProcessor.setLoc(loc);
2896 result = CatPrimOp::create(builder, operands);
2901ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2902 consumeToken(FIRToken::lp_string_concat);
2904 auto loc = getToken().getLoc();
2905 SmallVector<Value, 3> operands;
2906 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2908 locationProcessor.setLoc(loc);
2909 if (parseExp(operand,
2910 "expected expression in string_concat expression"))
2912 if (!type_isa<StringType>(operand.getType()))
2913 return emitError(loc,
"all operands must be String type");
2914 operands.push_back(operand);
2919 if (operands.empty())
2920 return emitError(loc,
"need at least one String to concatenate");
2922 locationProcessor.setLoc(loc);
2923 auto type = StringType::get(builder.getContext());
2924 result = builder.create<StringConcatOp>(type, operands);
2929ParseResult FIRStmtParser::parsePropEqExp(Value &result) {
2930 consumeToken(FIRToken::lp_prop_eq);
2932 auto loc = getToken().getLoc();
2934 locationProcessor.setLoc(loc);
2935 if (parseExp(lhs,
"expected lhs expression in prop_eq expression") ||
2936 parseToken(FIRToken::comma,
"expected ','") ||
2937 parseExp(rhs,
"expected rhs expression in prop_eq expression") ||
2938 parseToken(FIRToken::r_paren,
"expected ')'"))
2941 auto isValidType = [](Type t) {
2942 return type_isa<StringType>(t) || type_isa<BoolType>(t) ||
2943 type_isa<FIntegerType>(t);
2945 if (!isValidType(lhs.getType()))
2946 return emitError(loc,
2947 "lhs of prop_eq must be String, Bool, or Integer type");
2948 if (!isValidType(rhs.getType()))
2949 return emitError(loc,
2950 "rhs of prop_eq must be String, Bool, or Integer type");
2951 if (lhs.getType() != rhs.getType())
2952 return emitError(loc,
"prop_eq operands must have the same type");
2954 locationProcessor.setLoc(loc);
2955 result = PropEqOp::create(builder, lhs, rhs);
2959ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2960 consumeToken(FIRToken::lp_unsafe_domain_cast);
2962 auto loc = getToken().getLoc();
2964 if (parseExp(input,
"expected input"))
2967 SmallVector<Value> domains;
2968 if (consumeIf(FIRToken::comma)) {
2969 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2971 if (parseExp(domain,
"expected domain"))
2973 domains.push_back(domain);
2977 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2981 locationProcessor.setLoc(loc);
2982 result = UnsafeDomainCastOp::create(builder, input, domains);
2986ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2987 auto loc = getToken().getLoc();
2988 consumeToken(FIRToken::lp_Unknown);
2992 if (parsePropertyType(type,
"expected property type") ||
2993 parseToken(FIRToken::r_paren,
"expected ')' in unknown property"))
2996 locationProcessor.setLoc(loc);
2997 result = UnknownValueOp::create(builder, type);
3018std::optional<ParseResult>
3019FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
3020 switch (getToken().getKind()) {
3023 return std::nullopt;
3025 case FIRToken::period:
3026 case FIRToken::l_square:
3027 case FIRToken::kw_is:
3028 case FIRToken::less_equal:
3034 auto loc = keyword.
getLoc();
3036 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
3037 return ParseResult(failure());
3043 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
3046 if (!consumeIf(FIRToken::period))
3047 return ParseResult(failure());
3049 StringRef fieldName;
3050 if (parseFieldId(fieldName,
"expected field name") ||
3051 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
3052 return ParseResult(failure());
3056 if (parseOptionalExpPostscript(lhs))
3057 return ParseResult(failure());
3059 return parseLeadingExpStmt(lhs);
3065ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
3068 if (getToken().isAny(FIRToken::eof, FIRToken::error))
3071 auto subIndent = getIndentation();
3072 if (!subIndent.has_value())
3073 return emitError(
"expected statement to be on its own line"), failure();
3075 if (*subIndent <= indent)
3079 if (parseSimpleStmt(*subIndent))
3084ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
3085 locationProcessor.startStatement();
3086 auto result = parseSimpleStmtImpl(stmtIndent);
3087 locationProcessor.endStatement(*
this);
3110ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
3111 auto kind = getToken().getKind();
3114 case FIRToken::kw_invalidate:
3115 case FIRToken::kw_connect:
3116 case FIRToken::kw_regreset:
3120 kind = FIRToken::identifier;
3127 case FIRToken::kw_attach:
3128 return parseAttach();
3129 case FIRToken::kw_infer:
3130 return parseMemPort(MemDirAttr::Infer);
3131 case FIRToken::kw_read:
3132 return parseMemPort(MemDirAttr::Read);
3133 case FIRToken::kw_write:
3134 return parseMemPort(MemDirAttr::Write);
3135 case FIRToken::kw_rdwr:
3136 return parseMemPort(MemDirAttr::ReadWrite);
3137 case FIRToken::kw_connect:
3138 return parseConnect();
3139 case FIRToken::kw_propassert:
3140 if (requireFeature({6, 0, 0},
"property assertions"))
3142 return parsePropAssert();
3143 case FIRToken::kw_propassign:
3144 if (requireFeature({3, 1, 0},
"properties"))
3146 return parsePropAssign();
3147 case FIRToken::kw_invalidate:
3148 return parseInvalidate();
3149 case FIRToken::lp_printf:
3150 return parsePrintf();
3151 case FIRToken::lp_fprintf:
3152 return parseFPrintf();
3153 case FIRToken::lp_fflush:
3154 return parseFFlush();
3155 case FIRToken::kw_skip:
3157 case FIRToken::lp_stop:
3159 case FIRToken::lp_assert:
3160 return parseAssert();
3161 case FIRToken::lp_assume:
3162 return parseAssume();
3163 case FIRToken::lp_cover:
3164 return parseCover();
3165 case FIRToken::kw_when:
3166 return parseWhen(stmtIndent);
3167 case FIRToken::kw_match:
3168 return parseMatch(stmtIndent);
3169 case FIRToken::kw_domain:
3171 return parseDomainInstantiation();
3172 case FIRToken::kw_domain_define:
3173 return parseDomainDefine();
3174 case FIRToken::kw_define:
3175 return parseRefDefine();
3176 case FIRToken::lp_force:
3177 return parseRefForce();
3178 case FIRToken::lp_force_initial:
3179 return parseRefForceInitial();
3180 case FIRToken::lp_release:
3181 return parseRefRelease();
3182 case FIRToken::lp_release_initial:
3183 return parseRefReleaseInitial();
3184 case FIRToken::kw_group:
3185 if (requireFeature({3, 2, 0},
"optional groups") ||
3186 removedFeature({3, 3, 0},
"optional groups"))
3188 return parseLayerBlockOrGroup(stmtIndent);
3189 case FIRToken::kw_layerblock:
3190 if (requireFeature({3, 3, 0},
"layers"))
3192 return parseLayerBlockOrGroup(stmtIndent);
3193 case FIRToken::lp_intrinsic:
3194 if (requireFeature({4, 0, 0},
"generic intrinsics"))
3196 return parseIntrinsicStmt();
3200 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
3207 return parseLeadingExpStmt(lhs);
3211 case FIRToken::kw_inst:
3212 return parseInstance();
3213 case FIRToken::kw_instchoice:
3214 return parseInstanceChoice();
3215 case FIRToken::kw_object:
3216 return parseObject();
3217 case FIRToken::kw_cmem:
3218 return parseCombMem();
3219 case FIRToken::kw_smem:
3220 return parseSeqMem();
3221 case FIRToken::kw_mem:
3222 return parseMem(stmtIndent);
3223 case FIRToken::kw_node:
3225 case FIRToken::kw_wire:
3227 case FIRToken::kw_reg:
3228 return parseRegister(stmtIndent);
3229 case FIRToken::kw_regreset:
3230 return parseRegisterWithReset();
3231 case FIRToken::kw_contract:
3232 return parseContract(stmtIndent);
3236ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3238 SymbolRefAttr layerSym) {
3240 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3241 moduleContext, &blockToInsertInto);
3246 UnbundledValueRestorer x(moduleContext.unbundledValues);
3250 auto subParser = std::make_unique<FIRStmtParser>(
3251 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3255 auto stmtIndent = getIndentation();
3258 if (!stmtIndent.has_value())
3259 return subParser->parseSimpleStmt(indent);
3261 if (*stmtIndent <= indent)
3262 return emitError(
"statement must be indented more than previous statement"),
3266 return subParser->parseSimpleStmtBlock(indent);
3270ParseResult FIRStmtParser::parseAttach() {
3271 auto startTok = consumeToken(FIRToken::kw_attach);
3274 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3277 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3280 SmallVector<Value, 4> operands;
3281 operands.push_back({});
3282 if (parseExp(operands.back(),
"expected operand in attach"))
3285 while (consumeIf(FIRToken::comma)) {
3286 operands.push_back({});
3287 if (parseExp(operands.back(),
"expected operand in attach"))
3290 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3293 if (parseOptionalInfo())
3296 locationProcessor.setLoc(startTok.getLoc());
3297 AttachOp::create(builder, operands);
3304ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3305 auto startTok = consumeToken();
3306 auto startLoc = startTok.getLoc();
3310 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3316 Value memory, indexExp, clock;
3317 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3318 parseId(
id,
"expected result name") ||
3319 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3320 parseId(memName,
"expected memory name") ||
3321 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3322 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3323 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3324 parseExp(indexExp,
"expected index expression") ||
3325 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3326 parseToken(FIRToken::comma,
"expected ','") ||
3327 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3330 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3332 return emitError(startLoc,
3333 "memory port should have behavioral memory type");
3334 auto resultType = memVType.getElementType();
3336 ArrayAttr annotations = getConstants().emptyArrayAttr;
3337 locationProcessor.setLoc(startLoc);
3340 Value memoryPort, memoryData;
3342 OpBuilder::InsertionGuard guard(builder);
3343 builder.setInsertionPointAfterValue(memory);
3344 auto memoryPortOp = MemoryPortOp::create(
3345 builder, resultType, CMemoryPortType::get(getContext()), memory,
3346 direction,
id, annotations);
3347 memoryData = memoryPortOp.getResult(0);
3348 memoryPort = memoryPortOp.getResult(1);
3352 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3354 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3360ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3361 StringRef formatString,
3362 ArrayRef<Value> specOperands,
3363 StringAttr &formatStringResult,
3364 SmallVectorImpl<Value> &operands) {
3367 operands.append(specOperands.begin(), specOperands.end());
3368 formatStringResult =
3374 auto loc = translateLocation(formatStringLoc);
3377 formatStringResult, operands);
3382ParseResult FIRStmtParser::parsePrintf() {
3383 auto startTok = consumeToken(FIRToken::lp_printf);
3385 Value clock, condition;
3386 StringRef formatString;
3387 if (parseExp(clock,
"expected clock expression in printf") ||
3388 parseToken(FIRToken::comma,
"expected ','") ||
3389 parseExp(condition,
"expected condition in printf") ||
3390 parseToken(FIRToken::comma,
"expected ','"))
3393 auto formatStringLoc = getToken().getLoc();
3394 if (parseGetSpelling(formatString) ||
3395 parseToken(FIRToken::string,
"expected format string in printf"))
3398 SmallVector<Value, 4> specOperands;
3399 while (consumeIf(FIRToken::comma)) {
3400 specOperands.push_back({});
3401 if (parseExp(specOperands.back(),
"expected operand in printf"))
3406 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3407 parseOptionalName(name) || parseOptionalInfo())
3410 locationProcessor.setLoc(startTok.getLoc());
3412 StringAttr formatStrUnescaped;
3413 SmallVector<Value> operands;
3415 formatStrUnescaped, operands))
3418 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3424ParseResult FIRStmtParser::parseFPrintf() {
3425 if (requireFeature({6, 0, 0},
"fprintf"))
3427 auto startTok = consumeToken(FIRToken::lp_fprintf);
3429 Value clock, condition;
3430 StringRef outputFile, formatString;
3431 if (parseExp(clock,
"expected clock expression in fprintf") ||
3432 parseToken(FIRToken::comma,
"expected ','") ||
3433 parseExp(condition,
"expected condition in fprintf") ||
3434 parseToken(FIRToken::comma,
"expected ','"))
3437 auto outputFileLoc = getToken().getLoc();
3438 if (parseGetSpelling(outputFile) ||
3439 parseToken(FIRToken::string,
"expected output file in fprintf"))
3442 SmallVector<Value, 4> outputFileSpecOperands;
3443 while (consumeIf(FIRToken::comma)) {
3445 if (getToken().getKind() == FIRToken::string)
3447 outputFileSpecOperands.push_back({});
3448 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3452 auto formatStringLoc = getToken().getLoc();
3453 if (parseGetSpelling(formatString) ||
3454 parseToken(FIRToken::string,
"expected format string in printf"))
3457 SmallVector<Value, 4> specOperands;
3458 while (consumeIf(FIRToken::comma)) {
3459 specOperands.push_back({});
3460 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3465 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3466 parseOptionalName(name) || parseOptionalInfo())
3469 locationProcessor.setLoc(startTok.getLoc());
3471 StringAttr outputFileNameStrUnescaped;
3472 SmallVector<Value> outputFileOperands;
3474 outputFileNameStrUnescaped, outputFileOperands))
3477 StringAttr formatStrUnescaped;
3478 SmallVector<Value> operands;
3480 formatStrUnescaped, operands))
3483 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3484 outputFileOperands, formatStrUnescaped, operands, name);
3489ParseResult FIRStmtParser::parseFFlush() {
3490 if (requireFeature({6, 0, 0},
"fflush"))
3493 auto startTok = consumeToken(FIRToken::lp_fflush);
3495 Value clock, condition;
3496 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3497 parseToken(FIRToken::comma,
"expected ','") ||
3498 parseExp(condition,
"expected condition in 'fflush'"))
3501 locationProcessor.setLoc(startTok.getLoc());
3502 StringAttr outputFileNameStrUnescaped;
3503 SmallVector<Value> outputFileOperands;
3505 if (consumeIf(FIRToken::comma)) {
3506 SmallVector<Value, 4> outputFileSpecOperands;
3507 auto outputFileLoc = getToken().getLoc();
3508 StringRef outputFile;
3509 if (parseGetSpelling(outputFile) ||
3510 parseToken(FIRToken::string,
"expected output file in fflush"))
3513 while (consumeIf(FIRToken::comma)) {
3514 outputFileSpecOperands.push_back({});
3515 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3520 outputFileNameStrUnescaped, outputFileOperands))
3524 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3525 parseOptionalInfo())
3528 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3529 outputFileOperands);
3534ParseResult FIRStmtParser::parseSkip() {
3535 auto startTok = consumeToken(FIRToken::kw_skip);
3539 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3542 if (parseOptionalInfo())
3545 locationProcessor.setLoc(startTok.getLoc());
3546 SkipOp::create(builder);
3551ParseResult FIRStmtParser::parseStop() {
3552 auto startTok = consumeToken(FIRToken::lp_stop);
3554 Value clock, condition;
3557 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3558 parseToken(FIRToken::comma,
"expected ','") ||
3559 parseExp(condition,
"expected condition in 'stop'") ||
3560 parseToken(FIRToken::comma,
"expected ','") ||
3561 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3562 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3563 parseOptionalName(name) || parseOptionalInfo())
3566 locationProcessor.setLoc(startTok.getLoc());
3567 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3573ParseResult FIRStmtParser::parseAssert() {
3574 auto startTok = consumeToken(FIRToken::lp_assert);
3576 Value clock, predicate, enable;
3577 StringRef formatString;
3579 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3580 parseToken(FIRToken::comma,
"expected ','") ||
3581 parseExp(predicate,
"expected predicate in 'assert'") ||
3582 parseToken(FIRToken::comma,
"expected ','") ||
3583 parseExp(enable,
"expected enable in 'assert'") ||
3584 parseToken(FIRToken::comma,
"expected ','") ||
3585 parseGetSpelling(formatString) ||
3586 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3589 SmallVector<Value, 4> operands;
3590 while (!consumeIf(FIRToken::r_paren)) {
3591 operands.push_back({});
3592 if (parseToken(FIRToken::comma,
"expected ','") ||
3593 parseExp(operands.back(),
"expected operand in 'assert'"))
3597 if (parseOptionalName(name) || parseOptionalInfo())
3600 locationProcessor.setLoc(startTok.getLoc());
3602 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3603 operands, name.getValue());
3608ParseResult FIRStmtParser::parseAssume() {
3609 auto startTok = consumeToken(FIRToken::lp_assume);
3611 Value clock, predicate, enable;
3612 StringRef formatString;
3614 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3615 parseToken(FIRToken::comma,
"expected ','") ||
3616 parseExp(predicate,
"expected predicate in 'assume'") ||
3617 parseToken(FIRToken::comma,
"expected ','") ||
3618 parseExp(enable,
"expected enable in 'assume'") ||
3619 parseToken(FIRToken::comma,
"expected ','") ||
3620 parseGetSpelling(formatString) ||
3621 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3624 SmallVector<Value, 4> operands;
3625 while (!consumeIf(FIRToken::r_paren)) {
3626 operands.push_back({});
3627 if (parseToken(FIRToken::comma,
"expected ','") ||
3628 parseExp(operands.back(),
"expected operand in 'assume'"))
3632 if (parseOptionalName(name) || parseOptionalInfo())
3635 locationProcessor.setLoc(startTok.getLoc());
3637 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3638 operands, name.getValue());
3643ParseResult FIRStmtParser::parseCover() {
3644 auto startTok = consumeToken(FIRToken::lp_cover);
3646 Value clock, predicate, enable;
3649 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3650 parseToken(FIRToken::comma,
"expected ','") ||
3651 parseExp(predicate,
"expected predicate in 'cover'") ||
3652 parseToken(FIRToken::comma,
"expected ','") ||
3653 parseExp(enable,
"expected enable in 'cover'") ||
3654 parseToken(FIRToken::comma,
"expected ','") ||
3655 parseGetSpelling(message) ||
3656 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3657 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3658 parseOptionalName(name) || parseOptionalInfo())
3661 locationProcessor.setLoc(startTok.getLoc());
3663 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3664 ValueRange{}, name.getValue());
3670ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3671 auto startTok = consumeToken(FIRToken::kw_when);
3675 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3679 if (parseExp(condition,
"expected condition in 'when'") ||
3680 parseToken(FIRToken::colon,
"expected ':' in when") ||
3681 parseOptionalInfo())
3684 locationProcessor.setLoc(startTok.getLoc());
3686 auto whenStmt = WhenOp::create(builder, condition,
false);
3689 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3693 if (getToken().isNot(FIRToken::kw_else))
3698 auto elseIndent = getIndentation();
3699 if (elseIndent && *elseIndent < whenIndent)
3702 consumeToken(FIRToken::kw_else);
3705 whenStmt.createElseRegion();
3711 if (getToken().is(FIRToken::kw_when)) {
3713 auto subParser = std::make_unique<FIRStmtParser>(
3714 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3717 return subParser->parseSimpleStmt(whenIndent);
3721 LocationAttr elseLoc;
3722 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3723 parseOptionalInfoLocator(elseLoc) ||
3724 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3733ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3734 auto startLoc = getToken().getLoc();
3735 locationProcessor.setLoc(startLoc);
3737 if (parseEnumType(type))
3741 auto enumType = type_dyn_cast<FEnumType>(type);
3743 return emitError(startLoc,
3744 "expected enumeration type in enumeration expression");
3747 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3748 parseId(tag,
"expected enumeration tag"))
3752 if (consumeIf(FIRToken::r_paren)) {
3755 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3756 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3757 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3758 input = ConstantOp::create(builder, type, attr);
3761 if (parseToken(FIRToken::comma,
"expected ','") ||
3762 parseExp(input,
"expected expression in enumeration value") ||
3763 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3767 value = FEnumCreateOp::create(builder, enumType, tag, input);
3775ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3776 auto startTok = consumeToken(FIRToken::kw_match);
3778 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3782 if (parseExp(input,
"expected expression in 'match'") ||
3783 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3784 parseOptionalInfo())
3787 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3789 return mlir::emitError(
3791 "expected enumeration type for 'match' statement, but got ")
3794 locationProcessor.setLoc(startTok.getLoc());
3796 SmallVector<Attribute> tags;
3797 SmallVector<std::unique_ptr<Region>> regions;
3799 auto tagLoc = getToken().getLoc();
3802 auto caseIndent = getIndentation();
3803 if (!caseIndent || *caseIndent <= matchIndent)
3807 StringRef tagSpelling;
3808 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3810 auto tagIndex = enumType.getElementIndex(tagSpelling);
3812 return emitError(tagLoc,
"tag ")
3813 << tagSpelling <<
" not a member of enumeration " << enumType;
3814 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3815 tags.push_back(tag);
3818 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3821 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3826 UnbundledValueRestorer x(moduleContext.unbundledValues);
3829 if (consumeIf(FIRToken::l_paren)) {
3830 StringAttr identifier;
3831 if (parseId(identifier,
"expected identifier for 'case' binding"))
3835 auto dataType = enumType.getElementType(*tagIndex);
3836 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3838 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3842 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3846 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3847 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3850 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3854 auto subParser = std::make_unique<FIRStmtParser>(
3855 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3857 if (subParser->parseSimpleStmtBlock(*caseIndent))
3861 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3868ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3869 auto loc = getToken().getLoc();
3872 if (parseId(
id,
"expected domain expression") ||
3873 moduleContext.lookupSymbolEntry(entry,
id, loc))
3876 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3878 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3879 parseFieldId(field,
"expected field name") ||
3880 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3884 if (parseOptionalExpPostscript(result,
false))
3887 auto type = result.getType();
3888 if (!type_isa<DomainType>(type))
3889 return emitError(loc) <<
"expected domain-type expression, got " << type;
3896ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3897 auto token = getToken().getKind();
3898 if (token == FIRToken::lp_probe)
3899 return parseProbe(result);
3900 if (token == FIRToken::lp_rwprobe)
3901 return parseRWProbe(result);
3906 return parseStaticRefExp(result, message);
3913ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3914 const Twine &message) {
3915 auto parseIdOrInstance = [&]() -> ParseResult {
3917 auto loc = getToken().getLoc();
3919 if (parseId(
id, message) ||
3920 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3924 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3927 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3930 StringRef fieldName;
3932 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3933 parseFieldId(fieldName,
"expected field name") ||
3934 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3936 return failure(parseIdOrInstance() ||
3937 parseOptionalExpPostscript(result,
false));
3948ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3950 const Twine &message) {
3951 auto loc = getToken().getLoc();
3955 if (parseId(
id, message) ||
3956 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3968 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3970 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3972 StringRef fieldName;
3973 auto loc = getToken().getLoc();
3974 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3975 parseFieldId(fieldName,
"expected field name"))
3980 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3981 for (
auto &elt : ubEntry) {
3982 if (elt.first == fieldAttr) {
3985 auto &instResult = elt.second;
3988 auto *defining = instResult.getDefiningOp();
3990 if (isa<WireOp>(defining)) {
3991 result = instResult;
3996 auto type = instResult.getType();
4000 auto annotations = getConstants().emptyArrayAttr;
4001 StringAttr sym = {};
4002 SmallString<64> name;
4003 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
4004 locationProcessor.setLoc(loc);
4005 OpBuilder::InsertionGuard guard(builder);
4006 builder.setInsertionPoint(defining);
4008 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
4010 auto bounceVal = bounce.getDataRaw();
4013 instResult.replaceAllUsesWith(bounceVal);
4016 builder.setInsertionPointAfter(defining);
4017 if (
foldFlow(instResult) == Flow::Source)
4019 getConstants().options.warnOnTruncation);
4022 getConstants().options.warnOnTruncation);
4026 result = instResult = bounce.getDataRaw();
4032 emitError(loc,
"use of invalid field name '")
4033 << fieldName <<
"' on bundle value";
4038 result = cast<Value>(symtabEntry);
4042 assert(isa<BlockArgument>(result) ||
4043 result.getDefiningOp<hw::InnerSymbolOpInterface>());
4049 type = result.getType();
4051 if (consumeIf(FIRToken::period)) {
4052 SmallVector<StringRef, 3> fields;
4053 if (parseFieldIdSeq(fields,
"expected field name"))
4055 for (
auto fieldName : fields) {
4056 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4057 if (
auto index = bundle.getElementIndex(fieldName)) {
4058 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4059 type = bundle.getElementTypePreservingConst(*index);
4062 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
4063 if (
auto index = bundle.getElementIndex(fieldName)) {
4064 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4065 type = bundle.getElementTypePreservingConst(*index);
4069 return emitError(loc,
"subfield requires bundle operand")
4070 <<
"got " << type <<
"\n";
4072 return emitError(loc,
4073 "unknown field '" + fieldName +
"' in bundle type ")
4078 if (consumeIf(FIRToken::l_square)) {
4079 auto loc = getToken().
getLoc();
4081 if (parseIntLit(index,
"expected index") ||
4082 parseToken(FIRToken::r_square,
"expected ']'"))
4086 return emitError(loc,
"invalid index specifier");
4088 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
4089 if ((
unsigned)index < vector.getNumElements()) {
4090 refResult = refResult.
getSubField(vector.getFieldID(index));
4091 type = vector.getElementTypePreservingConst();
4094 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
4095 if ((
unsigned)index < vector.getNumElements()) {
4096 refResult = refResult.
getSubField(vector.getFieldID(index));
4097 type = vector.getElementTypePreservingConst();
4101 return emitError(loc,
"subindex requires vector operand");
4103 return emitError(loc,
"out of range index '")
4104 << index <<
"' for vector type " << type;
4112ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4113 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4114 StringRef intrinsic;
4115 ArrayAttr parameters;
4118 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4119 parseOptionalParams(parameters))
4122 if (consumeIf(FIRToken::colon)) {
4123 if (
parseType(type,
"expected intrinsic return type"))
4125 }
else if (!isStatement)
4126 return emitError(
"expected ':' in intrinsic expression");
4128 SmallVector<Value> operands;
4129 auto loc = startTok.getLoc();
4130 if (consumeIf(FIRToken::comma)) {
4131 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4133 if (parseExp(operand,
"expected operand in intrinsic"))
4135 operands.push_back(operand);
4136 locationProcessor.setLoc(loc);
4141 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4146 if (parseOptionalInfo())
4149 locationProcessor.setLoc(loc);
4151 auto op = GenericIntrinsicOp::create(
4152 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4154 result = op.getResult();
4159ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4160 if (!consumeIf(FIRToken::less))
4163 SmallVector<Attribute, 8> parameters;
4164 SmallPtrSet<StringAttr, 8> seen;
4165 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4169 if (parseParameter(name, value, loc))
4171 auto typedValue = dyn_cast<TypedAttr>(value);
4173 return emitError(loc)
4174 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4175 if (!seen.insert(name).second)
4176 return emitError(loc,
"redefinition of parameter '" +
4177 name.getValue() +
"'");
4178 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4183 resultParameters = ArrayAttr::get(getContext(), parameters);
4189ParseResult FIRStmtParser::parsePathExp(Value &result) {
4190 auto startTok = consumeToken(FIRToken::lp_path);
4191 locationProcessor.setLoc(startTok.getLoc());
4193 if (parseGetSpelling(target) ||
4194 parseToken(FIRToken::string,
4195 "expected target string in path expression") ||
4196 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4198 result = UnresolvedPathOp::create(
4204ParseResult FIRStmtParser::parseDomainInstantiation() {
4205 auto startTok = consumeToken(FIRToken::kw_domain);
4206 auto startLoc = startTok.getLoc();
4209 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4212 locationProcessor.setLoc(startTok.getLoc());
4214 StringAttr instanceName;
4215 StringAttr domainKind;
4218 parseId(instanceName,
"expected domain instance name") ||
4219 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4220 parseId(domainKind,
"expected domain type name"))
4225 const auto &domainMap = getConstants().domainMap;
4226 auto lookup = domainMap.find(domainKind.getValue());
4227 if (lookup == domainMap.end())
4228 return emitError(startTok.getLoc())
4229 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4231 auto domainType = DomainType::getFromDomainOp(lookup->second);
4234 SmallVector<Value> fieldValues;
4235 if (consumeIf(FIRToken::l_paren)) {
4237 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4239 if (parseExp(value,
"expected field value expression"))
4241 fieldValues.push_back(value);
4247 if (parseOptionalInfo())
4250 locationProcessor.setLoc(startLoc);
4252 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4255 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4260ParseResult FIRStmtParser::parseDomainDefine() {
4261 auto startTok = consumeToken(FIRToken::kw_domain_define);
4262 auto startLoc = startTok.getLoc();
4263 locationProcessor.setLoc(startLoc);
4267 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4268 parseDomainExp(src) || parseOptionalInfo())
4271 emitConnect(builder, dest, src, getConstants().options.warnOnTruncation);
4276ParseResult FIRStmtParser::parseRefDefine() {
4277 auto startTok = consumeToken(FIRToken::kw_define);
4280 if (parseStaticRefExp(target,
4281 "expected static reference expression in 'define'") ||
4282 parseToken(FIRToken::equal,
4283 "expected '=' after define reference expression") ||
4284 parseRefExp(src,
"expected reference expression in 'define'") ||
4285 parseOptionalInfo())
4289 if (!type_isa<RefType>(target.getType()))
4290 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4291 "'define' target (LHS), got ")
4292 << target.getType();
4293 if (!type_isa<RefType>(src.getType()))
4294 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4295 "'define' source (RHS), got ")
4300 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4301 return emitError(startTok.getLoc(),
4302 "cannot define into a sub-element of a reference");
4304 locationProcessor.setLoc(startTok.getLoc());
4307 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4308 << target.getType() <<
" with incompatible reference of type "
4311 emitConnect(builder, target, src, getConstants().options.warnOnTruncation);
4318ParseResult FIRStmtParser::parseRefRead(Value &result) {
4319 auto startTok = consumeToken(FIRToken::lp_read);
4322 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4323 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4326 locationProcessor.setLoc(startTok.getLoc());
4329 if (!type_isa<RefType>(ref.getType()))
4330 return emitError(startTok.getLoc(),
4331 "expected reference-type expression in 'read', got ")
4334 result = RefResolveOp::create(builder, ref);
4340ParseResult FIRStmtParser::parseProbe(Value &result) {
4341 auto startTok = consumeToken(FIRToken::lp_probe);
4344 if (parseStaticRefExp(staticRef,
4345 "expected static reference expression in 'probe'") ||
4346 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4349 locationProcessor.setLoc(startTok.getLoc());
4352 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4353 return emitError(startTok.getLoc(),
4354 "expected base-type expression in 'probe', got ")
4355 << staticRef.getType();
4359 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4360 MemoryDebugPortOp, MemoryPortAccessOp>(
4361 staticRef.getDefiningOp()))
4362 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4364 result = RefSendOp::create(builder, staticRef);
4370ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4371 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4374 Type parsedTargetType;
4375 if (parseRWProbeStaticRefExp(
4376 staticRef, parsedTargetType,
4377 "expected static reference expression in 'rwprobe'") ||
4378 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4381 locationProcessor.setLoc(startTok.getLoc());
4387 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4389 return emitError(startTok.getLoc(),
4390 "expected base-type expression in 'rwprobe', got ")
4391 << parsedTargetType;
4394 auto *definingOp = root.getDefiningOp();
4396 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4397 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4398 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4402 return emitError(startTok.getLoc(),
"cannot force target of type ")
4406 auto op = RWProbeOp::create(builder, forceableType,
4407 getConstants().placeholderInnerRef);
4414ParseResult FIRStmtParser::parseRefForce() {
4415 auto startTok = consumeToken(FIRToken::lp_force);
4417 Value clock, pred, dest, src;
4418 if (parseExp(clock,
"expected clock expression in force") ||
4419 parseToken(FIRToken::comma,
"expected ','") ||
4420 parseExp(pred,
"expected predicate expression in force") ||
4421 parseToken(FIRToken::comma,
"expected ','") ||
4422 parseRefExp(dest,
"expected destination reference expression in force") ||
4423 parseToken(FIRToken::comma,
"expected ','") ||
4424 parseExp(src,
"expected source expression in force") ||
4425 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4426 parseOptionalInfo())
4430 auto ref = type_dyn_cast<RefType>(dest.getType());
4431 if (!ref || !ref.getForceable())
4434 "expected rwprobe-type expression for force destination, got ")
4436 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4438 return emitError(startTok.getLoc(),
4439 "expected base-type for force source, got ")
4441 if (!srcBaseType.isPassive())
4442 return emitError(startTok.getLoc(),
4443 "expected passive value for force source, got ")
4446 locationProcessor.setLoc(startTok.getLoc());
4449 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4450 if (noConstSrcType != ref.getType()) {
4452 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4454 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4456 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4457 << src.getType() <<
" cannot target destination "
4461 RefForceOp::create(builder, clock, pred, dest, src);
4467ParseResult FIRStmtParser::parseRefForceInitial() {
4468 auto startTok = consumeToken(FIRToken::lp_force_initial);
4472 dest,
"expected destination reference expression in force_initial") ||
4473 parseToken(FIRToken::comma,
"expected ','") ||
4474 parseExp(src,
"expected source expression in force_initial") ||
4475 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4476 parseOptionalInfo())
4480 auto ref = type_dyn_cast<RefType>(dest.getType());
4481 if (!ref || !ref.getForceable())
4482 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4483 "force_initial destination, got ")
4485 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4487 return emitError(startTok.getLoc(),
4488 "expected base-type expression for force_initial "
4491 if (!srcBaseType.isPassive())
4492 return emitError(startTok.getLoc(),
4493 "expected passive value for force_initial source, got ")
4496 locationProcessor.setLoc(startTok.getLoc());
4499 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4500 if (noConstSrcType != ref.getType()) {
4502 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4504 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4506 return emitError(startTok.getLoc(),
4507 "incompatible force_initial source of type ")
4508 << src.getType() <<
" cannot target destination "
4512 auto value = APInt::getAllOnes(1);
4513 auto type = UIntType::get(builder.getContext(), 1);
4514 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4515 value.getBitWidth(),
4516 IntegerType::Unsigned),
4518 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4519 RefForceInitialOp::create(builder, pred, dest, src);
4525ParseResult FIRStmtParser::parseRefRelease() {
4526 auto startTok = consumeToken(FIRToken::lp_release);
4528 Value clock, pred, dest;
4529 if (parseExp(clock,
"expected clock expression in release") ||
4530 parseToken(FIRToken::comma,
"expected ','") ||
4531 parseExp(pred,
"expected predicate expression in release") ||
4532 parseToken(FIRToken::comma,
"expected ','") ||
4534 "expected destination reference expression in release") ||
4535 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4536 parseOptionalInfo())
4540 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4541 !ref || !ref.getForceable())
4544 "expected rwprobe-type expression for release destination, got ")
4547 locationProcessor.setLoc(startTok.getLoc());
4549 RefReleaseOp::create(builder, clock, pred, dest);
4555ParseResult FIRStmtParser::parseRefReleaseInitial() {
4556 auto startTok = consumeToken(FIRToken::lp_release_initial);
4561 "expected destination reference expression in release_initial") ||
4562 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4563 parseOptionalInfo())
4567 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4568 !ref || !ref.getForceable())
4569 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4570 "release_initial destination, got ")
4573 locationProcessor.setLoc(startTok.getLoc());
4575 auto value = APInt::getAllOnes(1);
4576 auto type = UIntType::get(builder.getContext(), 1);
4577 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4578 value.getBitWidth(),
4579 IntegerType::Unsigned),
4581 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4582 RefReleaseInitialOp::create(builder, pred, dest);
4588ParseResult FIRStmtParser::parseConnect() {
4589 auto startTok = consumeToken(FIRToken::kw_connect);
4590 auto loc = startTok.getLoc();
4593 if (parseExp(lhs,
"expected connect expression") ||
4594 parseToken(FIRToken::comma,
"expected ','") ||
4595 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4598 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4599 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4600 if (!lhsType || !rhsType)
4601 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4602 "cannot connect reference or property types");
4604 if (lhsType.containsReference() || rhsType.containsReference())
4605 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4606 "cannot connect types containing references");
4609 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4610 "cannot connect non-equivalent type ")
4611 << rhsType <<
" to " << lhsType;
4613 locationProcessor.setLoc(loc);
4615 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4616 getConstants().options.warnOnTruncation);
4627ParseResult FIRStmtParser::parsePropAssert() {
4628 auto startTok = consumeToken(FIRToken::kw_propassert);
4629 auto loc = startTok.getLoc();
4631 llvm::SMLoc conditionLoc = getToken().getLoc(), messageLoc;
4632 Value condition, message;
4633 if (parseExp(condition,
"expected condition in 'propassert'") ||
4634 parseToken(FIRToken::comma,
"expected ','"))
4637 if (getToken().is(FIRToken::string)) {
4638 if (removedFeature({8, 0, 0},
"string messages in property asserts"))
4640 StringRef messageStr;
4641 messageLoc = getToken().getLoc();
4642 if (parseGetSpelling(messageStr) ||
4643 parseToken(FIRToken::string,
"expected message string in 'propassert'"))
4645 locationProcessor.setLoc(messageLoc);
4647 message = moduleContext.getCachedConstant<StringConstantOp>(
4648 builder, attr, builder.getType<StringType>(), attr);
4652 "string property expression message in property asserts"))
4654 messageLoc = getToken().getLoc();
4655 if (parseExp(message,
"expected message in 'propassert'"))
4659 if (!isa<BoolType>(condition.getType()))
4660 return emitError(conditionLoc,
4661 "propassert condition must be of boolean type");
4664 if (!type_isa<StringType>(message.getType()))
4665 return emitError(messageLoc,
"propassert message must be a string type");
4667 if (parseOptionalInfo())
4670 locationProcessor.setLoc(loc);
4671 PropertyAssertOp::create(builder, condition, message);
4676ParseResult FIRStmtParser::parsePropAssign() {
4677 auto startTok = consumeToken(FIRToken::kw_propassign);
4678 auto loc = startTok.getLoc();
4681 if (parseExp(lhs,
"expected propassign expression") ||
4682 parseToken(FIRToken::comma,
"expected ','") ||
4683 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4686 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4687 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4688 if (!lhsType || !rhsType)
4689 return emitError(loc,
"can only propassign property types");
4690 locationProcessor.setLoc(loc);
4691 if (lhsType != rhsType) {
4693 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4694 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4696 return emitError(loc,
"cannot propassign non-equivalent type ")
4697 << rhsType <<
" to " << lhsType;
4699 PropAssignOp::create(builder, lhs, rhs);
4704ParseResult FIRStmtParser::parseInvalidate() {
4705 auto startTok = consumeToken(FIRToken::kw_invalidate);
4710 auto loc = getToken().getLoc();
4712 if (parseId(
id,
"expected static reference expression") ||
4713 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4718 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4719 if (parseOptionalExpPostscript(lhs,
false) ||
4720 parseOptionalInfo())
4723 locationProcessor.setLoc(startTok.getLoc());
4724 emitInvalidate(lhs);
4731 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4733 if (getToken().isNot(FIRToken::period)) {
4734 locationProcessor.setLoc(loc);
4736 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4738 for (
auto elt : ubEntry)
4739 emitInvalidate(elt.second);
4745 StringRef fieldName;
4746 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4747 parseFieldId(fieldName,
"expected field name") ||
4748 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4752 if (parseOptionalExpPostscript(lhs,
false) ||
4753 parseOptionalInfo())
4756 locationProcessor.setLoc(startTok.getLoc());
4757 emitInvalidate(lhs);
4761ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4763 auto startTok = consumeToken();
4764 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4765 "consumed an unexpected token");
4766 auto loc = startTok.getLoc();
4769 if (parseId(
id,
"expected layer identifer") ||
4770 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4771 parseOptionalInfo())
4774 locationProcessor.setLoc(loc);
4776 StringRef rootLayer;
4777 SmallVector<FlatSymbolRefAttr> nestedLayers;
4781 rootLayer = layerSym.getRootReference();
4782 auto nestedRefs = layerSym.getNestedReferences();
4783 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4784 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4787 auto layerBlockOp = LayerBlockOp::create(
4789 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4790 layerBlockOp->getRegion(0).push_back(
new Block());
4792 if (getIndentation() > indent)
4793 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4794 layerBlockOp.getLayerName()))
4802ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4803 auto loc = getToken().getLoc();
4806 if (consumeIf(FIRToken::kw_is)) {
4807 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4808 parseOptionalInfo())
4811 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4814 locationProcessor.setLoc(loc);
4815 emitInvalidate(lhs);
4819 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4822 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4826 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4829 locationProcessor.setLoc(loc);
4831 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4832 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4833 if (!lhsType || !rhsType)
4834 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4835 "cannot connect reference or property types");
4837 if (lhsType.containsReference() || rhsType.containsReference())
4838 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4839 "cannot connect types containing references");
4842 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4843 "cannot connect non-equivalent type ")
4844 << rhsType <<
" to " << lhsType;
4846 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4847 getConstants().options.warnOnTruncation);
4855ParseResult FIRStmtParser::parseInstance() {
4856 auto startTok = consumeToken(FIRToken::kw_inst);
4860 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4864 StringRef moduleName;
4865 if (parseId(
id,
"expected instance name") ||
4866 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4867 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4870 locationProcessor.setLoc(startTok.getLoc());
4873 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4874 if (!referencedModule)
4877 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4879 auto annotations = getConstants().emptyArrayAttr;
4880 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4882 hw::InnerSymAttr sym = {};
4883 auto result = InstanceOp::create(
4884 builder, referencedModule,
id, NameKindEnum::InterestingName,
4885 annotations.getValue(), portAnnotations,
false,
false, sym);
4891 unbundledValueEntry.reserve(modulePorts.size());
4892 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4893 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4897 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4898 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4899 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4904ParseResult FIRStmtParser::parseInstanceChoice() {
4905 auto startTok = consumeToken(FIRToken::kw_instchoice);
4906 SMLoc loc = startTok.getLoc();
4909 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4916 StringRef defaultModuleName;
4917 StringRef optionGroupName;
4918 if (parseId(
id,
"expected instance name") ||
4919 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4920 parseId(defaultModuleName,
"expected module name") ||
4921 parseToken(FIRToken::comma,
"expected ','") ||
4922 parseId(optionGroupName,
"expected option group name") ||
4923 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4924 parseOptionalInfo())
4927 locationProcessor.setLoc(startTok.getLoc());
4931 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4935 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4938 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4940 return emitError(loc,
4941 "use of undefined option group '" + optionGroupName +
"'");
4943 auto baseIndent = getIndentation();
4944 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4945 while (getIndentation() == baseIndent) {
4947 StringRef caseModuleName;
4948 if (parseId(caseId,
"expected a case identifier") ||
4949 parseToken(FIRToken::equal_greater,
4950 "expected '=> in instance choice definition") ||
4951 parseId(caseModuleName,
"expected module name"))
4954 auto caseModule = getReferencedModule(loc, caseModuleName);
4958 for (
const auto &[defaultPort, casePort] :
4959 llvm::zip(modulePorts, caseModule.getPorts())) {
4960 if (defaultPort.name != casePort.name)
4961 return emitError(loc,
"instance case module port '")
4962 << casePort.name.getValue()
4963 <<
"' does not match the default module port '"
4964 << defaultPort.name.getValue() <<
"'";
4965 if (defaultPort.type != casePort.type)
4966 return emitError(loc,
"instance case port '")
4967 << casePort.name.getValue()
4968 <<
"' type does not match the default module port";
4972 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4974 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4975 caseModules.emplace_back(optionCase, caseModule);
4978 auto annotations = getConstants().emptyArrayAttr;
4979 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4983 auto result = InstanceChoiceOp::create(
4984 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4985 annotations.getValue(), portAnnotations, sym);
4989 unbundledValueEntry.reserve(modulePorts.size());
4990 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4991 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4993 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4994 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4995 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4998FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4999 StringRef moduleName) {
5000 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
5001 if (!referencedModule) {
5003 "use of undefined module name '" + moduleName +
"' in instance");
5006 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
5007 emitError(loc,
"cannot create instance of class '" + moduleName +
5008 "', did you mean object?");
5011 return referencedModule;
5015ParseResult FIRStmtParser::parseObject() {
5016 auto startTok = consumeToken(FIRToken::kw_object);
5020 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5023 if (requireFeature({6, 0, 0},
"object statements"))
5027 StringRef className;
5028 if (parseId(
id,
"expected object name") ||
5029 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
5030 parseId(className,
"expected class name") || parseOptionalInfo())
5033 locationProcessor.setLoc(startTok.getLoc());
5036 const auto &classMap = getConstants().classMap;
5037 auto lookup = classMap.find(className);
5038 if (lookup == classMap.end())
5039 return emitError(startTok.getLoc(),
"use of undefined class name '" +
5040 className +
"' in object");
5041 auto referencedClass = lookup->getSecond();
5042 auto result = ObjectOp::create(builder, referencedClass,
id);
5043 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5047ParseResult FIRStmtParser::parseCombMem() {
5049 auto startTok = consumeToken(FIRToken::kw_cmem);
5053 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5058 if (parseId(
id,
"expected cmem name") ||
5059 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
5060 parseType(type,
"expected cmem type") || parseOptionalInfo())
5063 locationProcessor.setLoc(startTok.getLoc());
5066 auto vectorType = type_dyn_cast<FVectorType>(type);
5068 return emitError(
"cmem requires vector type");
5070 auto annotations = getConstants().emptyArrayAttr;
5071 StringAttr sym = {};
5072 auto result = CombMemOp::create(
5073 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
5074 NameKindEnum::InterestingName, annotations, sym);
5075 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5079ParseResult FIRStmtParser::parseSeqMem() {
5081 auto startTok = consumeToken(FIRToken::kw_smem);
5085 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5090 RUWBehavior ruw = RUWBehavior::Undefined;
5092 if (parseId(
id,
"expected smem name") ||
5093 parseToken(FIRToken::colon,
"expected ':' in smem") ||
5097 if (consumeIf(FIRToken::comma)) {
5102 if (parseOptionalInfo()) {
5106 locationProcessor.setLoc(startTok.getLoc());
5109 auto vectorType = type_dyn_cast<FVectorType>(type);
5111 return emitError(
"smem requires vector type");
5113 auto annotations = getConstants().emptyArrayAttr;
5114 StringAttr sym = {};
5115 auto result = SeqMemOp::create(
5116 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
5117 id, NameKindEnum::InterestingName, annotations, sym);
5118 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5130ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
5131 auto startTok = consumeToken(FIRToken::kw_mem);
5135 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5139 if (parseId(
id,
"expected mem name") ||
5140 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
5144 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5145 RUWBehavior ruw = RUWBehavior::Undefined;
5147 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5151 auto nextIndent = getIndentation();
5152 if (!nextIndent || *nextIndent <= memIndent)
5155 auto spelling = getTokenSpelling();
5156 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
5157 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
5160 if (spelling ==
"data-type") {
5162 return emitError(
"'mem' type specified multiple times"), failure();
5164 if (
parseType(type,
"expected type in data-type declaration"))
5168 if (spelling ==
"depth") {
5169 if (parseIntLit(depth,
"expected integer in depth specification"))
5173 if (spelling ==
"read-latency") {
5174 if (parseIntLit(readLatency,
"expected integer latency"))
5178 if (spelling ==
"write-latency") {
5179 if (parseIntLit(writeLatency,
"expected integer latency"))
5183 if (spelling ==
"read-under-write") {
5184 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5185 FIRToken::kw_undefined))
5186 return emitError(
"expected specifier"), failure();
5188 if (parseOptionalRUW(ruw))
5193 MemOp::PortKind portKind;
5194 if (spelling ==
"reader")
5195 portKind = MemOp::PortKind::Read;
5196 else if (spelling ==
"writer")
5197 portKind = MemOp::PortKind::Write;
5198 else if (spelling ==
"readwriter")
5199 portKind = MemOp::PortKind::ReadWrite;
5201 return emitError(
"unexpected field in 'mem' declaration"), failure();
5204 if (parseId(portName,
"expected port name"))
5206 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5208 return emitError(
"unexpected type, must be base type");
5209 ports.push_back({builder.getStringAttr(portName),
5210 MemOp::getTypeForPort(depth, baseType, portKind)});
5212 while (!getIndentation().has_value()) {
5213 if (parseId(portName,
"expected port name"))
5215 ports.push_back({builder.getStringAttr(portName),
5216 MemOp::getTypeForPort(depth, baseType, portKind)});
5227 llvm::array_pod_sort(ports.begin(), ports.end(),
5228 [](
const std::pair<StringAttr, Type> *lhs,
5229 const std::pair<StringAttr, Type> *rhs) ->
int {
5230 return lhs->first.getValue().compare(
5231 rhs->first.getValue());
5234 auto annotations = getConstants().emptyArrayAttr;
5235 SmallVector<Attribute, 4> resultNames;
5236 SmallVector<Type, 4> resultTypes;
5237 SmallVector<Attribute, 4> resultAnnotations;
5238 for (
auto p : ports) {
5239 resultNames.push_back(p.first);
5240 resultTypes.push_back(p.second);
5241 resultAnnotations.push_back(annotations);
5244 locationProcessor.setLoc(startTok.getLoc());
5246 auto result = MemOp::create(
5247 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5248 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5249 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5250 MemoryInitAttr(), StringAttr());
5253 unbundledValueEntry.reserve(result.getNumResults());
5254 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5255 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5257 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5258 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5259 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5263ParseResult FIRStmtParser::parseNode() {
5264 auto startTok = consumeToken(FIRToken::kw_node);
5268 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5273 if (parseId(
id,
"expected node name") ||
5274 parseToken(FIRToken::equal,
"expected '=' in node") ||
5275 parseExp(initializer,
"expected expression for node") ||
5276 parseOptionalInfo())
5279 locationProcessor.setLoc(startTok.getLoc());
5291 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5292 auto initializerBaseType =
5293 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5294 if (type_isa<AnalogType>(initializerType) ||
5295 !(initializerBaseType && initializerBaseType.isPassive())) {
5296 emitError(startTok.getLoc())
5297 <<
"Node cannot be analog and must be passive or passive under a flip "
5298 << initializer.getType();
5302 auto annotations = getConstants().emptyArrayAttr;
5303 StringAttr sym = {};
5305 auto result = NodeOp::create(builder, initializer,
id,
5306 NameKindEnum::InterestingName, annotations, sym);
5307 return moduleContext.addSymbolEntry(
id, result.getResult(),
5312ParseResult FIRStmtParser::parseWire() {
5313 auto startTok = consumeToken(FIRToken::kw_wire);
5317 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5322 if (parseId(
id,
"expected wire name") ||
5323 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5328 SmallVector<Value> domains;
5329 if (consumeIf(FIRToken::kw_domains)) {
5333 if (parseToken(FIRToken::l_square,
"expected '[' after 'domains'"))
5336 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5337 StringRef domainName;
5338 auto domainLoc = getToken().getLoc();
5339 if (parseId(domainName,
"expected domain name"))
5344 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5349 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5352 if (!isa<DomainType>(domainValue.getType()))
5353 return emitError(domainLoc)
5354 <<
"'" << domainName <<
"' is not a domain";
5356 domains.push_back(domainValue);
5362 if (parseOptionalInfo())
5365 locationProcessor.setLoc(startTok.getLoc());
5367 auto annotations = getConstants().emptyArrayAttr;
5368 StringAttr sym = {};
5371 auto namekind = isa<PropertyType, RefType>(type)
5372 ? NameKindEnum::DroppableName
5373 : NameKindEnum::InterestingName;
5375 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym,
5377 return moduleContext.addSymbolEntry(
id, result.getResult(),
5391ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5392 auto startTok = consumeToken(FIRToken::kw_reg);
5396 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5405 if (parseId(
id,
"expected reg name") ||
5406 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5408 parseToken(FIRToken::comma,
"expected ','") ||
5409 parseExp(clock,
"expected expression for register clock"))
5412 if (!type_isa<FIRRTLBaseType>(type))
5413 return emitError(startTok.getLoc(),
"register must have base type");
5416 Value resetSignal, resetValue;
5417 if (consumeIf(FIRToken::kw_with)) {
5418 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5421 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5429 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5431 auto indent = getIndentation();
5432 if (!indent || *indent <= regIndent)
5433 if (!hasExtraLParen)
5434 return emitError(
"expected indented reset specifier in reg"), failure();
5436 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5437 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5438 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5439 parseExp(resetSignal,
"expected expression for reset signal") ||
5440 parseToken(FIRToken::comma,
"expected ','"))
5448 if (getTokenSpelling() ==
id) {
5450 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5452 resetSignal = Value();
5454 if (parseExp(resetValue,
"expected expression for reset value") ||
5455 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5459 if (hasExtraLParen &&
5460 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5466 if (parseOptionalInfo())
5469 locationProcessor.setLoc(startTok.getLoc());
5471 ArrayAttr annotations = getConstants().emptyArrayAttr;
5473 StringAttr sym = {};
5476 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5477 NameKindEnum::InterestingName, annotations, sym)
5480 result = RegOp::create(builder, type, clock,
id,
5481 NameKindEnum::InterestingName, annotations, sym)
5483 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5491ParseResult FIRStmtParser::parseRegisterWithReset() {
5492 auto startTok = consumeToken(FIRToken::kw_regreset);
5496 Value clock, resetSignal, resetValue;
5498 if (parseId(
id,
"expected reg name") ||
5499 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5501 parseToken(FIRToken::comma,
"expected ','") ||
5502 parseExp(clock,
"expected expression for register clock") ||
5503 parseToken(FIRToken::comma,
"expected ','") ||
5504 parseExp(resetSignal,
"expected expression for register reset") ||
5505 parseToken(FIRToken::comma,
"expected ','") ||
5506 parseExp(resetValue,
"expected expression for register reset value") ||
5507 parseOptionalInfo())
5510 if (!type_isa<FIRRTLBaseType>(type))
5511 return emitError(startTok.getLoc(),
"register must have base type");
5513 locationProcessor.setLoc(startTok.getLoc());
5516 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5517 NameKindEnum::InterestingName,
5518 getConstants().emptyArrayAttr, StringAttr{})
5521 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5526ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5530 auto startTok = consumeToken(FIRToken::kw_contract);
5533 SmallVector<StringRef> ids;
5534 SmallVector<SMLoc> locs;
5535 SmallVector<Value> values;
5536 SmallVector<Type> types;
5537 if (!consumeIf(FIRToken::colon)) {
5538 auto parseContractId = [&] {
5540 locs.push_back(getToken().
getLoc());
5541 if (parseId(
id,
"expected contract result name"))
5546 auto parseContractValue = [&] {
5548 if (parseExp(value,
"expected expression for contract result"))
5550 values.push_back(value);
5551 types.push_back(value.getType());
5554 if (parseListUntil(FIRToken::equal, parseContractId) ||
5555 parseListUntil(FIRToken::colon, parseContractValue))
5558 if (parseOptionalInfo())
5562 if (ids.size() != values.size())
5563 return emitError(startTok.getLoc())
5564 <<
"contract requires same number of results and expressions; got "
5565 << ids.size() <<
" results and " << values.size()
5566 <<
" expressions instead";
5568 locationProcessor.setLoc(startTok.getLoc());
5572 auto contract = ContractOp::create(builder, types, values);
5573 auto &block = contract.getBody().emplaceBlock();
5577 FIRModuleContext::ContextScope scope(moduleContext, &block);
5578 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5579 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5580 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5583 if (getIndentation() > blockIndent)
5584 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5589 for (
auto [
id, loc, value, result] :
5590 llvm::zip(ids, locs, values, contract.getResults())) {
5592 moduleContext.removeSymbolEntry(
id);
5593 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5606struct FIRCircuitParser :
public FIRParser {
5607 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5609 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5612 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5613 mlir::TimingScope &ts);
5618 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5619 SmallVectorImpl<Attribute> &attrs);
5621 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5623 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5624 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5625 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5626 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5627 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5628 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5629 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5630 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5632 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5634 ParseResult parseLayerName(SymbolRefAttr &result);
5635 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5636 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5637 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5638 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5639 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5640 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5641 ArrayAttr &knownLayers,
5642 ArrayAttr &externalRequirements);
5644 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5645 SmallVectorImpl<SMLoc> &resultPortLocs,
5649 ParseResult skipToModuleEnd(
unsigned indent);
5651 ParseResult parseTypeDecl();
5653 ParseResult parseOptionDecl(CircuitOp circuit);
5655 ParseResult parseLayer(CircuitOp circuit);
5657 ParseResult resolveDomains(
5658 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5659 const DenseMap<Attribute, size_t> &nameToIndex,
5660 SmallVectorImpl<Attribute> &domainsByIndex);
5663 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5664 const DenseMap<Attribute, size_t> &nameToIndex);
5666 struct DeferredModuleToParse {
5667 FModuleLike moduleOp;
5668 SmallVector<SMLoc> portLocs;
5673 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5674 DeferredModuleToParse &deferredModule,
5675 InnerSymFixups &fixups);
5677 SmallVector<DeferredModuleToParse, 0> deferredModules;
5679 SmallVector<InnerSymFixups, 0> moduleFixups;
5683 ModuleOp mlirModule;
5688FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5689 SmallVectorImpl<Attribute> &attrs) {
5691 auto annotations = json::parse(annotationsStr);
5692 if (
auto err = annotations.takeError()) {
5693 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5694 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5695 diag.attachNote() << a.message();
5700 json::Path::Root root;
5701 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5704 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5705 std::string jsonErrorMessage =
5706 "See inline comments for problem area in JSON:\n";
5707 llvm::raw_string_ostream
s(jsonErrorMessage);
5708 root.printErrorContext(annotations.get(), s);
5709 diag.attachNote() << jsonErrorMessage;
5716ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5718 SmallVector<StringRef> strings;
5721 if (parseId(name,
"expected layer name"))
5723 strings.push_back(name);
5724 }
while (consumeIf(FIRToken::period));
5726 SmallVector<FlatSymbolRefAttr> nested;
5727 nested.reserve(strings.size() - 1);
5728 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5729 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5731 result = SymbolRefAttr::get(
context, strings[0], nested);
5735ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5736 SmallVector<Attribute> enabledLayersBuffer;
5738 auto tokenKind = getToken().getKind();
5740 if (tokenKind == FIRToken::kw_enablelayer) {
5741 if (parseEnableLayerSpec(enabledLayersBuffer))
5749 if (enabledLayersBuffer.size() != 0)
5750 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5753 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5757ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5758 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5759 ArrayAttr &externalRequirements) {
5760 SmallVector<Attribute> enabledLayersBuffer;
5761 SmallVector<Attribute> knownLayersBuffer;
5762 SmallVector<Attribute> requirementsBuffer;
5764 auto tokenKind = getToken().getKind();
5766 if (tokenKind == FIRToken::kw_enablelayer) {
5767 if (parseEnableLayerSpec(enabledLayersBuffer))
5772 if (tokenKind == FIRToken::kw_knownlayer) {
5773 if (parseKnownLayerSpec(knownLayersBuffer))
5778 if (tokenKind == FIRToken::kw_requires) {
5779 if (parseRequiresSpec(requirementsBuffer))
5787 if (enabledLayersBuffer.size() != 0)
5788 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5791 if (knownLayersBuffer.size() != 0)
5792 if (requireFeature({6, 0, 0},
"extmodules with known layers"))
5795 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5796 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5797 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5802FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5804 SymbolRefAttr layer;
5805 if (parseLayerName(layer))
5807 result.push_back(layer);
5808 }
while (consumeIf(FIRToken::comma));
5813FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5814 consumeToken(FIRToken::kw_enablelayer);
5815 return parseLayerList(result);
5819FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5820 consumeToken(FIRToken::kw_knownlayer);
5821 return parseLayerList(result);
5825FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5826 consumeToken(FIRToken::kw_requires);
5828 StringRef requireStr;
5829 if (parseGetSpelling(requireStr) ||
5830 parseToken(FIRToken::string,
"expected string after 'requires'"))
5834 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5835 }
while (consumeIf(FIRToken::comma));
5843FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5844 SmallVectorImpl<SMLoc> &resultPortLocs,
5850 DenseMap<Attribute, size_t> nameToIndex;
5851 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5854 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5856 getIndentation() > indent) {
5862 auto backtrackState = getLexer().getCursor();
5864 bool isOutput = getToken().is(FIRToken::kw_output);
5869 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5870 !getToken().isKeyword()) {
5871 backtrackState.restore(getLexer());
5878 if (parseId(name,
"expected port name") ||
5879 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5880 parseType(type,
"expected a type in port declaration"))
5882 Attribute domainInfoElement = {};
5883 size_t portIdx = resultPorts.size();
5884 if (
auto domainType = dyn_cast<DomainType>(type)) {
5887 domainInfoElement = ArrayAttr::get(getContext(), {});
5889 if (getToken().is(FIRToken::kw_domains))
5890 if (parseDomains(domainNames[portIdx], nameToIndex))
5894 if (
info.parseOptionalInfo())
5897 StringAttr innerSym = {};
5898 resultPorts.push_back(
PortInfo{name,
5904 domainInfoElement});
5905 resultPortLocs.push_back(
info.getFIRLoc());
5906 nameToIndex.insert({name, portIdx});
5910 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5911 auto &port = resultPorts[portIdx];
5912 Attribute &attr = port.domains;
5916 SmallVector<Attribute> domainInfo;
5917 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5919 attr = ArrayAttr::get(getContext(), domainInfo);
5924 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5925 PortInfo &port = std::get<0>(portAndLoc);
5926 auto &entry = portIds[port.
name];
5927 if (!entry.isValid()) {
5928 entry = std::get<1>(portAndLoc);
5932 emitError(std::get<1>(portAndLoc),
5933 "redefinition of name '" + port.
getName() +
"'")
5934 .attachNote(translateLocation(entry))
5935 <<
"previous definition here";
5944ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5946 switch (getToken().getKind()) {
5950 case FIRToken::error:
5954 case FIRToken::kw_class:
5955 case FIRToken::kw_domain:
5956 case FIRToken::kw_declgroup:
5957 case FIRToken::kw_extclass:
5958 case FIRToken::kw_extmodule:
5959 case FIRToken::kw_intmodule:
5960 case FIRToken::kw_formal:
5961 case FIRToken::kw_module:
5962 case FIRToken::kw_public:
5963 case FIRToken::kw_layer:
5964 case FIRToken::kw_option:
5965 case FIRToken::kw_simulation:
5966 case FIRToken::kw_type:
5970 if (getIndentation() == indent)
5982ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5983 SmallVector<Attribute, 8> parameters;
5984 SmallPtrSet<StringAttr, 8> seen;
5985 while (consumeIf(FIRToken::kw_parameter)) {
5989 if (parseParameter(name, value, loc))
5991 auto typedValue = dyn_cast<TypedAttr>(value);
5993 return emitError(loc)
5994 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5995 if (!seen.insert(name).second)
5996 return emitError(loc,
5997 "redefinition of parameter '" + name.getValue() +
"'");
5998 parameters.push_back(ParamDeclAttr::get(name, typedValue));
6000 resultParameters = ArrayAttr::get(getContext(), parameters);
6005ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
6007 SmallVector<PortInfo, 8> portList;
6008 SmallVector<SMLoc> portLocs;
6011 if (requireFeature({6, 0, 0},
"classes"))
6014 consumeToken(FIRToken::kw_class);
6015 if (parseId(name,
"expected class name") ||
6016 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
6020 if (name == circuit.getName())
6021 return mlir::emitError(
info.getLoc(),
6022 "class cannot be the top of a circuit");
6024 for (
auto &portInfo : portList)
6026 return
mlir::emitError(portInfo.loc,
6027 "ports on classes must be properties");
6030 auto builder = circuit.getBodyBuilder();
6031 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
6032 classOp.setPrivate();
6033 deferredModules.emplace_back(
6034 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
6037 getConstants().classMap[name.getValue()] = classOp;
6038 return skipToModuleEnd(indent);
6042ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
6043 consumeToken(FIRToken::kw_domain);
6047 if (parseId(name,
"domain name") ||
6048 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
6049 info.parseOptionalInfo())
6052 SmallVector<Attribute> fields;
6054 auto nextIndent = getIndentation();
6055 if (!nextIndent || *nextIndent <= indent)
6058 StringAttr fieldName;
6060 if (parseId(fieldName,
"field name") ||
6061 parseToken(FIRToken::colon,
"expected ':' after field name") ||
6062 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
6066 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
6069 auto builder = circuit.getBodyBuilder();
6071 DomainOp::create(builder,
info.getLoc(), name, {},
6072 builder.getArrayAttr(fields));
6076 getConstants().domainMap[name.getValue()] = domainOp;
6082ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
6085 SmallVector<PortInfo, 8> portList;
6086 SmallVector<SMLoc> portLocs;
6089 if (requireFeature({6, 0, 0},
"classes"))
6092 consumeToken(FIRToken::kw_extclass);
6093 if (parseId(name,
"expected extclass name") ||
6094 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
6098 if (name == circuit.getName())
6099 return mlir::emitError(
info.getLoc(),
6100 "extclass cannot be the top of a circuit");
6102 for (
auto &portInfo : portList)
6104 return
mlir::emitError(portInfo.loc,
6105 "ports on extclasses must be properties");
6108 auto builder = circuit.getBodyBuilder();
6109 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
6112 getConstants().classMap[name.getValue()] = extClassOp;
6113 return skipToModuleEnd(indent);
6121ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
6124 ArrayAttr enabledLayers;
6125 ArrayAttr knownLayers;
6126 ArrayAttr externalRequirements;
6127 SmallVector<PortInfo, 8> portList;
6128 SmallVector<SMLoc> portLocs;
6130 consumeToken(FIRToken::kw_extmodule);
6131 if (parseId(name,
"expected extmodule name") ||
6132 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
6133 externalRequirements) ||
6134 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
6139 if (consumeIf(FIRToken::kw_defname)) {
6140 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
6141 parseId(defName,
"expected defname name"))
6145 ArrayAttr parameters;
6150 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6151 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6152 if (ftype.hasUninferredWidth())
6153 return emitError(loc,
"extmodule port must have known width");
6158 auto builder = circuit.getBodyBuilder();
6159 auto isMainModule = (name == circuit.getName());
6161 (isMainModule && getConstants().options.scalarizePublicModules) ||
6162 getConstants().options.scalarizeExtModules
6163 ? Convention::Scalarized
6164 : Convention::Internal;
6165 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6166 auto annotations = ArrayAttr::get(getContext(), {});
6167 auto extModuleOp = FExtModuleOp::create(
6168 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
6169 defName, annotations, parameters, enabledLayers, externalRequirements);
6170 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6171 : SymbolTable::Visibility::Private;
6172 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6180ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6184 ArrayAttr enabledLayers;
6185 SmallVector<PortInfo, 8> portList;
6186 SmallVector<SMLoc> portLocs;
6188 consumeToken(FIRToken::kw_intmodule);
6189 if (parseId(name,
"expected intmodule name") ||
6190 parseModuleLayerSpec(enabledLayers) ||
6191 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
6193 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
6194 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
6195 parseId(intName,
"expected intrinsic name"))
6198 ArrayAttr parameters;
6202 ArrayAttr annotations = getConstants().emptyArrayAttr;
6203 auto builder = circuit.getBodyBuilder();
6204 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
6205 annotations, parameters, enabledLayers)
6211ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
6214 SmallVector<PortInfo, 8> portList;
6215 SmallVector<SMLoc> portLocs;
6216 ArrayAttr enabledLayers;
6217 auto modLoc = getToken().getLoc();
6218 LocWithInfo
info(modLoc,
this);
6219 consumeToken(FIRToken::kw_module);
6220 if (parseId(name,
"expected module name") ||
6221 parseModuleLayerSpec(enabledLayers) ||
6222 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
6227 if (name == circuit.getName()) {
6228 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
6233 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
6234 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6235 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6236 if (ftype.hasUninferredWidth())
6237 return emitError(loc,
"public module port must have known width");
6238 if (ftype.hasUninferredReset())
6239 return emitError(loc,
6240 "public module port must have concrete reset type");
6245 ArrayAttr annotations = getConstants().emptyArrayAttr;
6246 auto convention = Convention::Internal;
6247 if (isPublic && getConstants().options.scalarizePublicModules)
6248 convention = Convention::Scalarized;
6249 if (!isPublic && getConstants().options.scalarizeInternalModules)
6250 convention = Convention::Scalarized;
6251 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6252 auto builder = circuit.getBodyBuilder();
6254 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6255 annotations, enabledLayers);
6257 auto visibility = isPublic ? SymbolTable::Visibility::Public
6258 : SymbolTable::Visibility::Private;
6259 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6263 deferredModules.emplace_back(DeferredModuleToParse{
6264 moduleOp, portLocs, getLexer().getCursor(), indent});
6266 if (skipToModuleEnd(indent))
6272ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6273 consumeToken(FIRToken::kw_formal);
6274 return parseFormalLike<FormalOp>(circuit, indent);
6278ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6280 consumeToken(FIRToken::kw_simulation);
6281 return parseFormalLike<SimulationOp>(circuit, indent);
6288ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6290 StringRef id, moduleName;
6293 auto builder = circuit.getBodyBuilder();
6296 if (parseId(
id,
"expected test name") ||
6297 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6298 parseId(moduleName,
"expected module name"))
6302 NamedAttrList params;
6303 if (consumeIf(FIRToken::comma)) {
6305 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6306 return emitError(
"expected 'bound' after ','");
6308 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6309 parseIntLit(bound,
"expected integer bound after '='"))
6312 return emitError(
"bound must be a positive integer");
6313 if (
info.parseOptionalInfo())
6315 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6318 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6319 info.parseOptionalInfo())
6321 while (getIndentation() > indent) {
6322 StringAttr paramName;
6323 Attribute paramValue;
6325 if (parseParameter(paramName, paramValue, paramLoc,
6328 if (params.set(paramName, paramValue))
6329 return emitError(paramLoc,
"redefinition of parameter '" +
6330 paramName.getValue() +
"'");
6334 Op::create(builder,
info.getLoc(),
id, {}, moduleName,
6335 params.getDictionary(getContext()));
6339ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6341 switch (getToken().getKind()) {
6342 case FIRToken::kw_class:
6343 return parseClass(circuit, indent);
6344 case FIRToken::kw_declgroup:
6345 if (requireFeature({3, 2, 0},
"optional groups") ||
6346 removedFeature({3, 3, 0},
"optional groups"))
6348 return parseLayer(circuit);
6349 case FIRToken::kw_domain:
6352 return parseDomain(circuit, indent);
6353 case FIRToken::kw_extclass:
6354 return parseExtClass(circuit, indent);
6355 case FIRToken::kw_extmodule:
6356 return parseExtModule(circuit, indent);
6357 case FIRToken::kw_formal:
6358 if (requireFeature({4, 0, 0},
"formal tests"))
6360 return parseFormal(circuit, indent);
6361 case FIRToken::kw_intmodule:
6362 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6363 removedFeature({4, 0, 0},
"intrinsic modules"))
6365 return parseIntModule(circuit, indent);
6366 case FIRToken::kw_layer:
6367 if (requireFeature({3, 3, 0},
"layers"))
6369 return parseLayer(circuit);
6370 case FIRToken::kw_module:
6371 return parseModule(circuit,
false, indent);
6372 case FIRToken::kw_public:
6373 if (requireFeature({3, 3, 0},
"public modules"))
6376 if (getToken().getKind() == FIRToken::kw_module)
6377 return parseModule(circuit,
true, indent);
6378 return emitError(getToken().
getLoc(),
"only modules may be public");
6379 case FIRToken::kw_simulation:
6382 return parseSimulation(circuit, indent);
6383 case FIRToken::kw_type:
6384 return parseTypeDecl();
6385 case FIRToken::kw_option:
6388 return parseOptionDecl(circuit);
6390 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6395ParseResult FIRCircuitParser::parseTypeDecl() {
6399 auto loc = getToken().getLoc();
6401 if (getToken().isKeyword())
6402 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6403 <<
"' for type alias name";
6405 if (parseId(
id,
"expected type name") ||
6406 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6409 auto name = StringAttr::get(type.getContext(),
id);
6412 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6413 type = BaseTypeAliasType::get(name, base);
6416 <<
"type alias for non-base type " << type
6417 <<
" is currently not supported. Type alias is stripped immediately";
6419 if (!getConstants().aliasMap.insert({id, type}).second)
6420 return emitError(loc) <<
"type alias `" << name.getValue()
6421 <<
"` is already defined";
6426ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6429 auto loc = getToken().getLoc();
6432 if (parseId(
id,
"expected an option group name") ||
6433 parseToken(FIRToken::colon,
6434 "expected ':' after option group definition") ||
6435 info.parseOptionalInfo())
6438 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6440 OptionOp::create(builder,
info.getLoc(),
id, {});
6441 auto *block =
new Block;
6442 optionOp.getBody().push_back(block);
6443 builder.setInsertionPointToEnd(block);
6445 auto baseIndent = getIndentation();
6447 while (getIndentation() == baseIndent) {
6449 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6450 if (parseId(
id,
"expected an option case ID") ||
6451 caseInfo.parseOptionalInfo())
6454 if (!cases.insert(
id).second)
6455 return emitError(loc)
6456 <<
"duplicate option case definition '" <<
id <<
"'";
6458 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6465ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6466 auto baseIndent = getIndentation();
6469 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6472 auto parseOne = [&](
Block *block) -> ParseResult {
6473 auto indent = getIndentation();
6474 StringRef id, convention;
6477 if (parseId(
id,
"expected layer name") ||
6478 parseToken(FIRToken::comma,
"expected ','") ||
6479 parseGetSpelling(convention))
6482 auto layerConvention = symbolizeLayerConvention(convention);
6483 if (!layerConvention) {
6484 emitError() <<
"unknown convention '" << convention
6485 <<
"' (did you misspell it?)";
6488 if (layerConvention == LayerConvention::Inline &&
6489 requireFeature({4, 1, 0},
"inline layers"))
6493 hw::OutputFileAttr outputDir;
6494 if (consumeIf(FIRToken::comma)) {
6495 if (getToken().getKind() == FIRToken::string) {
6496 auto text = getToken().getStringValue();
6498 return emitError() <<
"output directory must not be blank";
6499 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6500 consumeToken(FIRToken::string);
6504 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6505 info.parseOptionalInfo())
6507 auto builder = OpBuilder::atBlockEnd(block);
6509 auto layerOp = LayerOp::create(builder,
info.getLoc(),
id,
6510 {}, *layerConvention);
6511 layerOp->getRegion(0).push_back(
new Block());
6513 layerOp->setAttr(
"output_file", outputDir);
6514 layerStack.push_back({indent, layerOp});
6518 if (parseOne(circuit.getBodyBlock()))
6522 while (getIndentation() > baseIndent) {
6523 switch (getToken().getKind()) {
6524 case FIRToken::kw_declgroup:
6525 case FIRToken::kw_layer: {
6528 while (layerStack.back().first >= getIndentation())
6529 layerStack.pop_back();
6530 auto parentLayer = layerStack.back().second;
6531 if (parseOne(&parentLayer.getBody().front()))
6536 return emitError(
"expected 'layer'"), failure();
6543ParseResult FIRCircuitParser::resolveDomains(
6544 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6545 const DenseMap<Attribute, size_t> &nameToIndex,
6546 SmallVectorImpl<Attribute> &domainsByIndex) {
6548 for (
auto [attr, loc] : domainsByName) {
6549 auto domain = cast<StringAttr>(attr);
6550 auto indexItr = nameToIndex.find(domain);
6551 if (indexItr == nameToIndex.end()) {
6552 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6555 domainsByIndex.push_back(IntegerAttr::get(
6556 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6563ParseResult FIRCircuitParser::parseDomains(
6564 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6565 const DenseMap<Attribute, size_t> &nameToIndex) {
6568 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6569 parseToken(FIRToken::l_square,
"expected '['"))
6572 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6574 auto domainLoc = getToken().getLoc();
6575 if (parseId(domain,
"expected domain name"))
6577 domains.push_back({domain, domainLoc});
6587FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6588 DeferredModuleToParse &deferredModule,
6589 InnerSymFixups &fixups) {
6590 FModuleLike moduleOp = deferredModule.moduleOp;
6591 auto &body = moduleOp->getRegion(0).front();
6592 auto &portLocs = deferredModule.portLocs;
6596 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6599 deferredModule.lexerCursor.restore(moduleBodyLexer);
6601 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6606 auto portList = moduleOp.getPorts();
6607 auto portArgs = body.getArguments();
6608 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6609 PortInfo &port = std::get<0>(tuple);
6610 llvm::SMLoc loc = std::get<1>(tuple);
6611 BlockArgument portArg = std::get<2>(tuple);
6613 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6617 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6620 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6633ParseResult FIRCircuitParser::parseCircuit(
6634 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6635 mlir::TimingScope &ts) {
6637 auto indent = getIndentation();
6638 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6640 if (!indent.has_value())
6641 return emitError(
"'FIRRTL' must be first token on its line");
6642 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6643 parseVersionLit(
"expected version literal"))
6645 indent = getIndentation();
6647 if (!indent.has_value())
6648 return emitError(
"'circuit' must be first token on its line");
6649 unsigned circuitIndent = *indent;
6653 SMLoc inlineAnnotationsLoc;
6654 StringRef inlineAnnotations;
6657 if (parseToken(FIRToken::kw_circuit,
6658 "expected a top-level 'circuit' definition") ||
6659 parseId(name,
"expected circuit name") ||
6660 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6661 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6662 info.parseOptionalInfo())
6666 OpBuilder b(mlirModule.getBodyRegion());
6667 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6670 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6676 SmallVector<Attribute> annos;
6677 if (!inlineAnnotations.empty())
6678 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6682 for (
auto *annotationsBuf : annotationsBufs)
6683 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6687 parseAnnotationTimer.stop();
6695 auto parseTimer = ts.nest(
"Parse modules");
6696 deferredModules.reserve(16);
6700 switch (getToken().getKind()) {
6708 case FIRToken::error:
6712 emitError(
"unexpected token in circuit");
6715 case FIRToken::kw_class:
6716 case FIRToken::kw_declgroup:
6717 case FIRToken::kw_domain:
6718 case FIRToken::kw_extclass:
6719 case FIRToken::kw_extmodule:
6720 case FIRToken::kw_intmodule:
6721 case FIRToken::kw_layer:
6722 case FIRToken::kw_formal:
6723 case FIRToken::kw_module:
6724 case FIRToken::kw_option:
6725 case FIRToken::kw_public:
6726 case FIRToken::kw_simulation:
6727 case FIRToken::kw_type: {
6728 auto indent = getIndentation();
6729 if (!indent.has_value())
6730 return emitError(
"'module' must be first token on its line"), failure();
6731 unsigned definitionIndent = *indent;
6733 if (definitionIndent <= circuitIndent)
6734 return emitError(
"module should be indented more"), failure();
6736 if (parseToplevelDefinition(circuit, definitionIndent))
6750 (void)getLexer().translateLocation(
info.getFIRLoc());
6756 DenseMap<Attribute, Location> nameToOrigLoc;
6759 auto symbol = dyn_cast<mlir::SymbolOpInterface>(&op);
6763 auto nameAttr = symbol.getNameAttr();
6766 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6769 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6770 .attachNote(it.first->second)
6771 .append(
"see existing symbol definition here");
6777 SymbolTable circuitSymTbl(circuit);
6779 moduleFixups.resize(deferredModules.size());
6784 for (
auto &d : deferredModules)
6785 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6788 auto anyFailed = mlir::failableParallelForEachN(
6789 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6790 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6791 moduleFixups[index]))
6795 if (failed(anyFailed))
6800 for (
auto &fixups : moduleFixups) {
6801 if (failed(fixups.resolve(innerSymbolNamespaces)))
6807 auto parseLayerName = [&](StringRef name) -> Attribute {
6809 auto [head, rest] = name.split(
".");
6810 SmallVector<FlatSymbolRefAttr> nestedRefs;
6811 while (!rest.empty()) {
6813 std::tie(next, rest) = rest.split(
".");
6814 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6816 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6819 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6820 SmallVector<Attribute> attrArray;
6822 for (
const auto &str : strArray)
6823 attrArray.push_back(getAttr(str));
6824 if (attrArray.empty())
6826 return ArrayAttr::get(
context, attrArray);
6829 if (
auto enableLayers =
6830 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6831 circuit.setEnableLayersAttr(enableLayers);
6832 if (
auto disableLayers =
6833 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6834 circuit.setDisableLayersAttr(disableLayers);
6836 auto getStrAttr = [&](StringRef str) -> Attribute {
6837 return StringAttr::get(getContext(), str);
6840 if (
auto selectInstChoice =
6841 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6842 circuit.setSelectInstChoiceAttr(selectInstChoice);
6844 circuit.setDefaultLayerSpecialization(
6845 getConstants().options.defaultLayerSpecialization);
6858 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6859 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6860 unsigned fileID = 1;
6862 annotationsBufs.push_back(
6863 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6865 context->loadDialect<CHIRRTLDialect>();
6866 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6870 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6873 SharedParserConstants state(
context, options);
6876 .parseCircuit(annotationsBufs, ts))
6881 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6882 if (failed(verify(*module)))
6889 static mlir::TranslateToMLIRRegistration fromFIR(
6890 "import-firrtl",
"import .fir",
6891 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6892 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
constexpr FIRVersion nextFIRVersion(7, 0, 0)
The next version of FIRRTL that is not yet released.
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.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs, bool warnOnTruncation=false)
Emit a connect between two values.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
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.
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.
static std::optional< FIRVersion > fromString(StringRef str)
Parse a version string of the form "major.minor.patch".
This holds the name and type that describes the module's ports.
StringRef getName() const