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;
3900ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3901 auto token = getToken().getKind();
3902 if (token == FIRToken::lp_probe)
3903 return failure(parseProbe(result) ||
3904 parseOptionalExpPostscript(result,
false));
3905 if (token == FIRToken::lp_rwprobe)
3906 return failure(parseRWProbe(result) ||
3907 parseOptionalExpPostscript(result,
false));
3912 return parseStaticRefExp(result, message);
3919ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3920 const Twine &message) {
3921 auto parseIdOrInstance = [&]() -> ParseResult {
3923 auto loc = getToken().getLoc();
3925 if (parseId(
id, message) ||
3926 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3930 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3933 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3936 StringRef fieldName;
3938 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3939 parseFieldId(fieldName,
"expected field name") ||
3940 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3942 return failure(parseIdOrInstance() ||
3943 parseOptionalExpPostscript(result,
false));
3954ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3956 const Twine &message) {
3957 auto loc = getToken().getLoc();
3961 if (parseId(
id, message) ||
3962 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3974 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3976 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3978 StringRef fieldName;
3979 auto loc = getToken().getLoc();
3980 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3981 parseFieldId(fieldName,
"expected field name"))
3986 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3987 for (
auto &elt : ubEntry) {
3988 if (elt.first == fieldAttr) {
3991 auto &instResult = elt.second;
3994 auto *defining = instResult.getDefiningOp();
3996 if (isa<WireOp>(defining)) {
3997 result = instResult;
4002 auto type = instResult.getType();
4006 auto annotations = getConstants().emptyArrayAttr;
4007 StringAttr sym = {};
4008 SmallString<64> name;
4009 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
4010 locationProcessor.setLoc(loc);
4011 OpBuilder::InsertionGuard guard(builder);
4012 builder.setInsertionPoint(defining);
4014 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
4016 auto bounceVal = bounce.getDataRaw();
4019 instResult.replaceAllUsesWith(bounceVal);
4022 builder.setInsertionPointAfter(defining);
4023 if (
foldFlow(instResult) == Flow::Source)
4025 getConstants().options.warnOnTruncation);
4028 getConstants().options.warnOnTruncation);
4032 result = instResult = bounce.getDataRaw();
4038 emitError(loc,
"use of invalid field name '")
4039 << fieldName <<
"' on bundle value";
4044 result = cast<Value>(symtabEntry);
4048 assert(isa<BlockArgument>(result) ||
4049 result.getDefiningOp<hw::InnerSymbolOpInterface>());
4055 type = result.getType();
4057 if (consumeIf(FIRToken::period)) {
4058 SmallVector<StringRef, 3> fields;
4059 if (parseFieldIdSeq(fields,
"expected field name"))
4061 for (
auto fieldName : fields) {
4062 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4063 if (
auto index = bundle.getElementIndex(fieldName)) {
4064 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4065 type = bundle.getElementTypePreservingConst(*index);
4068 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
4069 if (
auto index = bundle.getElementIndex(fieldName)) {
4070 refResult = refResult.
getSubField(bundle.getFieldID(*index));
4071 type = bundle.getElementTypePreservingConst(*index);
4075 return emitError(loc,
"subfield requires bundle operand")
4076 <<
"got " << type <<
"\n";
4078 return emitError(loc,
4079 "unknown field '" + fieldName +
"' in bundle type ")
4084 if (consumeIf(FIRToken::l_square)) {
4085 auto loc = getToken().
getLoc();
4087 if (parseIntLit(index,
"expected index") ||
4088 parseToken(FIRToken::r_square,
"expected ']'"))
4092 return emitError(loc,
"invalid index specifier");
4094 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
4095 if ((
unsigned)index < vector.getNumElements()) {
4096 refResult = refResult.
getSubField(vector.getFieldID(index));
4097 type = vector.getElementTypePreservingConst();
4100 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
4101 if ((
unsigned)index < vector.getNumElements()) {
4102 refResult = refResult.
getSubField(vector.getFieldID(index));
4103 type = vector.getElementTypePreservingConst();
4107 return emitError(loc,
"subindex requires vector operand");
4109 return emitError(loc,
"out of range index '")
4110 << index <<
"' for vector type " << type;
4118ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4119 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4120 StringRef intrinsic;
4121 ArrayAttr parameters;
4124 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4125 parseOptionalParams(parameters))
4128 if (consumeIf(FIRToken::colon)) {
4129 if (
parseType(type,
"expected intrinsic return type"))
4131 }
else if (!isStatement)
4132 return emitError(
"expected ':' in intrinsic expression");
4134 SmallVector<Value> operands;
4135 auto loc = startTok.getLoc();
4136 if (consumeIf(FIRToken::comma)) {
4137 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4139 if (parseExp(operand,
"expected operand in intrinsic"))
4141 operands.push_back(operand);
4142 locationProcessor.setLoc(loc);
4147 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4152 if (parseOptionalInfo())
4155 locationProcessor.setLoc(loc);
4157 auto op = GenericIntrinsicOp::create(
4158 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4160 result = op.getResult();
4165ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4166 if (!consumeIf(FIRToken::less))
4169 SmallVector<Attribute, 8> parameters;
4170 SmallPtrSet<StringAttr, 8> seen;
4171 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4175 if (parseParameter(name, value, loc))
4177 auto typedValue = dyn_cast<TypedAttr>(value);
4179 return emitError(loc)
4180 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4181 if (!seen.insert(name).second)
4182 return emitError(loc,
"redefinition of parameter '" +
4183 name.getValue() +
"'");
4184 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4189 resultParameters = ArrayAttr::get(getContext(), parameters);
4195ParseResult FIRStmtParser::parsePathExp(Value &result) {
4196 auto startTok = consumeToken(FIRToken::lp_path);
4197 locationProcessor.setLoc(startTok.getLoc());
4199 if (parseGetSpelling(target) ||
4200 parseToken(FIRToken::string,
4201 "expected target string in path expression") ||
4202 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4204 result = UnresolvedPathOp::create(
4210ParseResult FIRStmtParser::parseDomainInstantiation() {
4211 auto startTok = consumeToken(FIRToken::kw_domain);
4212 auto startLoc = startTok.getLoc();
4215 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4218 locationProcessor.setLoc(startTok.getLoc());
4220 StringAttr instanceName;
4221 StringAttr domainKind;
4224 parseId(instanceName,
"expected domain instance name") ||
4225 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4226 parseId(domainKind,
"expected domain type name"))
4231 const auto &domainMap = getConstants().domainMap;
4232 auto lookup = domainMap.find(domainKind.getValue());
4233 if (lookup == domainMap.end())
4234 return emitError(startTok.getLoc())
4235 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4237 auto domainType = DomainType::getFromDomainOp(lookup->second);
4240 SmallVector<Value> fieldValues;
4241 if (consumeIf(FIRToken::l_paren)) {
4243 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4245 if (parseExp(value,
"expected field value expression"))
4247 fieldValues.push_back(value);
4253 if (parseOptionalInfo())
4256 locationProcessor.setLoc(startLoc);
4258 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4261 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4266ParseResult FIRStmtParser::parseDomainDefine() {
4267 auto startTok = consumeToken(FIRToken::kw_domain_define);
4268 auto startLoc = startTok.getLoc();
4269 locationProcessor.setLoc(startLoc);
4273 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4274 parseDomainExp(src) || parseOptionalInfo())
4277 emitConnect(builder, dest, src, getConstants().options.warnOnTruncation);
4282ParseResult FIRStmtParser::parseRefDefine() {
4283 auto startTok = consumeToken(FIRToken::kw_define);
4286 if (parseStaticRefExp(target,
4287 "expected static reference expression in 'define'") ||
4288 parseToken(FIRToken::equal,
4289 "expected '=' after define reference expression") ||
4290 parseRefExp(src,
"expected reference expression in 'define'") ||
4291 parseOptionalInfo())
4295 if (!type_isa<RefType>(target.getType()))
4296 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4297 "'define' target (LHS), got ")
4298 << target.getType();
4299 if (!type_isa<RefType>(src.getType()))
4300 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4301 "'define' source (RHS), got ")
4306 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4307 return emitError(startTok.getLoc(),
4308 "cannot define into a sub-element of a reference");
4310 locationProcessor.setLoc(startTok.getLoc());
4313 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4314 << target.getType() <<
" with incompatible reference of type "
4317 emitConnect(builder, target, src, getConstants().options.warnOnTruncation);
4323ParseResult FIRStmtParser::parseRefRead(Value &result) {
4324 auto startTok = consumeToken(FIRToken::lp_read);
4327 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4328 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4331 locationProcessor.setLoc(startTok.getLoc());
4334 if (!type_isa<RefType>(ref.getType()))
4335 return emitError(startTok.getLoc(),
4336 "expected reference-type expression in 'read', got ")
4339 result = RefResolveOp::create(builder, ref);
4345ParseResult FIRStmtParser::parseProbe(Value &result) {
4346 auto startTok = consumeToken(FIRToken::lp_probe);
4349 if (parseStaticRefExp(staticRef,
4350 "expected static reference expression in 'probe'") ||
4351 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4354 locationProcessor.setLoc(startTok.getLoc());
4357 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4358 return emitError(startTok.getLoc(),
4359 "expected base-type expression in 'probe', got ")
4360 << staticRef.getType();
4364 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4365 MemoryDebugPortOp, MemoryPortAccessOp>(
4366 staticRef.getDefiningOp()))
4367 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4369 result = RefSendOp::create(builder, staticRef);
4375ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4376 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4379 Type parsedTargetType;
4380 if (parseRWProbeStaticRefExp(
4381 staticRef, parsedTargetType,
4382 "expected static reference expression in 'rwprobe'") ||
4383 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4386 locationProcessor.setLoc(startTok.getLoc());
4392 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4394 return emitError(startTok.getLoc(),
4395 "expected base-type expression in 'rwprobe', got ")
4396 << parsedTargetType;
4399 auto *definingOp = root.getDefiningOp();
4401 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4402 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4403 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4407 return emitError(startTok.getLoc(),
"cannot force target of type ")
4411 auto op = RWProbeOp::create(builder, forceableType,
4412 getConstants().placeholderInnerRef);
4419ParseResult FIRStmtParser::parseRefForce() {
4420 auto startTok = consumeToken(FIRToken::lp_force);
4422 Value clock, pred, dest, src;
4423 if (parseExp(clock,
"expected clock expression in force") ||
4424 parseToken(FIRToken::comma,
"expected ','") ||
4425 parseExp(pred,
"expected predicate expression in force") ||
4426 parseToken(FIRToken::comma,
"expected ','") ||
4427 parseRefExp(dest,
"expected destination reference expression in force") ||
4428 parseToken(FIRToken::comma,
"expected ','") ||
4429 parseExp(src,
"expected source expression in force") ||
4430 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4431 parseOptionalInfo())
4435 auto ref = type_dyn_cast<RefType>(dest.getType());
4436 if (!ref || !ref.getForceable())
4439 "expected rwprobe-type expression for force destination, got ")
4441 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4443 return emitError(startTok.getLoc(),
4444 "expected base-type for force source, got ")
4446 if (!srcBaseType.isPassive())
4447 return emitError(startTok.getLoc(),
4448 "expected passive value for force source, got ")
4451 locationProcessor.setLoc(startTok.getLoc());
4454 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4455 if (noConstSrcType != ref.getType()) {
4457 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4459 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4461 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4462 << src.getType() <<
" cannot target destination "
4466 RefForceOp::create(builder, clock, pred, dest, src);
4472ParseResult FIRStmtParser::parseRefForceInitial() {
4473 auto startTok = consumeToken(FIRToken::lp_force_initial);
4477 dest,
"expected destination reference expression in force_initial") ||
4478 parseToken(FIRToken::comma,
"expected ','") ||
4479 parseExp(src,
"expected source expression in force_initial") ||
4480 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4481 parseOptionalInfo())
4485 auto ref = type_dyn_cast<RefType>(dest.getType());
4486 if (!ref || !ref.getForceable())
4487 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4488 "force_initial destination, got ")
4490 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4492 return emitError(startTok.getLoc(),
4493 "expected base-type expression for force_initial "
4496 if (!srcBaseType.isPassive())
4497 return emitError(startTok.getLoc(),
4498 "expected passive value for force_initial source, got ")
4501 locationProcessor.setLoc(startTok.getLoc());
4504 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4505 if (noConstSrcType != ref.getType()) {
4507 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4509 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4511 return emitError(startTok.getLoc(),
4512 "incompatible force_initial source of type ")
4513 << src.getType() <<
" cannot target destination "
4517 auto value = APInt::getAllOnes(1);
4518 auto type = UIntType::get(builder.getContext(), 1);
4519 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4520 value.getBitWidth(),
4521 IntegerType::Unsigned),
4523 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4524 RefForceInitialOp::create(builder, pred, dest, src);
4530ParseResult FIRStmtParser::parseRefRelease() {
4531 auto startTok = consumeToken(FIRToken::lp_release);
4533 Value clock, pred, dest;
4534 if (parseExp(clock,
"expected clock expression in release") ||
4535 parseToken(FIRToken::comma,
"expected ','") ||
4536 parseExp(pred,
"expected predicate expression in release") ||
4537 parseToken(FIRToken::comma,
"expected ','") ||
4539 "expected destination reference expression in release") ||
4540 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4541 parseOptionalInfo())
4545 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4546 !ref || !ref.getForceable())
4549 "expected rwprobe-type expression for release destination, got ")
4552 locationProcessor.setLoc(startTok.getLoc());
4554 RefReleaseOp::create(builder, clock, pred, dest);
4560ParseResult FIRStmtParser::parseRefReleaseInitial() {
4561 auto startTok = consumeToken(FIRToken::lp_release_initial);
4566 "expected destination reference expression in release_initial") ||
4567 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4568 parseOptionalInfo())
4572 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4573 !ref || !ref.getForceable())
4574 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4575 "release_initial destination, got ")
4578 locationProcessor.setLoc(startTok.getLoc());
4580 auto value = APInt::getAllOnes(1);
4581 auto type = UIntType::get(builder.getContext(), 1);
4582 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4583 value.getBitWidth(),
4584 IntegerType::Unsigned),
4586 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4587 RefReleaseInitialOp::create(builder, pred, dest);
4593ParseResult FIRStmtParser::parseConnect() {
4594 auto startTok = consumeToken(FIRToken::kw_connect);
4595 auto loc = startTok.getLoc();
4598 if (parseExp(lhs,
"expected connect expression") ||
4599 parseToken(FIRToken::comma,
"expected ','") ||
4600 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4603 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4604 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4605 if (!lhsType || !rhsType)
4606 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4607 "cannot connect reference or property types");
4609 if (lhsType.containsReference() || rhsType.containsReference())
4610 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4611 "cannot connect types containing references");
4614 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4615 "cannot connect non-equivalent type ")
4616 << rhsType <<
" to " << lhsType;
4618 locationProcessor.setLoc(loc);
4620 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4621 getConstants().options.warnOnTruncation);
4632ParseResult FIRStmtParser::parsePropAssert() {
4633 auto startTok = consumeToken(FIRToken::kw_propassert);
4634 auto loc = startTok.getLoc();
4636 llvm::SMLoc conditionLoc = getToken().getLoc(), messageLoc;
4637 Value condition, message;
4638 if (parseExp(condition,
"expected condition in 'propassert'") ||
4639 parseToken(FIRToken::comma,
"expected ','"))
4642 if (getToken().is(FIRToken::string)) {
4643 if (removedFeature({8, 0, 0},
"string messages in property asserts"))
4645 StringRef messageStr;
4646 messageLoc = getToken().getLoc();
4647 if (parseGetSpelling(messageStr) ||
4648 parseToken(FIRToken::string,
"expected message string in 'propassert'"))
4650 locationProcessor.setLoc(messageLoc);
4652 message = moduleContext.getCachedConstant<StringConstantOp>(
4653 builder, attr, builder.getType<StringType>(), attr);
4657 "string property expression message in property asserts"))
4659 messageLoc = getToken().getLoc();
4660 if (parseExp(message,
"expected message in 'propassert'"))
4664 if (!isa<BoolType>(condition.getType()))
4665 return emitError(conditionLoc,
4666 "propassert condition must be of boolean type");
4669 if (!type_isa<StringType>(message.getType()))
4670 return emitError(messageLoc,
"propassert message must be a string type");
4672 if (parseOptionalInfo())
4675 locationProcessor.setLoc(loc);
4676 PropertyAssertOp::create(builder, condition, message);
4681ParseResult FIRStmtParser::parsePropAssign() {
4682 auto startTok = consumeToken(FIRToken::kw_propassign);
4683 auto loc = startTok.getLoc();
4686 if (parseExp(lhs,
"expected propassign expression") ||
4687 parseToken(FIRToken::comma,
"expected ','") ||
4688 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4691 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4692 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4693 if (!lhsType || !rhsType)
4694 return emitError(loc,
"can only propassign property types");
4695 locationProcessor.setLoc(loc);
4696 if (lhsType != rhsType) {
4698 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4699 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4701 return emitError(loc,
"cannot propassign non-equivalent type ")
4702 << rhsType <<
" to " << lhsType;
4704 PropAssignOp::create(builder, lhs, rhs);
4709ParseResult FIRStmtParser::parseInvalidate() {
4710 auto startTok = consumeToken(FIRToken::kw_invalidate);
4715 auto loc = getToken().getLoc();
4717 if (parseId(
id,
"expected static reference expression") ||
4718 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4723 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4724 if (parseOptionalExpPostscript(lhs,
false) ||
4725 parseOptionalInfo())
4728 locationProcessor.setLoc(startTok.getLoc());
4729 emitInvalidate(lhs);
4736 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4738 if (getToken().isNot(FIRToken::period)) {
4739 locationProcessor.setLoc(loc);
4741 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4743 for (
auto elt : ubEntry)
4744 emitInvalidate(elt.second);
4750 StringRef fieldName;
4751 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4752 parseFieldId(fieldName,
"expected field name") ||
4753 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4757 if (parseOptionalExpPostscript(lhs,
false) ||
4758 parseOptionalInfo())
4761 locationProcessor.setLoc(startTok.getLoc());
4762 emitInvalidate(lhs);
4766ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4768 auto startTok = consumeToken();
4769 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4770 "consumed an unexpected token");
4771 auto loc = startTok.getLoc();
4774 if (parseId(
id,
"expected layer identifer") ||
4775 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4776 parseOptionalInfo())
4779 locationProcessor.setLoc(loc);
4781 StringRef rootLayer;
4782 SmallVector<FlatSymbolRefAttr> nestedLayers;
4786 rootLayer = layerSym.getRootReference();
4787 auto nestedRefs = layerSym.getNestedReferences();
4788 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4789 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4792 auto layerBlockOp = LayerBlockOp::create(
4794 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4795 layerBlockOp->getRegion(0).push_back(
new Block());
4797 if (getIndentation() > indent)
4798 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4799 layerBlockOp.getLayerName()))
4807ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4808 auto loc = getToken().getLoc();
4811 if (consumeIf(FIRToken::kw_is)) {
4812 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4813 parseOptionalInfo())
4816 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4819 locationProcessor.setLoc(loc);
4820 emitInvalidate(lhs);
4824 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4827 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4831 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4834 locationProcessor.setLoc(loc);
4836 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4837 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4838 if (!lhsType || !rhsType)
4839 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4840 "cannot connect reference or property types");
4842 if (lhsType.containsReference() || rhsType.containsReference())
4843 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4844 "cannot connect types containing references");
4847 return mlir::emitError(locationProcessor.getLoc(*
this, loc),
4848 "cannot connect non-equivalent type ")
4849 << rhsType <<
" to " << lhsType;
4851 builder, lhs, rhs, [&] {
return locationProcessor.getLoc(*
this, loc); },
4852 getConstants().options.warnOnTruncation);
4860ParseResult FIRStmtParser::parseInstance() {
4861 auto startTok = consumeToken(FIRToken::kw_inst);
4865 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4869 StringRef moduleName;
4870 if (parseId(
id,
"expected instance name") ||
4871 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4872 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4875 locationProcessor.setLoc(startTok.getLoc());
4878 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4879 if (!referencedModule)
4882 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4884 auto annotations = getConstants().emptyArrayAttr;
4885 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4887 hw::InnerSymAttr sym = {};
4888 auto result = InstanceOp::create(
4889 builder, referencedModule,
id, NameKindEnum::InterestingName,
4890 annotations.getValue(), portAnnotations,
false,
false, sym);
4896 unbundledValueEntry.reserve(modulePorts.size());
4897 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4898 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4902 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4903 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4904 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4909ParseResult FIRStmtParser::parseInstanceChoice() {
4910 auto startTok = consumeToken(FIRToken::kw_instchoice);
4911 SMLoc loc = startTok.getLoc();
4914 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4921 StringRef defaultModuleName;
4922 StringRef optionGroupName;
4923 if (parseId(
id,
"expected instance name") ||
4924 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4925 parseId(defaultModuleName,
"expected module name") ||
4926 parseToken(FIRToken::comma,
"expected ','") ||
4927 parseId(optionGroupName,
"expected option group name") ||
4928 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4929 parseOptionalInfo())
4932 locationProcessor.setLoc(startTok.getLoc());
4936 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4940 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4943 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4945 return emitError(loc,
4946 "use of undefined option group '" + optionGroupName +
"'");
4948 auto baseIndent = getIndentation();
4949 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4950 while (getIndentation() == baseIndent) {
4952 StringRef caseModuleName;
4953 if (parseId(caseId,
"expected a case identifier") ||
4954 parseToken(FIRToken::equal_greater,
4955 "expected '=> in instance choice definition") ||
4956 parseId(caseModuleName,
"expected module name"))
4959 auto caseModule = getReferencedModule(loc, caseModuleName);
4963 for (
const auto &[defaultPort, casePort] :
4964 llvm::zip(modulePorts, caseModule.getPorts())) {
4965 if (defaultPort.name != casePort.name)
4966 return emitError(loc,
"instance case module port '")
4967 << casePort.name.getValue()
4968 <<
"' does not match the default module port '"
4969 << defaultPort.name.getValue() <<
"'";
4970 if (defaultPort.type != casePort.type)
4971 return emitError(loc,
"instance case port '")
4972 << casePort.name.getValue()
4973 <<
"' type does not match the default module port";
4977 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4979 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4980 caseModules.emplace_back(optionCase, caseModule);
4983 auto annotations = getConstants().emptyArrayAttr;
4984 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4988 auto result = InstanceChoiceOp::create(
4989 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4990 annotations.getValue(), portAnnotations, sym);
4994 unbundledValueEntry.reserve(modulePorts.size());
4995 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4996 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4998 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4999 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
5000 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
5003FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
5004 StringRef moduleName) {
5005 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
5006 if (!referencedModule) {
5008 "use of undefined module name '" + moduleName +
"' in instance");
5011 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
5012 emitError(loc,
"cannot create instance of class '" + moduleName +
5013 "', did you mean object?");
5016 return referencedModule;
5020ParseResult FIRStmtParser::parseObject() {
5021 auto startTok = consumeToken(FIRToken::kw_object);
5025 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5028 if (requireFeature({6, 0, 0},
"object statements"))
5032 StringRef className;
5033 if (parseId(
id,
"expected object name") ||
5034 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
5035 parseId(className,
"expected class name") || parseOptionalInfo())
5038 locationProcessor.setLoc(startTok.getLoc());
5041 const auto &classMap = getConstants().classMap;
5042 auto lookup = classMap.find(className);
5043 if (lookup == classMap.end())
5044 return emitError(startTok.getLoc(),
"use of undefined class name '" +
5045 className +
"' in object");
5046 auto referencedClass = lookup->getSecond();
5047 auto result = ObjectOp::create(builder, referencedClass,
id);
5048 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5052ParseResult FIRStmtParser::parseCombMem() {
5054 auto startTok = consumeToken(FIRToken::kw_cmem);
5058 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5063 if (parseId(
id,
"expected cmem name") ||
5064 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
5065 parseType(type,
"expected cmem type") || parseOptionalInfo())
5068 locationProcessor.setLoc(startTok.getLoc());
5071 auto vectorType = type_dyn_cast<FVectorType>(type);
5073 return emitError(
"cmem requires vector type");
5075 auto annotations = getConstants().emptyArrayAttr;
5076 StringAttr sym = {};
5077 auto result = CombMemOp::create(
5078 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
5079 NameKindEnum::InterestingName, annotations, sym);
5080 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5084ParseResult FIRStmtParser::parseSeqMem() {
5086 auto startTok = consumeToken(FIRToken::kw_smem);
5090 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5095 RUWBehavior ruw = RUWBehavior::Undefined;
5097 if (parseId(
id,
"expected smem name") ||
5098 parseToken(FIRToken::colon,
"expected ':' in smem") ||
5102 if (consumeIf(FIRToken::comma)) {
5107 if (parseOptionalInfo()) {
5111 locationProcessor.setLoc(startTok.getLoc());
5114 auto vectorType = type_dyn_cast<FVectorType>(type);
5116 return emitError(
"smem requires vector type");
5118 auto annotations = getConstants().emptyArrayAttr;
5119 StringAttr sym = {};
5120 auto result = SeqMemOp::create(
5121 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
5122 id, NameKindEnum::InterestingName, annotations, sym);
5123 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5135ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
5136 auto startTok = consumeToken(FIRToken::kw_mem);
5140 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5144 if (parseId(
id,
"expected mem name") ||
5145 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
5149 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5150 RUWBehavior ruw = RUWBehavior::Undefined;
5152 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5156 auto nextIndent = getIndentation();
5157 if (!nextIndent || *nextIndent <= memIndent)
5160 auto spelling = getTokenSpelling();
5161 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
5162 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
5165 if (spelling ==
"data-type") {
5167 return emitError(
"'mem' type specified multiple times"), failure();
5169 if (
parseType(type,
"expected type in data-type declaration"))
5173 if (spelling ==
"depth") {
5174 if (parseIntLit(depth,
"expected integer in depth specification"))
5178 if (spelling ==
"read-latency") {
5179 if (parseIntLit(readLatency,
"expected integer latency"))
5183 if (spelling ==
"write-latency") {
5184 if (parseIntLit(writeLatency,
"expected integer latency"))
5188 if (spelling ==
"read-under-write") {
5189 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5190 FIRToken::kw_undefined))
5191 return emitError(
"expected specifier"), failure();
5193 if (parseOptionalRUW(ruw))
5198 MemOp::PortKind portKind;
5199 if (spelling ==
"reader")
5200 portKind = MemOp::PortKind::Read;
5201 else if (spelling ==
"writer")
5202 portKind = MemOp::PortKind::Write;
5203 else if (spelling ==
"readwriter")
5204 portKind = MemOp::PortKind::ReadWrite;
5206 return emitError(
"unexpected field in 'mem' declaration"), failure();
5209 if (parseId(portName,
"expected port name"))
5211 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5213 return emitError(
"unexpected type, must be base type");
5214 ports.push_back({builder.getStringAttr(portName),
5215 MemOp::getTypeForPort(depth, baseType, portKind)});
5217 while (!getIndentation().has_value()) {
5218 if (parseId(portName,
"expected port name"))
5220 ports.push_back({builder.getStringAttr(portName),
5221 MemOp::getTypeForPort(depth, baseType, portKind)});
5232 llvm::array_pod_sort(ports.begin(), ports.end(),
5233 [](
const std::pair<StringAttr, Type> *lhs,
5234 const std::pair<StringAttr, Type> *rhs) ->
int {
5235 return lhs->first.getValue().compare(
5236 rhs->first.getValue());
5239 auto annotations = getConstants().emptyArrayAttr;
5240 SmallVector<Attribute, 4> resultNames;
5241 SmallVector<Type, 4> resultTypes;
5242 SmallVector<Attribute, 4> resultAnnotations;
5243 for (
auto p : ports) {
5244 resultNames.push_back(p.first);
5245 resultTypes.push_back(p.second);
5246 resultAnnotations.push_back(annotations);
5249 locationProcessor.setLoc(startTok.getLoc());
5251 auto result = MemOp::create(
5252 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5253 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5254 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5255 MemoryInitAttr(), StringAttr());
5258 unbundledValueEntry.reserve(result.getNumResults());
5259 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5260 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5262 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5263 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5264 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5268ParseResult FIRStmtParser::parseNode() {
5269 auto startTok = consumeToken(FIRToken::kw_node);
5273 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5278 if (parseId(
id,
"expected node name") ||
5279 parseToken(FIRToken::equal,
"expected '=' in node") ||
5280 parseExp(initializer,
"expected expression for node") ||
5281 parseOptionalInfo())
5284 locationProcessor.setLoc(startTok.getLoc());
5296 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5297 auto initializerBaseType =
5298 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5299 if (type_isa<AnalogType>(initializerType) ||
5300 !(initializerBaseType && initializerBaseType.isPassive())) {
5301 emitError(startTok.getLoc())
5302 <<
"Node cannot be analog and must be passive or passive under a flip "
5303 << initializer.getType();
5307 auto annotations = getConstants().emptyArrayAttr;
5308 StringAttr sym = {};
5310 auto result = NodeOp::create(builder, initializer,
id,
5311 NameKindEnum::InterestingName, annotations, sym);
5312 return moduleContext.addSymbolEntry(
id, result.getResult(),
5317ParseResult FIRStmtParser::parseWire() {
5318 auto startTok = consumeToken(FIRToken::kw_wire);
5322 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5327 if (parseId(
id,
"expected wire name") ||
5328 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5333 SmallVector<Value> domains;
5334 if (consumeIf(FIRToken::kw_domains)) {
5338 if (parseToken(FIRToken::l_square,
"expected '[' after 'domains'"))
5341 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5342 StringRef domainName;
5343 auto domainLoc = getToken().getLoc();
5344 if (parseId(domainName,
"expected domain name"))
5349 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5354 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5357 if (!isa<DomainType>(domainValue.getType()))
5358 return emitError(domainLoc)
5359 <<
"'" << domainName <<
"' is not a domain";
5361 domains.push_back(domainValue);
5367 if (parseOptionalInfo())
5370 locationProcessor.setLoc(startTok.getLoc());
5372 auto annotations = getConstants().emptyArrayAttr;
5373 StringAttr sym = {};
5376 auto namekind = isa<PropertyType, RefType>(type)
5377 ? NameKindEnum::DroppableName
5378 : NameKindEnum::InterestingName;
5380 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym,
5382 return moduleContext.addSymbolEntry(
id, result.getResult(),
5396ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5397 auto startTok = consumeToken(FIRToken::kw_reg);
5401 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5410 if (parseId(
id,
"expected reg name") ||
5411 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5413 parseToken(FIRToken::comma,
"expected ','") ||
5414 parseExp(clock,
"expected expression for register clock"))
5417 if (!type_isa<FIRRTLBaseType>(type))
5418 return emitError(startTok.getLoc(),
"register must have base type");
5421 Value resetSignal, resetValue;
5422 if (consumeIf(FIRToken::kw_with)) {
5423 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5426 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5434 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5436 auto indent = getIndentation();
5437 if (!indent || *indent <= regIndent)
5438 if (!hasExtraLParen)
5439 return emitError(
"expected indented reset specifier in reg"), failure();
5441 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5442 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5443 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5444 parseExp(resetSignal,
"expected expression for reset signal") ||
5445 parseToken(FIRToken::comma,
"expected ','"))
5453 if (getTokenSpelling() ==
id) {
5455 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5457 resetSignal = Value();
5459 if (parseExp(resetValue,
"expected expression for reset value") ||
5460 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5464 if (hasExtraLParen &&
5465 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5471 if (parseOptionalInfo())
5474 locationProcessor.setLoc(startTok.getLoc());
5476 ArrayAttr annotations = getConstants().emptyArrayAttr;
5478 StringAttr sym = {};
5481 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5482 NameKindEnum::InterestingName, annotations, sym)
5485 result = RegOp::create(builder, type, clock,
id,
5486 NameKindEnum::InterestingName, annotations, sym)
5488 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5496ParseResult FIRStmtParser::parseRegisterWithReset() {
5497 auto startTok = consumeToken(FIRToken::kw_regreset);
5501 Value clock, resetSignal, resetValue;
5503 if (parseId(
id,
"expected reg name") ||
5504 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5506 parseToken(FIRToken::comma,
"expected ','") ||
5507 parseExp(clock,
"expected expression for register clock") ||
5508 parseToken(FIRToken::comma,
"expected ','") ||
5509 parseExp(resetSignal,
"expected expression for register reset") ||
5510 parseToken(FIRToken::comma,
"expected ','") ||
5511 parseExp(resetValue,
"expected expression for register reset value") ||
5512 parseOptionalInfo())
5515 if (!type_isa<FIRRTLBaseType>(type))
5516 return emitError(startTok.getLoc(),
"register must have base type");
5518 locationProcessor.setLoc(startTok.getLoc());
5521 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5522 NameKindEnum::InterestingName,
5523 getConstants().emptyArrayAttr, StringAttr{})
5526 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5531ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5535 auto startTok = consumeToken(FIRToken::kw_contract);
5538 SmallVector<StringRef> ids;
5539 SmallVector<SMLoc> locs;
5540 SmallVector<Value> values;
5541 SmallVector<Type> types;
5542 if (!consumeIf(FIRToken::colon)) {
5543 auto parseContractId = [&] {
5545 locs.push_back(getToken().
getLoc());
5546 if (parseId(
id,
"expected contract result name"))
5551 auto parseContractValue = [&] {
5553 if (parseExp(value,
"expected expression for contract result"))
5555 values.push_back(value);
5556 types.push_back(value.getType());
5559 if (parseListUntil(FIRToken::equal, parseContractId) ||
5560 parseListUntil(FIRToken::colon, parseContractValue))
5563 if (parseOptionalInfo())
5567 if (ids.size() != values.size())
5568 return emitError(startTok.getLoc())
5569 <<
"contract requires same number of results and expressions; got "
5570 << ids.size() <<
" results and " << values.size()
5571 <<
" expressions instead";
5573 locationProcessor.setLoc(startTok.getLoc());
5577 auto contract = ContractOp::create(builder, types, values);
5578 auto &block = contract.getBody().emplaceBlock();
5582 FIRModuleContext::ContextScope scope(moduleContext, &block);
5583 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5584 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5585 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5588 if (getIndentation() > blockIndent)
5589 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5594 for (
auto [
id, loc, value, result] :
5595 llvm::zip(ids, locs, values, contract.getResults())) {
5597 moduleContext.removeSymbolEntry(
id);
5598 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5611struct FIRCircuitParser :
public FIRParser {
5612 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5614 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5617 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5618 mlir::TimingScope &ts);
5623 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5624 SmallVectorImpl<Attribute> &attrs);
5626 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5628 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5629 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5630 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5631 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5632 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5633 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5634 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5635 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5637 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5639 ParseResult parseLayerName(SymbolRefAttr &result);
5640 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5641 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5642 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5643 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5644 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5645 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5646 ArrayAttr &knownLayers,
5647 ArrayAttr &externalRequirements);
5649 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5650 SmallVectorImpl<SMLoc> &resultPortLocs,
5654 ParseResult skipToModuleEnd(
unsigned indent);
5656 ParseResult parseTypeDecl();
5658 ParseResult parseOptionDecl(CircuitOp circuit);
5660 ParseResult parseLayer(CircuitOp circuit);
5662 ParseResult resolveDomains(
5663 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5664 const DenseMap<Attribute, size_t> &nameToIndex,
5665 SmallVectorImpl<Attribute> &domainsByIndex);
5668 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5669 const DenseMap<Attribute, size_t> &nameToIndex);
5671 struct DeferredModuleToParse {
5672 FModuleLike moduleOp;
5673 SmallVector<SMLoc> portLocs;
5678 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5679 DeferredModuleToParse &deferredModule,
5680 InnerSymFixups &fixups);
5682 SmallVector<DeferredModuleToParse, 0> deferredModules;
5684 SmallVector<InnerSymFixups, 0> moduleFixups;
5688 ModuleOp mlirModule;
5693FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5694 SmallVectorImpl<Attribute> &attrs) {
5696 auto annotations = json::parse(annotationsStr);
5697 if (
auto err = annotations.takeError()) {
5698 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5699 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5700 diag.attachNote() << a.message();
5705 json::Path::Root root;
5706 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5709 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5710 std::string jsonErrorMessage =
5711 "See inline comments for problem area in JSON:\n";
5712 llvm::raw_string_ostream
s(jsonErrorMessage);
5713 root.printErrorContext(annotations.get(), s);
5714 diag.attachNote() << jsonErrorMessage;
5721ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5723 SmallVector<StringRef> strings;
5726 if (parseId(name,
"expected layer name"))
5728 strings.push_back(name);
5729 }
while (consumeIf(FIRToken::period));
5731 SmallVector<FlatSymbolRefAttr> nested;
5732 nested.reserve(strings.size() - 1);
5733 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5734 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5736 result = SymbolRefAttr::get(
context, strings[0], nested);
5740ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5741 SmallVector<Attribute> enabledLayersBuffer;
5743 auto tokenKind = getToken().getKind();
5745 if (tokenKind == FIRToken::kw_enablelayer) {
5746 if (parseEnableLayerSpec(enabledLayersBuffer))
5754 if (enabledLayersBuffer.size() != 0)
5755 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5758 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5762ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5763 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5764 ArrayAttr &externalRequirements) {
5765 SmallVector<Attribute> enabledLayersBuffer;
5766 SmallVector<Attribute> knownLayersBuffer;
5767 SmallVector<Attribute> requirementsBuffer;
5769 auto tokenKind = getToken().getKind();
5771 if (tokenKind == FIRToken::kw_enablelayer) {
5772 if (parseEnableLayerSpec(enabledLayersBuffer))
5777 if (tokenKind == FIRToken::kw_knownlayer) {
5778 if (parseKnownLayerSpec(knownLayersBuffer))
5783 if (tokenKind == FIRToken::kw_requires) {
5784 if (parseRequiresSpec(requirementsBuffer))
5792 if (enabledLayersBuffer.size() != 0)
5793 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5796 if (knownLayersBuffer.size() != 0)
5797 if (requireFeature({6, 0, 0},
"extmodules with known layers"))
5800 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5801 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5802 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5807FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5809 SymbolRefAttr layer;
5810 if (parseLayerName(layer))
5812 result.push_back(layer);
5813 }
while (consumeIf(FIRToken::comma));
5818FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5819 consumeToken(FIRToken::kw_enablelayer);
5820 return parseLayerList(result);
5824FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5825 consumeToken(FIRToken::kw_knownlayer);
5826 return parseLayerList(result);
5830FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5831 consumeToken(FIRToken::kw_requires);
5833 StringRef requireStr;
5834 if (parseGetSpelling(requireStr) ||
5835 parseToken(FIRToken::string,
"expected string after 'requires'"))
5839 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5840 }
while (consumeIf(FIRToken::comma));
5848FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5849 SmallVectorImpl<SMLoc> &resultPortLocs,
5855 DenseMap<Attribute, size_t> nameToIndex;
5856 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5859 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5861 getIndentation() > indent) {
5867 auto backtrackState = getLexer().getCursor();
5869 bool isOutput = getToken().is(FIRToken::kw_output);
5874 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5875 !getToken().isKeyword()) {
5876 backtrackState.restore(getLexer());
5883 if (parseId(name,
"expected port name") ||
5884 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5885 parseType(type,
"expected a type in port declaration"))
5887 Attribute domainInfoElement = {};
5888 size_t portIdx = resultPorts.size();
5889 if (
auto domainType = dyn_cast<DomainType>(type)) {
5892 domainInfoElement = ArrayAttr::get(getContext(), {});
5894 if (getToken().is(FIRToken::kw_domains))
5895 if (parseDomains(domainNames[portIdx], nameToIndex))
5899 if (
info.parseOptionalInfo())
5902 StringAttr innerSym = {};
5903 resultPorts.push_back(
PortInfo{name,
5909 domainInfoElement});
5910 resultPortLocs.push_back(
info.getFIRLoc());
5911 nameToIndex.insert({name, portIdx});
5915 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5916 auto &port = resultPorts[portIdx];
5917 Attribute &attr = port.domains;
5921 SmallVector<Attribute> domainInfo;
5922 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5924 attr = ArrayAttr::get(getContext(), domainInfo);
5929 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5930 PortInfo &port = std::get<0>(portAndLoc);
5931 auto &entry = portIds[port.
name];
5932 if (!entry.isValid()) {
5933 entry = std::get<1>(portAndLoc);
5937 emitError(std::get<1>(portAndLoc),
5938 "redefinition of name '" + port.
getName() +
"'")
5939 .attachNote(translateLocation(entry))
5940 <<
"previous definition here";
5949ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5951 switch (getToken().getKind()) {
5955 case FIRToken::error:
5959 case FIRToken::kw_class:
5960 case FIRToken::kw_domain:
5961 case FIRToken::kw_declgroup:
5962 case FIRToken::kw_extclass:
5963 case FIRToken::kw_extmodule:
5964 case FIRToken::kw_intmodule:
5965 case FIRToken::kw_formal:
5966 case FIRToken::kw_module:
5967 case FIRToken::kw_public:
5968 case FIRToken::kw_layer:
5969 case FIRToken::kw_option:
5970 case FIRToken::kw_simulation:
5971 case FIRToken::kw_type:
5975 if (getIndentation() == indent)
5987ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5988 SmallVector<Attribute, 8> parameters;
5989 SmallPtrSet<StringAttr, 8> seen;
5990 while (consumeIf(FIRToken::kw_parameter)) {
5994 if (parseParameter(name, value, loc))
5996 auto typedValue = dyn_cast<TypedAttr>(value);
5998 return emitError(loc)
5999 <<
"invalid value for parameter '" << name.getValue() <<
"'";
6000 if (!seen.insert(name).second)
6001 return emitError(loc,
6002 "redefinition of parameter '" + name.getValue() +
"'");
6003 parameters.push_back(ParamDeclAttr::get(name, typedValue));
6005 resultParameters = ArrayAttr::get(getContext(), parameters);
6010ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
6012 SmallVector<PortInfo, 8> portList;
6013 SmallVector<SMLoc> portLocs;
6016 if (requireFeature({6, 0, 0},
"classes"))
6019 consumeToken(FIRToken::kw_class);
6020 if (parseId(name,
"expected class name") ||
6021 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
6025 if (name == circuit.getName())
6026 return mlir::emitError(
info.getLoc(),
6027 "class cannot be the top of a circuit");
6029 for (
auto &portInfo : portList)
6031 return
mlir::emitError(portInfo.loc,
6032 "ports on classes must be properties");
6035 auto builder = circuit.getBodyBuilder();
6036 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
6037 classOp.setPrivate();
6038 deferredModules.emplace_back(
6039 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
6042 getConstants().classMap[name.getValue()] = classOp;
6043 return skipToModuleEnd(indent);
6047ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
6048 consumeToken(FIRToken::kw_domain);
6052 if (parseId(name,
"domain name") ||
6053 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
6054 info.parseOptionalInfo())
6057 SmallVector<Attribute> fields;
6059 auto nextIndent = getIndentation();
6060 if (!nextIndent || *nextIndent <= indent)
6063 StringAttr fieldName;
6065 if (parseId(fieldName,
"field name") ||
6066 parseToken(FIRToken::colon,
"expected ':' after field name") ||
6067 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
6071 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
6074 auto builder = circuit.getBodyBuilder();
6076 DomainOp::create(builder,
info.getLoc(), name, {},
6077 builder.getArrayAttr(fields));
6081 getConstants().domainMap[name.getValue()] = domainOp;
6087ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
6090 SmallVector<PortInfo, 8> portList;
6091 SmallVector<SMLoc> portLocs;
6094 if (requireFeature({6, 0, 0},
"classes"))
6097 consumeToken(FIRToken::kw_extclass);
6098 if (parseId(name,
"expected extclass name") ||
6099 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
6103 if (name == circuit.getName())
6104 return mlir::emitError(
info.getLoc(),
6105 "extclass cannot be the top of a circuit");
6107 for (
auto &portInfo : portList)
6109 return
mlir::emitError(portInfo.loc,
6110 "ports on extclasses must be properties");
6113 auto builder = circuit.getBodyBuilder();
6114 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
6117 getConstants().classMap[name.getValue()] = extClassOp;
6118 return skipToModuleEnd(indent);
6126ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
6129 ArrayAttr enabledLayers;
6130 ArrayAttr knownLayers;
6131 ArrayAttr externalRequirements;
6132 SmallVector<PortInfo, 8> portList;
6133 SmallVector<SMLoc> portLocs;
6135 consumeToken(FIRToken::kw_extmodule);
6136 if (parseId(name,
"expected extmodule name") ||
6137 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
6138 externalRequirements) ||
6139 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
6144 if (consumeIf(FIRToken::kw_defname)) {
6145 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
6146 parseId(defName,
"expected defname name"))
6150 ArrayAttr parameters;
6155 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6156 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6157 if (ftype.hasUninferredWidth())
6158 return emitError(loc,
"extmodule port must have known width");
6163 auto builder = circuit.getBodyBuilder();
6164 auto isMainModule = (name == circuit.getName());
6166 (isMainModule && getConstants().options.scalarizePublicModules) ||
6167 getConstants().options.scalarizeExtModules
6168 ? Convention::Scalarized
6169 : Convention::Internal;
6170 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6171 auto annotations = ArrayAttr::get(getContext(), {});
6172 auto extModuleOp = FExtModuleOp::create(
6173 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
6174 defName, annotations, parameters, enabledLayers, externalRequirements);
6175 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6176 : SymbolTable::Visibility::Private;
6177 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6185ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6189 ArrayAttr enabledLayers;
6190 SmallVector<PortInfo, 8> portList;
6191 SmallVector<SMLoc> portLocs;
6193 consumeToken(FIRToken::kw_intmodule);
6194 if (parseId(name,
"expected intmodule name") ||
6195 parseModuleLayerSpec(enabledLayers) ||
6196 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
6198 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
6199 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
6200 parseId(intName,
"expected intrinsic name"))
6203 ArrayAttr parameters;
6207 ArrayAttr annotations = getConstants().emptyArrayAttr;
6208 auto builder = circuit.getBodyBuilder();
6209 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
6210 annotations, parameters, enabledLayers)
6216ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
6219 SmallVector<PortInfo, 8> portList;
6220 SmallVector<SMLoc> portLocs;
6221 ArrayAttr enabledLayers;
6222 auto modLoc = getToken().getLoc();
6223 LocWithInfo
info(modLoc,
this);
6224 consumeToken(FIRToken::kw_module);
6225 if (parseId(name,
"expected module name") ||
6226 parseModuleLayerSpec(enabledLayers) ||
6227 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
6232 if (name == circuit.getName()) {
6233 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
6238 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
6239 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6240 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6241 if (ftype.hasUninferredWidth())
6242 return emitError(loc,
"public module port must have known width");
6243 if (ftype.hasUninferredReset())
6244 return emitError(loc,
6245 "public module port must have concrete reset type");
6250 ArrayAttr annotations = getConstants().emptyArrayAttr;
6251 auto convention = Convention::Internal;
6252 if (isPublic && getConstants().options.scalarizePublicModules)
6253 convention = Convention::Scalarized;
6254 if (!isPublic && getConstants().options.scalarizeInternalModules)
6255 convention = Convention::Scalarized;
6256 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6257 auto builder = circuit.getBodyBuilder();
6259 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6260 annotations, enabledLayers);
6262 auto visibility = isPublic ? SymbolTable::Visibility::Public
6263 : SymbolTable::Visibility::Private;
6264 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6268 deferredModules.emplace_back(DeferredModuleToParse{
6269 moduleOp, portLocs, getLexer().getCursor(), indent});
6271 if (skipToModuleEnd(indent))
6277ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6278 consumeToken(FIRToken::kw_formal);
6279 return parseFormalLike<FormalOp>(circuit, indent);
6283ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6285 consumeToken(FIRToken::kw_simulation);
6286 return parseFormalLike<SimulationOp>(circuit, indent);
6293ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6295 StringRef id, moduleName;
6298 auto builder = circuit.getBodyBuilder();
6301 if (parseId(
id,
"expected test name") ||
6302 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6303 parseId(moduleName,
"expected module name"))
6307 NamedAttrList params;
6308 if (consumeIf(FIRToken::comma)) {
6310 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6311 return emitError(
"expected 'bound' after ','");
6313 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6314 parseIntLit(bound,
"expected integer bound after '='"))
6317 return emitError(
"bound must be a positive integer");
6318 if (
info.parseOptionalInfo())
6320 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6323 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6324 info.parseOptionalInfo())
6326 while (getIndentation() > indent) {
6327 StringAttr paramName;
6328 Attribute paramValue;
6330 if (parseParameter(paramName, paramValue, paramLoc,
6333 if (params.set(paramName, paramValue))
6334 return emitError(paramLoc,
"redefinition of parameter '" +
6335 paramName.getValue() +
"'");
6339 Op::create(builder,
info.getLoc(),
id, {}, moduleName,
6340 params.getDictionary(getContext()));
6344ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6346 switch (getToken().getKind()) {
6347 case FIRToken::kw_class:
6348 return parseClass(circuit, indent);
6349 case FIRToken::kw_declgroup:
6350 if (requireFeature({3, 2, 0},
"optional groups") ||
6351 removedFeature({3, 3, 0},
"optional groups"))
6353 return parseLayer(circuit);
6354 case FIRToken::kw_domain:
6357 return parseDomain(circuit, indent);
6358 case FIRToken::kw_extclass:
6359 return parseExtClass(circuit, indent);
6360 case FIRToken::kw_extmodule:
6361 return parseExtModule(circuit, indent);
6362 case FIRToken::kw_formal:
6363 if (requireFeature({4, 0, 0},
"formal tests"))
6365 return parseFormal(circuit, indent);
6366 case FIRToken::kw_intmodule:
6367 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6368 removedFeature({4, 0, 0},
"intrinsic modules"))
6370 return parseIntModule(circuit, indent);
6371 case FIRToken::kw_layer:
6372 if (requireFeature({3, 3, 0},
"layers"))
6374 return parseLayer(circuit);
6375 case FIRToken::kw_module:
6376 return parseModule(circuit,
false, indent);
6377 case FIRToken::kw_public:
6378 if (requireFeature({3, 3, 0},
"public modules"))
6381 if (getToken().getKind() == FIRToken::kw_module)
6382 return parseModule(circuit,
true, indent);
6383 return emitError(getToken().
getLoc(),
"only modules may be public");
6384 case FIRToken::kw_simulation:
6387 return parseSimulation(circuit, indent);
6388 case FIRToken::kw_type:
6389 return parseTypeDecl();
6390 case FIRToken::kw_option:
6393 return parseOptionDecl(circuit);
6395 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6400ParseResult FIRCircuitParser::parseTypeDecl() {
6404 auto loc = getToken().getLoc();
6406 if (getToken().isKeyword())
6407 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6408 <<
"' for type alias name";
6410 if (parseId(
id,
"expected type name") ||
6411 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6414 auto name = StringAttr::get(type.getContext(),
id);
6417 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6418 type = BaseTypeAliasType::get(name, base);
6421 <<
"type alias for non-base type " << type
6422 <<
" is currently not supported. Type alias is stripped immediately";
6424 if (!getConstants().aliasMap.insert({id, type}).second)
6425 return emitError(loc) <<
"type alias `" << name.getValue()
6426 <<
"` is already defined";
6431ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6434 auto loc = getToken().getLoc();
6437 if (parseId(
id,
"expected an option group name") ||
6438 parseToken(FIRToken::colon,
6439 "expected ':' after option group definition") ||
6440 info.parseOptionalInfo())
6443 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6445 OptionOp::create(builder,
info.getLoc(),
id, {});
6446 auto *block =
new Block;
6447 optionOp.getBody().push_back(block);
6448 builder.setInsertionPointToEnd(block);
6450 auto baseIndent = getIndentation();
6452 while (getIndentation() == baseIndent) {
6454 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6455 if (parseId(
id,
"expected an option case ID") ||
6456 caseInfo.parseOptionalInfo())
6459 if (!cases.insert(
id).second)
6460 return emitError(loc)
6461 <<
"duplicate option case definition '" <<
id <<
"'";
6463 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6470ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6471 auto baseIndent = getIndentation();
6474 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6477 auto parseOne = [&](
Block *block) -> ParseResult {
6478 auto indent = getIndentation();
6479 StringRef id, convention;
6482 if (parseId(
id,
"expected layer name") ||
6483 parseToken(FIRToken::comma,
"expected ','") ||
6484 parseGetSpelling(convention))
6487 auto layerConvention = symbolizeLayerConvention(convention);
6488 if (!layerConvention) {
6489 emitError() <<
"unknown convention '" << convention
6490 <<
"' (did you misspell it?)";
6493 if (layerConvention == LayerConvention::Inline &&
6494 requireFeature({4, 1, 0},
"inline layers"))
6498 hw::OutputFileAttr outputDir;
6499 if (consumeIf(FIRToken::comma)) {
6500 if (getToken().getKind() == FIRToken::string) {
6501 auto text = getToken().getStringValue();
6503 return emitError() <<
"output directory must not be blank";
6504 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6505 consumeToken(FIRToken::string);
6509 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6510 info.parseOptionalInfo())
6512 auto builder = OpBuilder::atBlockEnd(block);
6514 auto layerOp = LayerOp::create(builder,
info.getLoc(),
id,
6515 {}, *layerConvention);
6516 layerOp->getRegion(0).push_back(
new Block());
6518 layerOp->setAttr(
"output_file", outputDir);
6519 layerStack.push_back({indent, layerOp});
6523 if (parseOne(circuit.getBodyBlock()))
6527 while (getIndentation() > baseIndent) {
6528 switch (getToken().getKind()) {
6529 case FIRToken::kw_declgroup:
6530 case FIRToken::kw_layer: {
6533 while (layerStack.back().first >= getIndentation())
6534 layerStack.pop_back();
6535 auto parentLayer = layerStack.back().second;
6536 if (parseOne(&parentLayer.getBody().front()))
6541 return emitError(
"expected 'layer'"), failure();
6548ParseResult FIRCircuitParser::resolveDomains(
6549 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6550 const DenseMap<Attribute, size_t> &nameToIndex,
6551 SmallVectorImpl<Attribute> &domainsByIndex) {
6553 for (
auto [attr, loc] : domainsByName) {
6554 auto domain = cast<StringAttr>(attr);
6555 auto indexItr = nameToIndex.find(domain);
6556 if (indexItr == nameToIndex.end()) {
6557 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6560 domainsByIndex.push_back(IntegerAttr::get(
6561 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6568ParseResult FIRCircuitParser::parseDomains(
6569 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6570 const DenseMap<Attribute, size_t> &nameToIndex) {
6573 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6574 parseToken(FIRToken::l_square,
"expected '['"))
6577 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6579 auto domainLoc = getToken().getLoc();
6580 if (parseId(domain,
"expected domain name"))
6582 domains.push_back({domain, domainLoc});
6592FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6593 DeferredModuleToParse &deferredModule,
6594 InnerSymFixups &fixups) {
6595 FModuleLike moduleOp = deferredModule.moduleOp;
6596 auto &body = moduleOp->getRegion(0).front();
6597 auto &portLocs = deferredModule.portLocs;
6601 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6604 deferredModule.lexerCursor.restore(moduleBodyLexer);
6606 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6611 auto portList = moduleOp.getPorts();
6612 auto portArgs = body.getArguments();
6613 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6614 PortInfo &port = std::get<0>(tuple);
6615 llvm::SMLoc loc = std::get<1>(tuple);
6616 BlockArgument portArg = std::get<2>(tuple);
6618 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6622 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6625 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6638ParseResult FIRCircuitParser::parseCircuit(
6639 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6640 mlir::TimingScope &ts) {
6642 auto indent = getIndentation();
6643 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6645 if (!indent.has_value())
6646 return emitError(
"'FIRRTL' must be first token on its line");
6647 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6648 parseVersionLit(
"expected version literal"))
6650 indent = getIndentation();
6652 if (!indent.has_value())
6653 return emitError(
"'circuit' must be first token on its line");
6654 unsigned circuitIndent = *indent;
6658 SMLoc inlineAnnotationsLoc;
6659 StringRef inlineAnnotations;
6662 if (parseToken(FIRToken::kw_circuit,
6663 "expected a top-level 'circuit' definition") ||
6664 parseId(name,
"expected circuit name") ||
6665 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6666 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6667 info.parseOptionalInfo())
6671 OpBuilder b(mlirModule.getBodyRegion());
6672 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6675 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6681 SmallVector<Attribute> annos;
6682 if (!inlineAnnotations.empty())
6683 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6687 for (
auto *annotationsBuf : annotationsBufs)
6688 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6692 parseAnnotationTimer.stop();
6700 auto parseTimer = ts.nest(
"Parse modules");
6701 deferredModules.reserve(16);
6705 switch (getToken().getKind()) {
6713 case FIRToken::error:
6717 emitError(
"unexpected token in circuit");
6720 case FIRToken::kw_class:
6721 case FIRToken::kw_declgroup:
6722 case FIRToken::kw_domain:
6723 case FIRToken::kw_extclass:
6724 case FIRToken::kw_extmodule:
6725 case FIRToken::kw_intmodule:
6726 case FIRToken::kw_layer:
6727 case FIRToken::kw_formal:
6728 case FIRToken::kw_module:
6729 case FIRToken::kw_option:
6730 case FIRToken::kw_public:
6731 case FIRToken::kw_simulation:
6732 case FIRToken::kw_type: {
6733 auto indent = getIndentation();
6734 if (!indent.has_value())
6735 return emitError(
"'module' must be first token on its line"), failure();
6736 unsigned definitionIndent = *indent;
6738 if (definitionIndent <= circuitIndent)
6739 return emitError(
"module should be indented more"), failure();
6741 if (parseToplevelDefinition(circuit, definitionIndent))
6755 (void)getLexer().translateLocation(
info.getFIRLoc());
6761 DenseMap<Attribute, Location> nameToOrigLoc;
6764 auto symbol = dyn_cast<mlir::SymbolOpInterface>(&op);
6768 auto nameAttr = symbol.getNameAttr();
6771 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6774 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6775 .attachNote(it.first->second)
6776 .append(
"see existing symbol definition here");
6782 SymbolTable circuitSymTbl(circuit);
6784 moduleFixups.resize(deferredModules.size());
6789 for (
auto &d : deferredModules)
6790 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6793 auto anyFailed = mlir::failableParallelForEachN(
6794 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6795 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6796 moduleFixups[index]))
6800 if (failed(anyFailed))
6805 for (
auto &fixups : moduleFixups) {
6806 if (failed(fixups.resolve(innerSymbolNamespaces)))
6812 auto parseLayerName = [&](StringRef name) -> Attribute {
6814 auto [head, rest] = name.split(
".");
6815 SmallVector<FlatSymbolRefAttr> nestedRefs;
6816 while (!rest.empty()) {
6818 std::tie(next, rest) = rest.split(
".");
6819 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6821 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6824 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6825 SmallVector<Attribute> attrArray;
6827 for (
const auto &str : strArray)
6828 attrArray.push_back(getAttr(str));
6829 if (attrArray.empty())
6831 return ArrayAttr::get(
context, attrArray);
6834 if (
auto enableLayers =
6835 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6836 circuit.setEnableLayersAttr(enableLayers);
6837 if (
auto disableLayers =
6838 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6839 circuit.setDisableLayersAttr(disableLayers);
6841 auto getStrAttr = [&](StringRef str) -> Attribute {
6842 return StringAttr::get(getContext(), str);
6845 if (
auto selectInstChoice =
6846 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6847 circuit.setSelectInstChoiceAttr(selectInstChoice);
6849 circuit.setDefaultLayerSpecialization(
6850 getConstants().options.defaultLayerSpecialization);
6863 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6864 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6865 unsigned fileID = 1;
6867 annotationsBufs.push_back(
6868 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6870 context->loadDialect<CHIRRTLDialect>();
6871 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6875 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6878 SharedParserConstants state(
context, options);
6881 .parseCircuit(annotationsBufs, ts))
6886 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6887 if (failed(verify(*module)))
6894 static mlir::TranslateToMLIRRegistration fromFIR(
6895 "import-firrtl",
"import .fir",
6896 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6897 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