26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Diagnostics.h"
29#include "mlir/IR/ImplicitLocOpBuilder.h"
30#include "mlir/IR/PatternMatch.h"
31#include "mlir/IR/Threading.h"
32#include "mlir/IR/Verifier.h"
33#include "mlir/Support/Timing.h"
34#include "mlir/Tools/mlir-translate/Translation.h"
35#include "llvm/ADT/PointerEmbeddedInt.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallPtrSet.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/StringSet.h"
40#include "llvm/ADT/StringSwitch.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/JSON.h"
43#include "llvm/Support/SourceMgr.h"
44#include "llvm/Support/raw_ostream.h"
49using namespace firrtl;
50using namespace chirrtl;
54using mlir::LocationAttr;
67struct SharedParserConstants {
69 : context(context), options(options),
70 emptyArrayAttr(ArrayAttr::
get(context, {})),
71 loIdentifier(StringAttr::get(context,
"lo")),
72 hiIdentifier(StringAttr::get(context,
"hi")),
73 amountIdentifier(StringAttr::get(context,
"amount")),
75 hw::InnerRefAttr::get(StringAttr::get(context,
"module"),
76 StringAttr::get(context,
"placeholder"))) {}
79 MLIRContext *
const context;
85 llvm::StringMap<FIRRTLType> aliasMap;
88 llvm::DenseMap<StringRef, ClassLike> classMap;
91 const ArrayAttr emptyArrayAttr;
94 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
97 const hw::InnerRefAttr placeholderInnerRef;
100 SharedParserConstants(
const SharedParserConstants &) =
delete;
101 void operator=(
const SharedParserConstants &) =
delete;
114 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
116 : version(version), constants(constants), lexer(lexer),
117 locatorFilenameCache(constants.loIdentifier ) {
121 SharedParserConstants &getConstants()
const {
return constants; }
122 MLIRContext *getContext()
const {
return constants.context; }
124 FIRLexer &getLexer() {
return lexer; }
127 std::optional<unsigned> getIndentation()
const {
132 const FIRToken &getToken()
const {
return lexer.getToken(); }
133 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
140 InFlightDiagnostic emitError(
const Twine &message = {}) {
141 return emitError(getToken().
getLoc(), message);
143 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
146 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
147 return emitWarning(getToken().
getLoc(), message);
150 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
160 Location translateLocation(llvm::SMLoc loc) {
161 return lexer.translateLocation(loc);
166 ParseResult parseOptionalInfoLocator(LocationAttr &result);
170 ParseResult parseOptionalName(StringAttr &name);
176 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
177 return requireFeature(minimum, feature, getToken().
getLoc());
180 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
181 if (version < minimum)
182 return emitError(loc)
183 << feature <<
" are a FIRRTL " << minimum
184 <<
"+ feature, but the specified FIRRTL version was " << version;
188 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
189 return removedFeature(removedVersion, feature, getToken().
getLoc());
192 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
194 if (version >= removedVersion)
195 return emitError(loc)
196 << feature <<
" were removed in FIRRTL " << removedVersion
197 <<
", but the specified FIRRTL version was " << version;
207 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
216 if (getToken().isNot(kind))
226 FIRToken consumedToken = getToken();
227 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
228 "shouldn't advance past EOF or errors");
230 return consumedToken;
239 FIRToken consumedToken = getToken();
240 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
242 return consumedToken;
247 ParseResult parseGetSpelling(StringRef &spelling) {
248 spelling = getTokenSpelling();
254 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
259 const std::function<ParseResult()> &parseElement);
266 ParseResult parseIntLit(APInt &result,
const Twine &message);
267 ParseResult parseIntLit(int64_t &result,
const Twine &message);
268 ParseResult parseIntLit(int32_t &result,
const Twine &message);
271 ParseResult parseVersionLit(
const Twine &message);
274 template <
typename T>
275 ParseResult parseOptionalWidth(T &result);
278 ParseResult parseId(StringRef &result,
const Twine &message);
279 ParseResult parseId(StringAttr &result,
const Twine &message);
280 ParseResult parseFieldId(StringRef &result,
const Twine &message);
281 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
282 const Twine &message);
283 ParseResult parseEnumType(
FIRRTLType &result);
284 ParseResult parseListType(
FIRRTLType &result);
287 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
289 ParseResult parseRUW(RUWBehavior &result);
290 ParseResult parseOptionalRUW(RUWBehavior &result);
292 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
293 SMLoc &resultLoc,
bool allowAggregates =
false);
294 ParseResult parseParameterValue(Attribute &resultValue,
295 bool allowAggregates =
false);
301 FIRParser(
const FIRParser &) =
delete;
302 void operator=(
const FIRParser &) =
delete;
306 SharedParserConstants &constants;
310 StringAttr locatorFilenameCache;
312 FileLineColLoc fileLineColLocCache;
321InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
322 auto diag = mlir::emitError(translateLocation(loc), message);
326 if (getToken().is(FIRToken::error))
331InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
332 return mlir::emitWarning(translateLocation(loc), message);
342 const Twine &message) {
343 if (consumeIf(expectedToken))
345 return emitError(message);
352 const std::function<ParseResult()> &parseElement) {
353 if (consumeIf(rightToken))
359 while (consumeIf(FIRToken::comma)) {
364 if (parseToken(rightToken,
"expected ','"))
396 if (failed(
parser->parseOptionalInfoLocator(loc)))
400 switch (
parser->constants.options.infoLocatorHandling) {
401 case ILH::IgnoreInfo:
402 assert(0 &&
"Should not return info locations if ignoring");
404 case ILH::PreferInfo:
408 infoLoc = FusedLoc::get(loc.getContext(),
409 {loc, parser->translateLocation(firLoc)});
436ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
437 if (getToken().isNot(FIRToken::fileinfo))
440 auto loc = getToken().getLoc();
442 auto spelling = getTokenSpelling();
443 consumeToken(FIRToken::fileinfo);
447 constants.options.infoLocatorHandling ==
448 FIRParserOptions::InfoLocHandling::IgnoreInfo,
449 locatorFilenameCache, fileLineColLocCache, getContext());
452 if (!locationPair.first) {
453 mlir::emitWarning(translateLocation(loc),
454 "ignoring unknown @ info record format");
460 if (locationPair.first && constants.options.infoLocatorHandling ==
461 FIRParserOptions::InfoLocHandling::IgnoreInfo)
465 result = *locationPair.second;
473ParseResult FIRParser::parseOptionalName(StringAttr &name) {
475 if (getToken().isNot(FIRToken::colon)) {
476 name = StringAttr::get(getContext(),
"");
480 consumeToken(FIRToken::colon);
482 if (parseId(nameRef,
"expected result name"))
485 name = StringAttr::get(getContext(), nameRef);
496ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
498 if (getToken().isNot(FIRToken::inlineannotation))
501 loc = getToken().getLoc();
503 result = getTokenSpelling().drop_front(2).drop_back(1);
504 consumeToken(FIRToken::inlineannotation);
522ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
523 auto spelling = getTokenSpelling();
524 bool isNegative =
false;
525 switch (getToken().getKind()) {
526 case FIRToken::signed_integer:
527 isNegative = spelling[0] ==
'-';
528 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
529 spelling = spelling.drop_front();
531 case FIRToken::integer:
532 if (spelling.getAsInteger(10, result))
533 return emitError(message), failure();
537 if (result.isNegative())
538 result = result.zext(result.getBitWidth() + 1);
547 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
548 result = result.trunc(32);
552 case FIRToken::radix_specified_integer: {
553 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
555 if (spelling[0] ==
'-') {
557 spelling = spelling.drop_front();
559 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
564 spelling = spelling.drop_front(2);
565 if (spelling.getAsInteger(base, result))
566 return emitError(
"invalid character in integer literal"), failure();
567 if (result.isNegative())
568 result = result.zext(result.getBitWidth() + 1);
574 case FIRToken::string: {
577 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
580 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
581 spelling = spelling.drop_back().drop_front();
585 switch (spelling.empty() ?
' ' : spelling.front()) {
596 return emitError(
"expected base specifier (h/o/b) in integer literal"),
599 spelling = spelling.drop_front();
602 bool isNegative =
false;
603 if (!spelling.empty() && spelling.front() ==
'+')
604 spelling = spelling.drop_front();
605 else if (!spelling.empty() && spelling.front() ==
'-') {
607 spelling = spelling.drop_front();
611 if (spelling.empty())
612 return emitError(
"expected digits in integer literal"), failure();
614 if (spelling.getAsInteger(base, result))
615 return emitError(
"invalid character in integer literal"), failure();
620 if (result.isNegative())
621 result = result.zext(result.getBitWidth() + 1);
626 consumeToken(FIRToken::string);
631 return emitError(
"expected integer literal"), failure();
635ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
637 auto loc = getToken().getLoc();
638 if (parseIntLit(value, message))
641 result = (int64_t)value.getLimitedValue(INT64_MAX);
643 return emitError(loc,
"value is too big to handle"), failure();
647ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
649 auto loc = getToken().getLoc();
650 if (parseIntLit(value, message))
653 result = (int32_t)value.getLimitedValue(INT32_MAX);
655 return emitError(loc,
"value is too big to handle"), failure();
661ParseResult FIRParser::parseVersionLit(
const Twine &message) {
662 auto spelling = getTokenSpelling();
663 if (getToken().getKind() != FIRToken::version)
664 return emitError(message), failure();
666 auto [a, d] = spelling.split(
".");
667 auto [b, c] = d.split(
".");
668 APInt aInt, bInt, cInt;
669 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
670 c.getAsInteger(10, cInt))
671 return emitError(
"failed to parse version string"), failure();
672 version.major = aInt.getLimitedValue(UINT32_MAX);
673 version.minor = bInt.getLimitedValue(UINT32_MAX);
674 version.patch = cInt.getLimitedValue(UINT32_MAX);
675 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
676 return emitError(
"integers out of range"), failure();
680 consumeToken(FIRToken::version);
688ParseResult FIRParser::parseOptionalWidth(T &result) {
689 if (!consumeIf(FIRToken::less))
690 return result = -1, success();
693 auto widthLoc = getToken().getLoc();
694 if (parseIntLit(result,
"expected width") ||
695 parseToken(FIRToken::greater,
"expected >"))
699 return emitError(widthLoc,
"invalid width specifier"), failure();
708ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
709 switch (getToken().getKind()) {
711 case FIRToken::identifier:
712 case FIRToken::literal_identifier:
714#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
715#include "FIRTokenKinds.def"
720 if (getToken().getKind() == FIRToken::literal_identifier)
721 result = getTokenSpelling().drop_front().drop_back();
723 result = getTokenSpelling();
733ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
735 if (parseId(name, message))
738 result = StringAttr::get(getContext(), name);
747ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
749 result = getTokenSpelling();
750 if (consumeIf(FIRToken::integer))
756 if (parseId(result, message))
768ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
769 const Twine &message) {
771 StringRef tmp = getTokenSpelling();
773 if (consumeIf(FIRToken::integer)) {
774 result.push_back(tmp);
778 if (consumeIf(FIRToken::floatingpoint)) {
782 auto [a, b] = tmp.split(
".");
788 if (consumeIf(FIRToken::version)) {
790 auto [a, d] = tmp.split(
".");
791 auto [b, c] = d.split(
".");
799 if (parseId(tmp, message))
801 result.push_back(tmp);
807ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
808 if (parseToken(FIRToken::l_brace_bar,
809 "expected leading '{|' in enumeration type"))
811 SmallVector<StringAttr> names;
812 SmallVector<APInt> values;
813 SmallVector<FIRRTLBaseType> types;
814 SmallVector<SMLoc> locs;
815 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
816 auto fieldLoc = getToken().getLoc();
817 locs.push_back(fieldLoc);
821 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
823 auto name = StringAttr::get(getContext(), nameStr);
824 names.push_back(name);
830 if (consumeIf(FIRToken::equal)) {
831 if (parseIntLit(value,
"expected integer value for enumeration tag"))
833 if (value.isNegative())
834 return emitError(fieldLoc,
"enum tag value must be non-negative");
835 }
else if (values.empty()) {
841 auto &prev = values.back();
842 if (prev.isMaxValue())
843 value = prev.zext(prev.getBitWidth() + 1);
848 values.push_back(std::move(value));
852 if (consumeIf(FIRToken::colon)) {
854 if (
parseType(parsedType,
"expected enumeration type"))
856 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
858 return emitError(fieldLoc,
"field must be a base type");
861 type = UIntType::get(getContext(), 0);
863 types.push_back(type);
865 auto r = type.getRecursiveTypeProperties();
867 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
868 if (r.containsAnalog)
869 return emitError(fieldLoc)
870 <<
"enum field " << name <<
" contains analog";
871 if (r.hasUninferredWidth)
872 return emitError(fieldLoc)
873 <<
"enum field " << name <<
" has uninferred width";
874 if (r.hasUninferredReset)
875 return emitError(fieldLoc)
876 <<
"enum field " << name <<
" has uninferred reset";
882 SmallPtrSet<StringAttr, 4> nameSet;
883 for (
auto [name, loc] :
llvm::zip(names, locs))
884 if (!nameSet.insert(name).second)
885 return emitError(loc,
886 "duplicate variant name in enum: " + name.getValue());
889 unsigned bitwidth = 0;
890 for (
auto &value : values)
891 bitwidth = std::max(bitwidth, value.getActiveBits());
893 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
897 SmallPtrSet<IntegerAttr, 4> valueSet;
898 SmallVector<FEnumType::EnumElement, 4> elements;
899 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
900 auto tagValue = value.zextOrTrunc(bitwidth);
901 auto attr = IntegerAttr::get(tagType, tagValue);
903 if (!valueSet.insert(attr).second)
904 return emitError(loc,
"duplicate variant value in enum: ") << attr;
905 elements.push_back({name, attr, type});
908 llvm::sort(elements);
909 result = FEnumType::get(getContext(), elements);
913ParseResult FIRParser::parsePropertyType(
PropertyType &result,
914 const Twine &message) {
918 auto prop = type_dyn_cast<PropertyType>(type);
920 return emitError(
"expected property type");
926ParseResult FIRParser::parseListType(
FIRRTLType &result) {
927 consumeToken(FIRToken::kw_List);
930 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
931 parsePropertyType(
elementType,
"expected List element type") ||
932 parseToken(FIRToken::greater,
"expected '>' in List type"))
957ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
958 switch (getToken().getKind()) {
960 return emitError(message), failure();
962 case FIRToken::kw_Clock:
963 consumeToken(FIRToken::kw_Clock);
964 result = ClockType::get(getContext());
967 case FIRToken::kw_Inst: {
971 consumeToken(FIRToken::kw_Inst);
972 if (parseToken(FIRToken::less,
"expected < in Inst type"))
975 auto loc = getToken().getLoc();
977 if (parseId(
id,
"expected class name in Inst type"))
981 const auto &classMap = getConstants().classMap;
982 auto lookup = classMap.find(
id);
983 if (lookup == classMap.end())
984 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
986 auto classOp = lookup->second;
988 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
991 result = classOp.getInstanceType();
995 case FIRToken::kw_AnyRef: {
999 consumeToken(FIRToken::kw_AnyRef);
1000 result = AnyRefType::get(getContext());
1004 case FIRToken::kw_Reset:
1005 consumeToken(FIRToken::kw_Reset);
1006 result = ResetType::get(getContext());
1009 case FIRToken::kw_AsyncReset:
1010 consumeToken(FIRToken::kw_AsyncReset);
1011 result = AsyncResetType::get(getContext());
1014 case FIRToken::kw_UInt:
1015 case FIRToken::kw_SInt:
1016 case FIRToken::kw_Analog: {
1017 auto kind = getToken().getKind();
1022 if (parseOptionalWidth(width))
1025 if (kind == FIRToken::kw_SInt)
1026 result = SIntType::get(getContext(), width);
1027 else if (kind == FIRToken::kw_UInt)
1028 result = UIntType::get(getContext(), width);
1030 assert(kind == FIRToken::kw_Analog);
1031 result = AnalogType::get(getContext(), width);
1036 case FIRToken::kw_Probe:
1037 case FIRToken::kw_RWProbe: {
1038 auto kind = getToken().getKind();
1039 auto loc = getToken().getLoc();
1044 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1045 parseType(type,
"expected probe data type"))
1048 SmallVector<StringRef> layers;
1049 if (consumeIf(FIRToken::comma)) {
1050 if (requireFeature({4, 0, 0},
"colored probes"))
1055 loc = getToken().getLoc();
1056 if (parseId(layer,
"expected layer name"))
1058 layers.push_back(layer);
1059 }
while (consumeIf(FIRToken::period));
1062 if (!consumeIf(FIRToken::greater))
1063 return emitError(loc,
"expected '>' to end reference type");
1065 bool forceable = kind == FIRToken::kw_RWProbe;
1067 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1069 return emitError(loc,
"invalid probe inner type, must be base-type");
1072 return emitError(loc,
"probe inner type must be passive");
1074 if (forceable &&
innerType.containsConst())
1075 return emitError(loc,
"rwprobe cannot contain const");
1077 SymbolRefAttr layer;
1078 if (!layers.empty()) {
1080 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1081 return FlatSymbolRefAttr::get(getContext(), a);
1083 layer = SymbolRefAttr::get(getContext(), layers.front(),
1084 llvm::to_vector(nestedLayers));
1087 result = RefType::get(innerType, forceable, layer);
1091 case FIRToken::l_brace: {
1092 consumeToken(FIRToken::l_brace);
1094 SmallVector<OpenBundleType::BundleElement, 4> elements;
1095 SmallPtrSet<StringAttr, 4> nameSet;
1096 bool bundleCompatible =
true;
1097 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1098 bool isFlipped = consumeIf(FIRToken::kw_flip);
1100 auto loc = getToken().getLoc();
1101 StringRef fieldNameStr;
1102 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1103 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1105 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1108 if (!nameSet.insert(fieldName).second)
1109 return emitError(loc,
"duplicate field name in bundle: " +
1110 fieldName.getValue());
1113 if (
parseType(type,
"expected bundle field type"))
1116 elements.push_back({fieldName, isFlipped, type});
1117 bundleCompatible &= isa<BundleType::ElementType>(type);
1124 if (bundleCompatible) {
1125 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1126 return BundleType::BundleElement{
1127 element.name, element.isFlip,
1128 cast<BundleType::ElementType>(element.type)};
1130 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1132 result = OpenBundleType::get(getContext(), elements);
1136 case FIRToken::l_brace_bar: {
1137 if (parseEnumType(result))
1142 case FIRToken::identifier: {
1144 auto loc = getToken().getLoc();
1145 if (parseId(
id,
"expected a type alias name"))
1147 auto it = constants.aliasMap.find(
id);
1148 if (it == constants.aliasMap.end()) {
1149 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1152 result = it->second;
1156 case FIRToken::kw_const: {
1157 consumeToken(FIRToken::kw_const);
1158 auto nextToken = getToken();
1159 auto loc = nextToken.getLoc();
1162 if (nextToken.is(FIRToken::kw_const))
1163 return emitError(loc,
"'const' can only be specified once on a type");
1168 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1170 return emitError(loc,
"only hardware types can be 'const'");
1172 result = baseType.getConstType(
true);
1176 case FIRToken::kw_String:
1177 if (requireFeature({3, 1, 0},
"Strings"))
1179 consumeToken(FIRToken::kw_String);
1180 result = StringType::get(getContext());
1182 case FIRToken::kw_Integer:
1183 if (requireFeature({3, 1, 0},
"Integers"))
1185 consumeToken(FIRToken::kw_Integer);
1186 result = FIntegerType::get(getContext());
1188 case FIRToken::kw_Bool:
1191 consumeToken(FIRToken::kw_Bool);
1192 result = BoolType::get(getContext());
1194 case FIRToken::kw_Double:
1197 consumeToken(FIRToken::kw_Double);
1198 result = DoubleType::get(getContext());
1200 case FIRToken::kw_Path:
1203 consumeToken(FIRToken::kw_Path);
1204 result = PathType::get(getContext());
1206 case FIRToken::kw_List:
1207 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1213 while (consumeIf(FIRToken::l_square)) {
1214 auto sizeLoc = getToken().getLoc();
1216 if (parseIntLit(size,
"expected width") ||
1217 parseToken(FIRToken::r_square,
"expected ]"))
1221 return emitError(sizeLoc,
"invalid size specifier"), failure();
1223 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1225 result = FVectorType::get(baseType, size);
1227 result = OpenVectorType::get(result, size);
1234ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1235 switch (getToken().getKind()) {
1237 case FIRToken::kw_old:
1238 result = RUWBehavior::Old;
1239 consumeToken(FIRToken::kw_old);
1241 case FIRToken::kw_new:
1242 result = RUWBehavior::New;
1243 consumeToken(FIRToken::kw_new);
1245 case FIRToken::kw_undefined:
1246 result = RUWBehavior::Undefined;
1247 consumeToken(FIRToken::kw_undefined);
1257ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1258 switch (getToken().getKind()) {
1262 case FIRToken::kw_old:
1263 result = RUWBehavior::Old;
1264 consumeToken(FIRToken::kw_old);
1266 case FIRToken::kw_new:
1267 result = RUWBehavior::New;
1268 consumeToken(FIRToken::kw_new);
1270 case FIRToken::kw_undefined:
1271 result = RUWBehavior::Undefined;
1272 consumeToken(FIRToken::kw_undefined);
1280ParseResult FIRParser::parseParameter(StringAttr &resultName,
1281 Attribute &resultValue, SMLoc &resultLoc,
1282 bool allowAggregates) {
1283 auto loc = getToken().getLoc();
1287 if (parseId(name,
"expected parameter name") ||
1288 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1293 if (parseParameterValue(value, allowAggregates))
1296 resultName = StringAttr::get(getContext(), name);
1297 resultValue = value;
1308ParseResult FIRParser::parseParameterValue(Attribute &value,
1309 bool allowAggregates) {
1310 mlir::Builder builder(getContext());
1311 switch (getToken().getKind()) {
1314 case FIRToken::integer:
1315 case FIRToken::signed_integer: {
1317 if (parseIntLit(result,
"invalid integer parameter"))
1323 if (result.getBitWidth() < 32)
1324 result = result.sext(32);
1326 value = builder.getIntegerAttr(
1327 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1333 case FIRToken::string: {
1335 value = builder.getStringAttr(getToken().getStringValue());
1336 consumeToken(FIRToken::string);
1341 case FIRToken::verbatim_string: {
1343 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1344 value = hw::ParamVerbatimAttr::get(text);
1345 consumeToken(FIRToken::verbatim_string);
1350 case FIRToken::floatingpoint: {
1352 if (!llvm::to_float(getTokenSpelling(), v))
1353 return emitError(
"invalid float parameter syntax"), failure();
1355 value = builder.getF64FloatAttr(v);
1356 consumeToken(FIRToken::floatingpoint);
1361 case FIRToken::l_square: {
1362 if (!allowAggregates)
1363 return emitError(
"expected non-aggregate parameter value");
1366 SmallVector<Attribute> elements;
1367 auto parseElement = [&] {
1368 return parseParameterValue(elements.emplace_back(),
1371 if (parseListUntil(FIRToken::r_square, parseElement))
1374 value = builder.getArrayAttr(elements);
1379 case FIRToken::l_brace: {
1380 if (!allowAggregates)
1381 return emitError(
"expected non-aggregate parameter value");
1384 NamedAttrList fields;
1385 auto parseField = [&]() -> ParseResult {
1386 StringAttr fieldName;
1387 Attribute fieldValue;
1389 if (parseParameter(fieldName, fieldValue, fieldLoc,
1392 if (fields.set(fieldName, fieldValue))
1393 return emitError(fieldLoc)
1394 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1397 if (parseListUntil(FIRToken::r_brace, parseField))
1400 value = fields.getDictionary(getContext());
1405 return emitError(
"expected parameter value");
1420 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1428struct UnbundledValueRestorer {
1430 size_t startingSize;
1432 startingSize = list.size();
1434 ~UnbundledValueRestorer() { list.resize(startingSize); }
1443struct FIRModuleContext :
public FIRParser {
1444 explicit FIRModuleContext(Block *topLevelBlock,
1445 SharedParserConstants &constants,
FIRLexer &lexer,
1447 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1450 template <
typename OpTy = ConstantOp,
typename... Args>
1451 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1452 Type type, Args &&...args) {
1453 auto &result = constantCache[{attr, type}];
1459 OpBuilder::InsertPoint savedIP;
1462 if (builder.getInsertionBlock() != topLevelBlock) {
1463 savedIP = builder.saveInsertionPoint();
1464 auto *block = builder.getInsertionBlock();
1466 auto *op = block->getParentOp();
1467 if (!op || !op->getBlock()) {
1469 builder.setInsertionPointToEnd(topLevelBlock);
1472 if (op->getBlock() == topLevelBlock) {
1473 builder.setInsertionPoint(op);
1476 block = op->getBlock();
1480 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1482 if (savedIP.isSet())
1483 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1494 Value &getCachedSubaccess(Value value,
unsigned index) {
1495 auto &result = subaccessCache[{value, index}];
1498 auto it = scopeMap.find(value.getParentBlock());
1499 if (it != scopeMap.end())
1500 it->second->scopedSubaccesses.push_back({result, index});
1510 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1511 bool insertNameIntoGlobalScope =
false);
1512 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1513 bool insertNameIntoGlobalScope =
false) {
1515 insertNameIntoGlobalScope);
1519 void removeSymbolEntry(StringRef name);
1523 SMLoc loc,
bool fatal =
true);
1528 StringRef field, SMLoc loc);
1536 assert(index < unbundledValues.size());
1537 return unbundledValues[index];
1547 struct ContextScope {
1548 friend struct FIRModuleContext;
1549 ContextScope(FIRModuleContext &moduleContext, Block *block)
1550 : moduleContext(moduleContext), block(block),
1551 previousScope(moduleContext.currentScope) {
1552 moduleContext.currentScope =
this;
1553 moduleContext.scopeMap[block] =
this;
1558 for (
auto *entryPtr : scopedDecls)
1559 entryPtr->second.first = SMLoc();
1562 for (
auto subaccess : scopedSubaccesses)
1563 moduleContext.subaccessCache.erase(subaccess);
1565 moduleContext.scopeMap.erase(block);
1567 moduleContext.currentScope = previousScope;
1571 void operator=(
const ContextScope &) =
delete;
1572 ContextScope(
const ContextScope &) =
delete;
1574 FIRModuleContext &moduleContext;
1576 ContextScope *previousScope;
1577 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1578 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1583 Block *topLevelBlock;
1589 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1601 DenseMap<Block *, ContextScope *> scopeMap;
1606 ContextScope *currentScope =
nullptr;
1612void FIRModuleContext::removeSymbolEntry(StringRef name) {
1613 symbolTable.erase(name);
1622ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1624 bool insertNameIntoGlobalScope) {
1627 auto [entryIt, inserted] =
1632 if (entryIt->second.first.isValid()) {
1634 emitError(loc,
"redefinition of name '" + name +
"' ")
1635 .attachNote(translateLocation(entryIt->second.first))
1636 <<
"previous definition here.";
1639 emitError(loc,
"redefinition of name '" + name +
"' ")
1640 <<
"- FIRRTL has flat namespace and requires all "
1641 <<
"declarations in a module to have unique names.";
1648 entryIt->second = {loc, entry};
1649 if (currentScope && !insertNameIntoGlobalScope)
1650 currentScope->scopedDecls.push_back(&*entryIt);
1657 StringRef name, SMLoc loc) {
1658 auto &entry = symbolTable[name];
1659 if (!entry.first.isValid())
1660 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1661 result = entry.second;
1662 assert(result &&
"name in symbol table without definition");
1666ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1668 SMLoc loc,
bool fatal) {
1669 if (!isa<Value>(entry)) {
1671 emitError(loc,
"bundle value should only be used from subfield");
1674 result = cast<Value>(entry);
1678ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1680 StringRef fieldName,
1682 if (!isa<UnbundledID>(entry)) {
1683 emitError(loc,
"value should not be used from subfield");
1687 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1689 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1690 assert(unbundledId < unbundledValues.size());
1692 for (
auto elt : ubEntry) {
1693 if (elt.first == fieldAttr) {
1694 result = elt.second;
1699 emitError(loc,
"use of invalid field name '")
1700 << fieldName <<
"' on bundle value";
1726struct LazyLocationListener :
public OpBuilder::Listener {
1727 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1728 assert(builder.getListener() ==
nullptr);
1729 builder.setListener(
this);
1732 ~LazyLocationListener() {
1733 assert(subOps.empty() &&
"didn't process parsed operations");
1734 assert(builder.getListener() ==
this);
1735 builder.setListener(
nullptr);
1738 void startStatement() {
1739 assert(!isActive &&
"Already processing a statement");
1745 void endStatement(FIRParser &parser) {
1746 assert(isActive &&
"Not parsing a statement");
1750 for (
auto opAndSMLoc : subOps) {
1754 switch (parser.getConstants().options.infoLocatorHandling) {
1755 case ILH::IgnoreInfo:
1757 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1759 case ILH::PreferInfo:
1760 opAndSMLoc.first->setLoc(infoLoc);
1762 case ILH::FusedInfo:
1763 opAndSMLoc.first->setLoc(FusedLoc::get(
1764 infoLoc.getContext(),
1765 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1772 for (
auto opAndSMLoc : subOps)
1773 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1778 infoLoc = LocationAttr();
1779 currentSMLoc = SMLoc();
1784 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1787 void setInfoLoc(LocationAttr loc) {
1788 assert(!infoLoc &&
"Info location multiply specified");
1794 void notifyOperationInserted(Operation *op,
1795 mlir::IRRewriter::InsertPoint)
override {
1796 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1797 assert(isActive &&
"Not parsing a statement");
1798 subOps.push_back({op, currentSMLoc});
1803 bool isActive =
false;
1811 LocationAttr infoLoc;
1818 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1820 void operator=(
const LazyLocationListener &) =
delete;
1821 LazyLocationListener(
const LazyLocationListener &) =
delete;
1829struct InnerSymFixups {
1832 fixups.push_back({user, target});
1841 hw::InnerRefUserOpInterface innerRefUser;
1844 SmallVector<Fixup, 0> fixups;
1850 for (
auto &f : fixups) {
1853 return isnc.get(module);
1855 assert(ref &&
"unable to resolve inner symbol target");
1859 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1860 .Case<RWProbeOp>([ref](RWProbeOp op) {
1861 op.setTargetAttr(ref);
1864 .Default([](
auto *op) {
1865 return op->emitError(
"unknown inner-ref user requiring fixup");
1876struct FIRStmtParser :
public FIRParser {
1877 explicit FIRStmtParser(Block &blockToInsertInto,
1878 FIRModuleContext &moduleContext,
1879 InnerSymFixups &innerSymFixups,
1880 const SymbolTable &circuitSymTbl,
FIRVersion version,
1881 SymbolRefAttr layerSym = {})
1882 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1884 builder(UnknownLoc::
get(getContext()), getContext()),
1885 locationProcessor(this->builder), moduleContext(moduleContext),
1886 innerSymFixups(innerSymFixups), layerSym(layerSym),
1887 circuitSymTbl(circuitSymTbl) {
1888 builder.setInsertionPointToEnd(&blockToInsertInto);
1891 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1892 ParseResult parseSimpleStmtBlock(
unsigned indent);
1895 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1898 void emitInvalidate(Value val,
Flow flow);
1904 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1907 ParseResult parseOptionalInfo() {
1909 if (failed(parseOptionalInfoLocator(loc)))
1911 locationProcessor.setInfoLoc(loc);
1916 ParseResult parseExpImpl(Value &result,
const Twine &message,
1917 bool isLeadingStmt);
1918 ParseResult parseExp(Value &result,
const Twine &message) {
1919 return parseExpImpl(result, message,
false);
1921 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1922 return parseExpImpl(result, message,
true);
1924 ParseResult parseEnumExp(Value &result);
1925 ParseResult parsePathExp(Value &result);
1926 ParseResult parseRefExp(Value &result,
const Twine &message);
1927 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1928 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1929 const Twine &message);
1932 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1933 ParseResult parseIntrinsicStmt() {
1935 return parseIntrinsic(unused,
true);
1937 ParseResult parseIntrinsicExp(Value &result) {
1938 return parseIntrinsic(result,
false);
1940 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1942 template <
typename subop>
1943 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1944 ParseResult parseOptionalExpPostscript(Value &result,
1945 bool allowDynamic =
true);
1946 ParseResult parsePostFixFieldId(Value &result);
1947 ParseResult parsePostFixIntSubscript(Value &result);
1948 ParseResult parsePostFixDynamicSubscript(Value &result);
1949 ParseResult parseIntegerLiteralExp(Value &result);
1950 ParseResult parseListExp(Value &result);
1951 ParseResult parseListConcatExp(Value &result);
1952 ParseResult parseCatExp(Value &result);
1954 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1955 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1957 auto loc = getToken().getLoc();
1958 locationProcessor.setLoc(loc);
1961 auto vals = std::array<Value, M>();
1962 auto ints = std::array<int64_t, N>();
1966 for (
size_t i = 0; i < M; ++i) {
1968 if (parseToken(FIRToken::comma,
"expected ','"))
1970 if (parseExp(vals[i],
"expected expression in primitive operand"))
1976 for (
size_t i = 0; i < N; ++i) {
1978 if (parseToken(FIRToken::comma,
"expected ','"))
1980 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
1985 if (parseToken(FIRToken::r_paren,
"expected ')'"))
1989 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
1993 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
1994 translateLocation(loc));
1999 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2000 result = op.getResult();
2004 template <
typename T,
unsigned M,
unsigned N>
2005 ParseResult parsePrimExp(Value &result) {
2006 auto ms = std::make_index_sequence<M>();
2007 auto ns = std::make_index_sequence<N>();
2008 return parsePrim<T, M, N>(ms, ns, result);
2011 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2014 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2015 SymbolRefAttr layerSym);
2016 ParseResult parseAttach();
2017 ParseResult parseMemPort(MemDirAttr direction);
2022 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
2023 ArrayRef<Value> specOperands,
2024 StringAttr &formatStringResult,
2025 SmallVectorImpl<Value> &operands);
2026 ParseResult parsePrintf();
2027 ParseResult parseFPrintf();
2028 ParseResult parseFFlush();
2029 ParseResult parseSkip();
2030 ParseResult parseStop();
2031 ParseResult parseAssert();
2032 ParseResult parseAssume();
2033 ParseResult parseCover();
2034 ParseResult parseWhen(
unsigned whenIndent);
2035 ParseResult parseMatch(
unsigned matchIndent);
2036 ParseResult parseRefDefine();
2037 ParseResult parseRefForce();
2038 ParseResult parseRefForceInitial();
2039 ParseResult parseRefRelease();
2040 ParseResult parseRefReleaseInitial();
2041 ParseResult parseRefRead(Value &result);
2042 ParseResult parseProbe(Value &result);
2043 ParseResult parsePropAssign();
2044 ParseResult parseRWProbe(Value &result);
2045 ParseResult parseLeadingExpStmt(Value lhs);
2046 ParseResult parseConnect();
2047 ParseResult parseInvalidate();
2048 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2051 ParseResult parseInstance();
2052 ParseResult parseInstanceChoice();
2053 ParseResult parseObject();
2054 ParseResult parseCombMem();
2055 ParseResult parseSeqMem();
2056 ParseResult parseMem(
unsigned memIndent);
2057 ParseResult parseNode();
2058 ParseResult parseWire();
2059 ParseResult parseRegister(
unsigned regIndent);
2060 ParseResult parseRegisterWithReset();
2061 ParseResult parseContract(
unsigned blockIndent);
2064 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2067 ImplicitLocOpBuilder builder;
2068 LazyLocationListener locationProcessor;
2071 FIRModuleContext &moduleContext;
2074 InnerSymFixups &innerSymFixups;
2078 SymbolRefAttr layerSym;
2080 const SymbolTable &circuitSymTbl;
2087void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2088 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2095 auto props = tpe.getRecursiveTypeProperties();
2096 if (props.isPassive && !props.containsAnalog) {
2097 if (flow == Flow::Source)
2099 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2110 TypeSwitch<FIRRTLType>(tpe)
2111 .Case<BundleType>([&](
auto tpe) {
2112 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2113 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2115 OpBuilder::InsertionGuard guard(builder);
2116 builder.setInsertionPointAfterValue(val);
2117 subfield = SubfieldOp::create(builder, val, i);
2119 emitInvalidate(subfield,
2120 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2123 .Case<FVectorType>([&](
auto tpe) {
2124 auto tpex = tpe.getElementType();
2125 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2126 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2128 OpBuilder::InsertionGuard guard(builder);
2129 builder.setInsertionPointAfterValue(val);
2130 subindex = SubindexOp::create(builder, tpex, val, i);
2132 emitInvalidate(subindex, flow);
2160ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2161 bool isLeadingStmt) {
2162 auto token = getToken();
2163 auto kind = token.getKind();
2165 case FIRToken::lp_integer_add:
2166 case FIRToken::lp_integer_mul:
2167 case FIRToken::lp_integer_shr:
2168 case FIRToken::lp_integer_shl:
2169 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2178#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2180 case FIRToken::lp_##SPELLING: \
2181 if (requireFeature(VERSION, FEATURE)) \
2183 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2186#include "FIRTokenKinds.def"
2188 case FIRToken::l_brace_bar:
2190 return emitError(
"unexpected enumeration as start of statement");
2191 if (parseEnumExp(result))
2194 case FIRToken::lp_read:
2196 return emitError(
"unexpected read() as start of statement");
2197 if (parseRefRead(result))
2200 case FIRToken::lp_probe:
2202 return emitError(
"unexpected probe() as start of statement");
2203 if (parseProbe(result))
2206 case FIRToken::lp_rwprobe:
2208 return emitError(
"unexpected rwprobe() as start of statement");
2209 if (parseRWProbe(result))
2213 case FIRToken::kw_UInt:
2214 case FIRToken::kw_SInt:
2215 if (parseIntegerLiteralExp(result))
2218 case FIRToken::kw_String: {
2219 if (requireFeature({3, 1, 0},
"Strings"))
2221 locationProcessor.setLoc(getToken().
getLoc());
2222 consumeToken(FIRToken::kw_String);
2224 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2225 parseGetSpelling(spelling) ||
2226 parseToken(FIRToken::string,
2227 "expected string literal in String expression") ||
2228 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2231 result = moduleContext.getCachedConstant<StringConstantOp>(
2232 builder, attr, builder.getType<StringType>(), attr);
2235 case FIRToken::kw_Integer: {
2236 if (requireFeature({3, 1, 0},
"Integers"))
2238 locationProcessor.setLoc(getToken().
getLoc());
2239 consumeToken(FIRToken::kw_Integer);
2241 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2242 parseIntLit(value,
"expected integer literal in Integer expression") ||
2243 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2245 APSInt apint(value,
false);
2246 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2247 builder, IntegerAttr::get(getContext(), apint),
2248 builder.getType<FIntegerType>(), apint);
2251 case FIRToken::kw_Bool: {
2254 locationProcessor.setLoc(getToken().
getLoc());
2255 consumeToken(FIRToken::kw_Bool);
2256 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2259 if (consumeIf(FIRToken::kw_true))
2261 else if (consumeIf(FIRToken::kw_false))
2264 return emitError(
"expected true or false in Bool expression");
2265 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2267 auto attr = builder.getBoolAttr(value);
2268 result = moduleContext.getCachedConstant<BoolConstantOp>(
2269 builder, attr, builder.getType<BoolType>(), value);
2272 case FIRToken::kw_Double: {
2275 locationProcessor.setLoc(getToken().
getLoc());
2276 consumeToken(FIRToken::kw_Double);
2277 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2279 auto spelling = getTokenSpelling();
2280 if (parseToken(FIRToken::floatingpoint,
2281 "expected floating point in Double expression") ||
2282 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2287 if (!llvm::to_float(spelling, d))
2288 return emitError(
"invalid double");
2289 auto attr = builder.getF64FloatAttr(d);
2290 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2291 builder, attr, builder.getType<DoubleType>(), attr);
2294 case FIRToken::kw_List: {
2295 if (requireFeature({4, 0, 0},
"Lists"))
2298 return emitError(
"unexpected List<>() as start of statement");
2299 if (parseListExp(result))
2304 case FIRToken::lp_list_concat: {
2306 return emitError(
"unexpected list_create() as start of statement");
2307 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2312 case FIRToken::lp_path:
2314 return emitError(
"unexpected path() as start of statement");
2319 case FIRToken::lp_intrinsic:
2320 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2321 parseIntrinsicExp(result))
2325 case FIRToken::lp_cat:
2326 if (parseCatExp(result))
2332 case FIRToken::identifier:
2333 case FIRToken::literal_identifier:
2336 auto loc = getToken().getLoc();
2338 if (parseId(name, message) ||
2339 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2343 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2346 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2351 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2352 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2353 parseOptionalInfo())
2356 locationProcessor.setLoc(loc);
2358 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2360 moduleContext.getUnbundledEntry(unbundledId);
2361 for (
auto elt : ubEntry)
2362 emitInvalidate(elt.second);
2370 StringRef fieldName;
2371 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2372 parseFieldId(fieldName,
"expected field name") ||
2373 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2381 case FIRToken::lp_shr:
2384 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2385 result = PadPrimOp::create(builder, result, 1);
2391 return parseOptionalExpPostscript(result);
2401ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2402 bool allowDynamic) {
2407 if (consumeIf(FIRToken::period)) {
2408 if (parsePostFixFieldId(result))
2415 if (consumeIf(FIRToken::l_square)) {
2416 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2417 if (parsePostFixIntSubscript(result))
2422 return emitError(
"subaccess not allowed here");
2423 if (parsePostFixDynamicSubscript(result))
2433template <
typename subop>
2435FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2437 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2443 auto baseType = cast<FIRRTLType>(base.getType());
2444 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2447 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2453 locationProcessor.setLoc(loc);
2454 OpBuilder::InsertionGuard guard(builder);
2455 builder.setInsertionPointAfterValue(base);
2456 auto op = subop::create(builder, resultType, base, indexNo);
2459 return value = op.getResult();
2466ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2467 auto loc = getToken().getLoc();
2468 SmallVector<StringRef, 3> fields;
2469 if (parseFieldIdSeq(fields,
"expected field name"))
2471 for (
auto fieldName : fields) {
2472 std::optional<unsigned> indexV;
2473 auto type = result.getType();
2474 if (
auto refTy = type_dyn_cast<RefType>(type))
2475 type = refTy.getType();
2476 if (
auto bundle = type_dyn_cast<BundleType>(type))
2477 indexV = bundle.getElementIndex(fieldName);
2478 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2479 indexV = bundle.getElementIndex(fieldName);
2480 else if (
auto klass = type_dyn_cast<ClassType>(type))
2481 indexV = klass.getElementIndex(fieldName);
2483 return emitError(loc,
"subfield requires bundle or object operand ");
2485 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2486 << result.getType();
2487 auto indexNo = *indexV;
2489 FailureOr<Value> subResult;
2490 if (type_isa<RefType>(result.getType()))
2491 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2492 else if (type_isa<ClassType>(type))
2493 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2494 else if (type_isa<BundleType>(type))
2495 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2497 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2499 if (failed(subResult))
2501 result = *subResult;
2510ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2511 auto loc = getToken().getLoc();
2513 if (parseIntLit(indexNo,
"expected index") ||
2514 parseToken(FIRToken::r_square,
"expected ']'"))
2518 return emitError(loc,
"invalid index specifier"), failure();
2520 FailureOr<Value> subResult;
2521 if (type_isa<RefType>(result.getType()))
2522 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2523 else if (type_isa<FVectorType>(result.getType()))
2524 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2526 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2528 if (failed(subResult))
2530 result = *subResult;
2538ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2539 auto loc = getToken().getLoc();
2541 if (parseExp(index,
"expected subscript index expression") ||
2542 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2546 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2548 return emitError(
"expected base type for index expression");
2549 indexType = indexType.getPassiveType();
2550 locationProcessor.setLoc(loc);
2555 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2558 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2559 translateLocation(loc));
2564 auto op = SubaccessOp::create(builder, resultType, result, index);
2565 result = op.getResult();
2571ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2572 bool isSigned = getToken().is(FIRToken::kw_SInt);
2573 auto loc = getToken().getLoc();
2579 if (parseOptionalWidth(width) ||
2580 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2581 parseIntLit(value,
"expected integer value") ||
2582 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2587 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2589 IntegerType::SignednessSemantics signedness =
2590 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2592 if (!value.isZero())
2593 return emitError(loc,
"zero bit constant must be zero");
2594 value = value.trunc(0);
2595 }
else if (width != -1) {
2597 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2599 return emitError(loc,
"initializer too wide for declared width");
2600 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2604 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2605 auto attr = builder.getIntegerAttr(attrType, value);
2607 locationProcessor.setLoc(loc);
2608 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2613ParseResult FIRStmtParser::parseListExp(Value &result) {
2614 auto loc = getToken().getLoc();
2616 if (parseListType(type))
2618 auto listType = type_cast<ListType>(type);
2621 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2624 SmallVector<Value, 3> operands;
2625 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2627 locationProcessor.setLoc(loc);
2628 if (parseExp(operand,
"expected expression in List expression"))
2632 if (!isa<AnyRefType>(elementType) ||
2633 !isa<ClassType>(operand.getType()))
2634 return emitError(loc,
"unexpected expression of type ")
2635 << operand.getType() <<
" in List expression of type "
2637 operand = ObjectAnyRefCastOp::create(builder, operand);
2640 operands.push_back(operand);
2645 locationProcessor.setLoc(loc);
2646 result = ListCreateOp::create(builder, listType, operands);
2651ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2652 consumeToken(FIRToken::lp_list_concat);
2654 auto loc = getToken().getLoc();
2656 SmallVector<Value, 3> operands;
2657 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2659 locationProcessor.setLoc(loc);
2660 if (parseExp(operand,
"expected expression in List concat expression"))
2663 if (!type_isa<ListType>(operand.getType()))
2664 return emitError(loc,
"unexpected expression of type ")
2665 << operand.getType() <<
" in List concat expression";
2668 type = type_cast<ListType>(operand.getType());
2670 if (operand.getType() != type)
2671 return emitError(loc,
"unexpected expression of type ")
2672 << operand.getType() <<
" in List concat expression of type "
2675 operands.push_back(operand);
2680 if (operands.empty())
2681 return emitError(loc,
"need at least one List to concatenate");
2683 locationProcessor.setLoc(loc);
2684 result = ListConcatOp::create(builder, type, operands);
2689ParseResult FIRStmtParser::parseCatExp(Value &result) {
2690 consumeToken(FIRToken::lp_cat);
2692 auto loc = getToken().getLoc();
2693 SmallVector<Value, 3> operands;
2694 std::optional<bool> isSigned;
2695 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2697 locationProcessor.setLoc(loc);
2698 auto operandLoc = getToken().getLoc();
2699 if (parseExp(operand,
"expected expression in cat expression"))
2701 if (!type_isa<IntType>(operand.getType())) {
2702 auto diag = emitError(loc,
"all operands must be Int type");
2703 diag.attachNote(translateLocation(operandLoc))
2704 <<
"non-integer operand is here";
2708 isSigned = type_isa<SIntType>(operand.getType());
2709 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2710 auto diag = emitError(loc,
"all operands must have same signedness");
2711 diag.attachNote(translateLocation(operandLoc))
2712 <<
"operand with different signedness is here";
2716 operands.push_back(operand);
2721 if (operands.size() != 2) {
2726 locationProcessor.setLoc(loc);
2727 result = CatPrimOp::create(builder, operands);
2748std::optional<ParseResult>
2749FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2750 switch (getToken().getKind()) {
2753 return std::nullopt;
2755 case FIRToken::period:
2756 case FIRToken::l_square:
2757 case FIRToken::kw_is:
2758 case FIRToken::less_equal:
2764 auto loc = keyword.
getLoc();
2766 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2767 return ParseResult(failure());
2773 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2776 if (!consumeIf(FIRToken::period))
2777 return ParseResult(failure());
2779 StringRef fieldName;
2780 if (parseFieldId(fieldName,
"expected field name") ||
2781 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2782 return ParseResult(failure());
2786 if (parseOptionalExpPostscript(lhs))
2787 return ParseResult(failure());
2789 return parseLeadingExpStmt(lhs);
2795ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2798 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2801 auto subIndent = getIndentation();
2802 if (!subIndent.has_value())
2803 return emitError(
"expected statement to be on its own line"), failure();
2805 if (*subIndent <= indent)
2809 if (parseSimpleStmt(*subIndent))
2814ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2815 locationProcessor.startStatement();
2816 auto result = parseSimpleStmtImpl(stmtIndent);
2817 locationProcessor.endStatement(*
this);
2839ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2840 auto kind = getToken().getKind();
2843 case FIRToken::kw_invalidate:
2844 case FIRToken::kw_connect:
2845 case FIRToken::kw_regreset:
2849 kind = FIRToken::identifier;
2856 case FIRToken::kw_attach:
2857 return parseAttach();
2858 case FIRToken::kw_infer:
2859 return parseMemPort(MemDirAttr::Infer);
2860 case FIRToken::kw_read:
2861 return parseMemPort(MemDirAttr::Read);
2862 case FIRToken::kw_write:
2863 return parseMemPort(MemDirAttr::Write);
2864 case FIRToken::kw_rdwr:
2865 return parseMemPort(MemDirAttr::ReadWrite);
2866 case FIRToken::kw_connect:
2867 return parseConnect();
2868 case FIRToken::kw_propassign:
2869 if (requireFeature({3, 1, 0},
"properties"))
2871 return parsePropAssign();
2872 case FIRToken::kw_invalidate:
2873 return parseInvalidate();
2874 case FIRToken::lp_printf:
2875 return parsePrintf();
2876 case FIRToken::lp_fprintf:
2877 return parseFPrintf();
2878 case FIRToken::lp_fflush:
2879 return parseFFlush();
2880 case FIRToken::kw_skip:
2882 case FIRToken::lp_stop:
2884 case FIRToken::lp_assert:
2885 return parseAssert();
2886 case FIRToken::lp_assume:
2887 return parseAssume();
2888 case FIRToken::lp_cover:
2889 return parseCover();
2890 case FIRToken::kw_when:
2891 return parseWhen(stmtIndent);
2892 case FIRToken::kw_match:
2893 return parseMatch(stmtIndent);
2894 case FIRToken::kw_define:
2895 return parseRefDefine();
2896 case FIRToken::lp_force:
2897 return parseRefForce();
2898 case FIRToken::lp_force_initial:
2899 return parseRefForceInitial();
2900 case FIRToken::lp_release:
2901 return parseRefRelease();
2902 case FIRToken::lp_release_initial:
2903 return parseRefReleaseInitial();
2904 case FIRToken::kw_group:
2905 if (requireFeature({3, 2, 0},
"optional groups") ||
2906 removedFeature({3, 3, 0},
"optional groups"))
2908 return parseLayerBlockOrGroup(stmtIndent);
2909 case FIRToken::kw_layerblock:
2910 if (requireFeature({3, 3, 0},
"layers"))
2912 return parseLayerBlockOrGroup(stmtIndent);
2913 case FIRToken::lp_intrinsic:
2914 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2916 return parseIntrinsicStmt();
2920 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2927 return parseLeadingExpStmt(lhs);
2931 case FIRToken::kw_inst:
2932 return parseInstance();
2933 case FIRToken::kw_instchoice:
2934 return parseInstanceChoice();
2935 case FIRToken::kw_object:
2936 return parseObject();
2937 case FIRToken::kw_cmem:
2938 return parseCombMem();
2939 case FIRToken::kw_smem:
2940 return parseSeqMem();
2941 case FIRToken::kw_mem:
2942 return parseMem(stmtIndent);
2943 case FIRToken::kw_node:
2945 case FIRToken::kw_wire:
2947 case FIRToken::kw_reg:
2948 return parseRegister(stmtIndent);
2949 case FIRToken::kw_regreset:
2950 return parseRegisterWithReset();
2951 case FIRToken::kw_contract:
2952 return parseContract(stmtIndent);
2956ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
2958 SymbolRefAttr layerSym) {
2960 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
2961 moduleContext, &blockToInsertInto);
2966 UnbundledValueRestorer x(moduleContext.unbundledValues);
2970 auto subParser = std::make_unique<FIRStmtParser>(
2971 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
2975 auto stmtIndent = getIndentation();
2978 if (!stmtIndent.has_value())
2979 return subParser->parseSimpleStmt(indent);
2981 if (*stmtIndent <= indent)
2982 return emitError(
"statement must be indented more than previous statement"),
2986 return subParser->parseSimpleStmtBlock(indent);
2990ParseResult FIRStmtParser::parseAttach() {
2991 auto startTok = consumeToken(FIRToken::kw_attach);
2994 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
2997 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3000 SmallVector<Value, 4> operands;
3001 operands.push_back({});
3002 if (parseExp(operands.back(),
"expected operand in attach"))
3005 while (consumeIf(FIRToken::comma)) {
3006 operands.push_back({});
3007 if (parseExp(operands.back(),
"expected operand in attach"))
3010 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3013 if (parseOptionalInfo())
3016 locationProcessor.setLoc(startTok.getLoc());
3017 AttachOp::create(builder, operands);
3024ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3025 auto startTok = consumeToken();
3026 auto startLoc = startTok.getLoc();
3030 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3036 Value memory, indexExp, clock;
3037 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3038 parseId(
id,
"expected result name") ||
3039 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3040 parseId(memName,
"expected memory name") ||
3041 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3042 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3043 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3044 parseExp(indexExp,
"expected index expression") ||
3045 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3046 parseToken(FIRToken::comma,
"expected ','") ||
3047 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3050 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3052 return emitError(startLoc,
3053 "memory port should have behavioral memory type");
3054 auto resultType = memVType.getElementType();
3056 ArrayAttr annotations = getConstants().emptyArrayAttr;
3057 locationProcessor.setLoc(startLoc);
3060 Value memoryPort, memoryData;
3062 OpBuilder::InsertionGuard guard(builder);
3063 builder.setInsertionPointAfterValue(memory);
3064 auto memoryPortOp = MemoryPortOp::create(
3065 builder, resultType, CMemoryPortType::get(getContext()), memory,
3066 direction,
id, annotations);
3067 memoryData = memoryPortOp.getResult(0);
3068 memoryPort = memoryPortOp.getResult(1);
3072 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3074 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3080ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3081 StringRef formatString,
3082 ArrayRef<Value> specOperands,
3083 StringAttr &formatStringResult,
3084 SmallVectorImpl<Value> &operands) {
3088 SmallVector<Attribute, 4> specialSubstitutions;
3089 SmallString<64> validatedFormatString;
3091 validatedFormatString = formatString;
3092 operands.append(specOperands.begin(), specOperands.end());
3094 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
3095 auto c = formatString[i];
3100 validatedFormatString.push_back(c);
3103 SmallString<6> width;
3104 c = formatString[++i];
3107 c = formatString[++i];
3113 if (!width.empty()) {
3114 emitError(formatStringLoc) <<
"ASCII character format specifiers "
3115 "('%c') may not specify a width";
3123 validatedFormatString.append(width);
3124 operands.push_back(specOperands[opIdx++]);
3127 if (!width.empty()) {
3128 emitError(formatStringLoc)
3129 <<
"literal percents ('%%') may not specify a width";
3135 emitError(formatStringLoc)
3136 <<
"unknown printf substitution '%" << width << c <<
"'";
3139 validatedFormatString.push_back(c);
3147 if (formatString[i + 1] !=
'{') {
3148 validatedFormatString.push_back(c);
3154 while (formatString[i] !=
'}')
3156 if (formatString[i] !=
'}') {
3157 llvm::errs() <<
"expected '}' to terminate special substitution";
3161 auto specialString = formatString.slice(start, i);
3162 if (specialString ==
"SimulationTime") {
3163 operands.push_back(TimeOp::create(builder));
3164 }
else if (specialString ==
"HierarchicalModuleName") {
3165 operands.push_back(HierarchicalModuleNameOp::create(builder));
3167 emitError(formatStringLoc)
3168 <<
"unknown printf substitution '" << specialString
3169 <<
"' (did you misspell it?)";
3173 validatedFormatString.append(
"{{}}");
3178 validatedFormatString.push_back(c);
3183 formatStringResult =
3189ParseResult FIRStmtParser::parsePrintf() {
3190 auto startTok = consumeToken(FIRToken::lp_printf);
3192 Value clock, condition;
3193 StringRef formatString;
3194 if (parseExp(clock,
"expected clock expression in printf") ||
3195 parseToken(FIRToken::comma,
"expected ','") ||
3196 parseExp(condition,
"expected condition in printf") ||
3197 parseToken(FIRToken::comma,
"expected ','"))
3200 auto formatStringLoc = getToken().getLoc();
3201 if (parseGetSpelling(formatString) ||
3202 parseToken(FIRToken::string,
"expected format string in printf"))
3205 SmallVector<Value, 4> specOperands;
3206 while (consumeIf(FIRToken::comma)) {
3207 specOperands.push_back({});
3208 if (parseExp(specOperands.back(),
"expected operand in printf"))
3213 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3214 parseOptionalName(name) || parseOptionalInfo())
3217 locationProcessor.setLoc(startTok.getLoc());
3219 StringAttr formatStrUnescaped;
3220 SmallVector<Value> operands;
3221 if (parseFormatString(formatStringLoc, formatString, specOperands,
3222 formatStrUnescaped, operands))
3225 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3231ParseResult FIRStmtParser::parseFPrintf() {
3234 auto startTok = consumeToken(FIRToken::lp_fprintf);
3236 Value clock, condition;
3237 StringRef outputFile, formatString;
3238 if (parseExp(clock,
"expected clock expression in fprintf") ||
3239 parseToken(FIRToken::comma,
"expected ','") ||
3240 parseExp(condition,
"expected condition in fprintf") ||
3241 parseToken(FIRToken::comma,
"expected ','"))
3244 auto outputFileLoc = getToken().getLoc();
3245 if (parseGetSpelling(outputFile) ||
3246 parseToken(FIRToken::string,
"expected output file in fprintf"))
3249 SmallVector<Value, 4> outputFileSpecOperands;
3250 while (consumeIf(FIRToken::comma)) {
3252 if (getToken().getKind() == FIRToken::string)
3254 outputFileSpecOperands.push_back({});
3255 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3259 auto formatStringLoc = getToken().getLoc();
3260 if (parseGetSpelling(formatString) ||
3261 parseToken(FIRToken::string,
"expected format string in printf"))
3264 SmallVector<Value, 4> specOperands;
3265 while (consumeIf(FIRToken::comma)) {
3266 specOperands.push_back({});
3267 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3272 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3273 parseOptionalName(name) || parseOptionalInfo())
3276 locationProcessor.setLoc(startTok.getLoc());
3278 StringAttr outputFileNameStrUnescaped;
3279 SmallVector<Value> outputFileOperands;
3280 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3281 outputFileNameStrUnescaped, outputFileOperands))
3284 StringAttr formatStrUnescaped;
3285 SmallVector<Value> operands;
3286 if (parseFormatString(formatStringLoc, formatString, specOperands,
3287 formatStrUnescaped, operands))
3290 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3291 outputFileOperands, formatStrUnescaped, operands, name);
3296ParseResult FIRStmtParser::parseFFlush() {
3300 auto startTok = consumeToken(FIRToken::lp_fflush);
3302 Value clock, condition;
3303 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3304 parseToken(FIRToken::comma,
"expected ','") ||
3305 parseExp(condition,
"expected condition in 'fflush'"))
3308 locationProcessor.setLoc(startTok.getLoc());
3309 StringAttr outputFileNameStrUnescaped;
3310 SmallVector<Value> outputFileOperands;
3312 if (consumeIf(FIRToken::comma)) {
3313 SmallVector<Value, 4> outputFileSpecOperands;
3314 auto outputFileLoc = getToken().getLoc();
3315 StringRef outputFile;
3316 if (parseGetSpelling(outputFile) ||
3317 parseToken(FIRToken::string,
"expected output file in fflush"))
3320 while (consumeIf(FIRToken::comma)) {
3321 outputFileSpecOperands.push_back({});
3322 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3326 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3327 outputFileNameStrUnescaped, outputFileOperands))
3331 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3332 parseOptionalInfo())
3335 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3336 outputFileOperands);
3341ParseResult FIRStmtParser::parseSkip() {
3342 auto startTok = consumeToken(FIRToken::kw_skip);
3346 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3349 if (parseOptionalInfo())
3352 locationProcessor.setLoc(startTok.getLoc());
3353 SkipOp::create(builder);
3358ParseResult FIRStmtParser::parseStop() {
3359 auto startTok = consumeToken(FIRToken::lp_stop);
3361 Value clock, condition;
3364 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3365 parseToken(FIRToken::comma,
"expected ','") ||
3366 parseExp(condition,
"expected condition in 'stop'") ||
3367 parseToken(FIRToken::comma,
"expected ','") ||
3368 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3369 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3370 parseOptionalName(name) || parseOptionalInfo())
3373 locationProcessor.setLoc(startTok.getLoc());
3374 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3380ParseResult FIRStmtParser::parseAssert() {
3381 auto startTok = consumeToken(FIRToken::lp_assert);
3383 Value clock, predicate, enable;
3384 StringRef formatString;
3386 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3387 parseToken(FIRToken::comma,
"expected ','") ||
3388 parseExp(predicate,
"expected predicate in 'assert'") ||
3389 parseToken(FIRToken::comma,
"expected ','") ||
3390 parseExp(enable,
"expected enable in 'assert'") ||
3391 parseToken(FIRToken::comma,
"expected ','") ||
3392 parseGetSpelling(formatString) ||
3393 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3396 SmallVector<Value, 4> operands;
3397 while (!consumeIf(FIRToken::r_paren)) {
3398 operands.push_back({});
3399 if (parseToken(FIRToken::comma,
"expected ','") ||
3400 parseExp(operands.back(),
"expected operand in 'assert'"))
3404 if (parseOptionalName(name) || parseOptionalInfo())
3407 locationProcessor.setLoc(startTok.getLoc());
3409 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3410 operands, name.getValue());
3415ParseResult FIRStmtParser::parseAssume() {
3416 auto startTok = consumeToken(FIRToken::lp_assume);
3418 Value clock, predicate, enable;
3419 StringRef formatString;
3421 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3422 parseToken(FIRToken::comma,
"expected ','") ||
3423 parseExp(predicate,
"expected predicate in 'assume'") ||
3424 parseToken(FIRToken::comma,
"expected ','") ||
3425 parseExp(enable,
"expected enable in 'assume'") ||
3426 parseToken(FIRToken::comma,
"expected ','") ||
3427 parseGetSpelling(formatString) ||
3428 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3431 SmallVector<Value, 4> operands;
3432 while (!consumeIf(FIRToken::r_paren)) {
3433 operands.push_back({});
3434 if (parseToken(FIRToken::comma,
"expected ','") ||
3435 parseExp(operands.back(),
"expected operand in 'assume'"))
3439 if (parseOptionalName(name) || parseOptionalInfo())
3442 locationProcessor.setLoc(startTok.getLoc());
3444 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3445 operands, name.getValue());
3450ParseResult FIRStmtParser::parseCover() {
3451 auto startTok = consumeToken(FIRToken::lp_cover);
3453 Value clock, predicate, enable;
3456 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3457 parseToken(FIRToken::comma,
"expected ','") ||
3458 parseExp(predicate,
"expected predicate in 'cover'") ||
3459 parseToken(FIRToken::comma,
"expected ','") ||
3460 parseExp(enable,
"expected enable in 'cover'") ||
3461 parseToken(FIRToken::comma,
"expected ','") ||
3462 parseGetSpelling(message) ||
3463 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3464 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3465 parseOptionalName(name) || parseOptionalInfo())
3468 locationProcessor.setLoc(startTok.getLoc());
3470 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3471 ValueRange{}, name.getValue());
3477ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3478 auto startTok = consumeToken(FIRToken::kw_when);
3482 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3486 if (parseExp(condition,
"expected condition in 'when'") ||
3487 parseToken(FIRToken::colon,
"expected ':' in when") ||
3488 parseOptionalInfo())
3491 locationProcessor.setLoc(startTok.getLoc());
3493 auto whenStmt = WhenOp::create(builder, condition,
false);
3496 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3500 if (getToken().isNot(FIRToken::kw_else))
3505 auto elseIndent = getIndentation();
3506 if (elseIndent && *elseIndent < whenIndent)
3509 consumeToken(FIRToken::kw_else);
3512 whenStmt.createElseRegion();
3518 if (getToken().is(FIRToken::kw_when)) {
3520 auto subParser = std::make_unique<FIRStmtParser>(
3521 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3524 return subParser->parseSimpleStmt(whenIndent);
3528 LocationAttr elseLoc;
3529 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3530 parseOptionalInfoLocator(elseLoc) ||
3531 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3540ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3541 auto startLoc = getToken().getLoc();
3542 locationProcessor.setLoc(startLoc);
3544 if (parseEnumType(type))
3548 auto enumType = type_dyn_cast<FEnumType>(type);
3550 return emitError(startLoc,
3551 "expected enumeration type in enumeration expression");
3554 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3555 parseId(tag,
"expected enumeration tag"))
3559 if (consumeIf(FIRToken::r_paren)) {
3562 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3563 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3564 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3565 input = ConstantOp::create(builder, type, attr);
3568 if (parseToken(FIRToken::comma,
"expected ','") ||
3569 parseExp(input,
"expected expression in enumeration value") ||
3570 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3574 value = FEnumCreateOp::create(builder, enumType, tag, input);
3582ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3583 auto startTok = consumeToken(FIRToken::kw_match);
3585 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3589 if (parseExp(input,
"expected expression in 'match'") ||
3590 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3591 parseOptionalInfo())
3594 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3596 return mlir::emitError(
3598 "expected enumeration type for 'match' statement, but got ")
3601 locationProcessor.setLoc(startTok.getLoc());
3603 SmallVector<Attribute> tags;
3604 SmallVector<std::unique_ptr<Region>> regions;
3606 auto tagLoc = getToken().getLoc();
3609 auto caseIndent = getIndentation();
3610 if (!caseIndent || *caseIndent <= matchIndent)
3614 StringRef tagSpelling;
3615 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3617 auto tagIndex = enumType.getElementIndex(tagSpelling);
3619 return emitError(tagLoc,
"tag ")
3620 << tagSpelling <<
" not a member of enumeration " << enumType;
3621 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3622 tags.push_back(tag);
3625 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3628 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3633 UnbundledValueRestorer x(moduleContext.unbundledValues);
3636 if (consumeIf(FIRToken::l_paren)) {
3637 StringAttr identifier;
3638 if (parseId(identifier,
"expected identifier for 'case' binding"))
3642 auto dataType = enumType.getElementType(*tagIndex);
3643 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3645 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3649 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3653 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3654 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3657 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3661 auto subParser = std::make_unique<FIRStmtParser>(
3662 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3664 if (subParser->parseSimpleStmtBlock(*caseIndent))
3668 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3674ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3675 auto token = getToken().getKind();
3676 if (token == FIRToken::lp_probe)
3677 return parseProbe(result);
3678 if (token == FIRToken::lp_rwprobe)
3679 return parseRWProbe(result);
3684 return parseStaticRefExp(result, message);
3691ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3692 const Twine &message) {
3693 auto parseIdOrInstance = [&]() -> ParseResult {
3695 auto loc = getToken().getLoc();
3697 if (parseId(
id, message) ||
3698 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3702 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3705 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3708 StringRef fieldName;
3710 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3711 parseFieldId(fieldName,
"expected field name") ||
3712 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3714 return failure(parseIdOrInstance() ||
3715 parseOptionalExpPostscript(result,
false));
3726ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3728 const Twine &message) {
3729 auto loc = getToken().getLoc();
3733 if (parseId(
id, message) ||
3734 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3746 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3748 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3750 StringRef fieldName;
3751 auto loc = getToken().getLoc();
3752 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3753 parseFieldId(fieldName,
"expected field name"))
3758 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3759 for (
auto &elt : ubEntry) {
3760 if (elt.first == fieldAttr) {
3763 auto &instResult = elt.second;
3766 auto *defining = instResult.getDefiningOp();
3768 if (isa<WireOp>(defining)) {
3769 result = instResult;
3774 auto type = instResult.getType();
3778 bool forceable =
static_cast<bool>(
3781 return emitError(loc,
"unable to force instance result of type ")
3785 auto annotations = getConstants().emptyArrayAttr;
3786 StringAttr sym = {};
3787 SmallString<64> name;
3788 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3789 locationProcessor.setLoc(loc);
3790 OpBuilder::InsertionGuard guard(builder);
3791 builder.setInsertionPoint(defining);
3793 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3795 auto bounceVal = bounce.getData();
3798 instResult.replaceAllUsesWith(bounceVal);
3801 builder.setInsertionPointAfter(defining);
3802 if (
foldFlow(instResult) == Flow::Source)
3809 result = instResult = bounce.getDataRaw();
3815 emitError(loc,
"use of invalid field name '")
3816 << fieldName <<
"' on bundle value";
3821 result = cast<Value>(symtabEntry);
3825 assert(isa<BlockArgument>(result) ||
3826 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3832 type = result.getType();
3834 if (consumeIf(FIRToken::period)) {
3835 SmallVector<StringRef, 3> fields;
3836 if (parseFieldIdSeq(fields,
"expected field name"))
3838 for (
auto fieldName : fields) {
3839 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3840 if (
auto index = bundle.getElementIndex(fieldName)) {
3841 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3842 type = bundle.getElementTypePreservingConst(*index);
3845 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3846 if (
auto index = bundle.getElementIndex(fieldName)) {
3847 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3848 type = bundle.getElementTypePreservingConst(*index);
3852 return emitError(loc,
"subfield requires bundle operand")
3853 <<
"got " << type <<
"\n";
3855 return emitError(loc,
3856 "unknown field '" + fieldName +
"' in bundle type ")
3861 if (consumeIf(FIRToken::l_square)) {
3862 auto loc = getToken().
getLoc();
3864 if (parseIntLit(index,
"expected index") ||
3865 parseToken(FIRToken::r_square,
"expected ']'"))
3869 return emitError(loc,
"invalid index specifier");
3871 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3872 if ((
unsigned)index < vector.getNumElements()) {
3873 refResult = refResult.
getSubField(vector.getFieldID(index));
3874 type = vector.getElementTypePreservingConst();
3877 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3878 if ((
unsigned)index < vector.getNumElements()) {
3879 refResult = refResult.
getSubField(vector.getFieldID(index));
3880 type = vector.getElementTypePreservingConst();
3884 return emitError(loc,
"subindex requires vector operand");
3886 return emitError(loc,
"out of range index '")
3887 << index <<
"' for vector type " << type;
3895ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3896 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3897 StringRef intrinsic;
3898 ArrayAttr parameters;
3901 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3902 parseOptionalParams(parameters))
3905 if (consumeIf(FIRToken::colon)) {
3906 if (
parseType(type,
"expected intrinsic return type"))
3908 }
else if (!isStatement)
3909 return emitError(
"expected ':' in intrinsic expression");
3911 SmallVector<Value> operands;
3912 auto loc = startTok.getLoc();
3913 if (consumeIf(FIRToken::comma)) {
3914 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3916 if (parseExp(operand,
"expected operand in intrinsic"))
3918 operands.push_back(operand);
3919 locationProcessor.setLoc(loc);
3924 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3929 if (parseOptionalInfo())
3932 locationProcessor.setLoc(loc);
3934 auto op = GenericIntrinsicOp::create(
3935 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
3937 result = op.getResult();
3942ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3943 if (!consumeIf(FIRToken::less))
3946 SmallVector<Attribute, 8> parameters;
3947 SmallPtrSet<StringAttr, 8> seen;
3948 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3952 if (parseParameter(name, value, loc))
3954 auto typedValue = dyn_cast<TypedAttr>(value);
3956 return emitError(loc)
3957 <<
"invalid value for parameter '" << name.getValue() <<
"'";
3958 if (!seen.insert(name).second)
3959 return emitError(loc,
"redefinition of parameter '" +
3960 name.getValue() +
"'");
3961 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3966 resultParameters = ArrayAttr::get(getContext(), parameters);
3972ParseResult FIRStmtParser::parsePathExp(Value &result) {
3973 auto startTok = consumeToken(FIRToken::lp_path);
3974 locationProcessor.setLoc(startTok.getLoc());
3976 if (parseGetSpelling(target) ||
3977 parseToken(FIRToken::string,
3978 "expected target string in path expression") ||
3979 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3981 result = UnresolvedPathOp::create(
3987ParseResult FIRStmtParser::parseRefDefine() {
3988 auto startTok = consumeToken(FIRToken::kw_define);
3991 if (parseStaticRefExp(target,
3992 "expected static reference expression in 'define'") ||
3993 parseToken(FIRToken::equal,
3994 "expected '=' after define reference expression") ||
3995 parseRefExp(src,
"expected reference expression in 'define'") ||
3996 parseOptionalInfo())
4000 if (!type_isa<RefType>(target.getType()))
4001 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4002 "'define' target (LHS), got ")
4003 << target.getType();
4004 if (!type_isa<RefType>(src.getType()))
4005 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4006 "'define' source (RHS), got ")
4011 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4012 return emitError(startTok.getLoc(),
4013 "cannot define into a sub-element of a reference");
4015 locationProcessor.setLoc(startTok.getLoc());
4018 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4019 << target.getType() <<
" with incompatible reference of type "
4029ParseResult FIRStmtParser::parseRefRead(Value &result) {
4030 auto startTok = consumeToken(FIRToken::lp_read);
4033 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4034 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4037 locationProcessor.setLoc(startTok.getLoc());
4040 if (!type_isa<RefType>(ref.getType()))
4041 return emitError(startTok.getLoc(),
4042 "expected reference-type expression in 'read', got ")
4045 result = RefResolveOp::create(builder, ref);
4051ParseResult FIRStmtParser::parseProbe(Value &result) {
4052 auto startTok = consumeToken(FIRToken::lp_probe);
4055 if (parseStaticRefExp(staticRef,
4056 "expected static reference expression in 'probe'") ||
4057 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4060 locationProcessor.setLoc(startTok.getLoc());
4063 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4064 return emitError(startTok.getLoc(),
4065 "expected base-type expression in 'probe', got ")
4066 << staticRef.getType();
4070 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4071 MemoryDebugPortOp, MemoryPortAccessOp>(
4072 staticRef.getDefiningOp()))
4073 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4075 result = RefSendOp::create(builder, staticRef);
4081ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4082 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4085 Type parsedTargetType;
4086 if (parseRWProbeStaticRefExp(
4087 staticRef, parsedTargetType,
4088 "expected static reference expression in 'rwprobe'") ||
4089 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4092 locationProcessor.setLoc(startTok.getLoc());
4098 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4100 return emitError(startTok.getLoc(),
4101 "expected base-type expression in 'rwprobe', got ")
4102 << parsedTargetType;
4105 auto *definingOp = root.getDefiningOp();
4107 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4108 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4109 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4113 return emitError(startTok.getLoc(),
"cannot force target of type ")
4117 auto op = RWProbeOp::create(builder, forceableType,
4118 getConstants().placeholderInnerRef);
4125ParseResult FIRStmtParser::parseRefForce() {
4126 auto startTok = consumeToken(FIRToken::lp_force);
4128 Value clock, pred, dest, src;
4129 if (parseExp(clock,
"expected clock expression in force") ||
4130 parseToken(FIRToken::comma,
"expected ','") ||
4131 parseExp(pred,
"expected predicate expression in force") ||
4132 parseToken(FIRToken::comma,
"expected ','") ||
4133 parseRefExp(dest,
"expected destination reference expression in force") ||
4134 parseToken(FIRToken::comma,
"expected ','") ||
4135 parseExp(src,
"expected source expression in force") ||
4136 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4137 parseOptionalInfo())
4141 auto ref = type_dyn_cast<RefType>(dest.getType());
4142 if (!ref || !ref.getForceable())
4145 "expected rwprobe-type expression for force destination, got ")
4147 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4149 return emitError(startTok.getLoc(),
4150 "expected base-type for force source, got ")
4152 if (!srcBaseType.isPassive())
4153 return emitError(startTok.getLoc(),
4154 "expected passive value for force source, got ")
4157 locationProcessor.setLoc(startTok.getLoc());
4160 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4161 if (noConstSrcType != ref.getType()) {
4163 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4165 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4167 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4168 << src.getType() <<
" cannot target destination "
4172 RefForceOp::create(builder, clock, pred, dest, src);
4178ParseResult FIRStmtParser::parseRefForceInitial() {
4179 auto startTok = consumeToken(FIRToken::lp_force_initial);
4183 dest,
"expected destination reference expression in force_initial") ||
4184 parseToken(FIRToken::comma,
"expected ','") ||
4185 parseExp(src,
"expected source expression in force_initial") ||
4186 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4187 parseOptionalInfo())
4191 auto ref = type_dyn_cast<RefType>(dest.getType());
4192 if (!ref || !ref.getForceable())
4193 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4194 "force_initial destination, got ")
4196 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4198 return emitError(startTok.getLoc(),
4199 "expected base-type expression for force_initial "
4202 if (!srcBaseType.isPassive())
4203 return emitError(startTok.getLoc(),
4204 "expected passive value for force_initial source, got ")
4207 locationProcessor.setLoc(startTok.getLoc());
4210 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4211 if (noConstSrcType != ref.getType()) {
4213 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4215 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4217 return emitError(startTok.getLoc(),
4218 "incompatible force_initial source of type ")
4219 << src.getType() <<
" cannot target destination "
4223 auto value = APInt::getAllOnes(1);
4224 auto type = UIntType::get(builder.getContext(), 1);
4225 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4226 value.getBitWidth(),
4227 IntegerType::Unsigned),
4229 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4230 RefForceInitialOp::create(builder, pred, dest, src);
4236ParseResult FIRStmtParser::parseRefRelease() {
4237 auto startTok = consumeToken(FIRToken::lp_release);
4239 Value clock, pred, dest;
4240 if (parseExp(clock,
"expected clock expression in release") ||
4241 parseToken(FIRToken::comma,
"expected ','") ||
4242 parseExp(pred,
"expected predicate expression in release") ||
4243 parseToken(FIRToken::comma,
"expected ','") ||
4245 "expected destination reference expression in release") ||
4246 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4247 parseOptionalInfo())
4251 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4252 !ref || !ref.getForceable())
4255 "expected rwprobe-type expression for release destination, got ")
4258 locationProcessor.setLoc(startTok.getLoc());
4260 RefReleaseOp::create(builder, clock, pred, dest);
4266ParseResult FIRStmtParser::parseRefReleaseInitial() {
4267 auto startTok = consumeToken(FIRToken::lp_release_initial);
4272 "expected destination reference expression in release_initial") ||
4273 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4274 parseOptionalInfo())
4278 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4279 !ref || !ref.getForceable())
4280 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4281 "release_initial destination, got ")
4284 locationProcessor.setLoc(startTok.getLoc());
4286 auto value = APInt::getAllOnes(1);
4287 auto type = UIntType::get(builder.getContext(), 1);
4288 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4289 value.getBitWidth(),
4290 IntegerType::Unsigned),
4292 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4293 RefReleaseInitialOp::create(builder, pred, dest);
4299ParseResult FIRStmtParser::parseConnect() {
4300 auto startTok = consumeToken(FIRToken::kw_connect);
4301 auto loc = startTok.getLoc();
4304 if (parseExp(lhs,
"expected connect expression") ||
4305 parseToken(FIRToken::comma,
"expected ','") ||
4306 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4309 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4310 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4311 if (!lhsType || !rhsType)
4312 return emitError(loc,
"cannot connect reference or property types");
4314 if (lhsType.containsReference() || rhsType.containsReference())
4315 return emitError(loc,
"cannot connect types containing references");
4318 return emitError(loc,
"cannot connect non-equivalent type ")
4319 << rhsType <<
" to " << lhsType;
4321 locationProcessor.setLoc(loc);
4327ParseResult FIRStmtParser::parsePropAssign() {
4328 auto startTok = consumeToken(FIRToken::kw_propassign);
4329 auto loc = startTok.getLoc();
4332 if (parseExp(lhs,
"expected propassign expression") ||
4333 parseToken(FIRToken::comma,
"expected ','") ||
4334 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4337 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4338 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4339 if (!lhsType || !rhsType)
4340 return emitError(loc,
"can only propassign property types");
4341 locationProcessor.setLoc(loc);
4342 if (lhsType != rhsType) {
4344 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4345 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4347 return emitError(loc,
"cannot propassign non-equivalent type ")
4348 << rhsType <<
" to " << lhsType;
4350 PropAssignOp::create(builder, lhs, rhs);
4355ParseResult FIRStmtParser::parseInvalidate() {
4356 auto startTok = consumeToken(FIRToken::kw_invalidate);
4361 auto loc = getToken().getLoc();
4363 if (parseId(
id,
"expected static reference expression") ||
4364 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4369 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4370 if (parseOptionalExpPostscript(lhs,
false) ||
4371 parseOptionalInfo())
4374 locationProcessor.setLoc(startTok.getLoc());
4375 emitInvalidate(lhs);
4382 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4384 if (getToken().isNot(FIRToken::period)) {
4385 locationProcessor.setLoc(loc);
4387 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4389 for (
auto elt : ubEntry)
4390 emitInvalidate(elt.second);
4396 StringRef fieldName;
4397 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4398 parseFieldId(fieldName,
"expected field name") ||
4399 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4403 if (parseOptionalExpPostscript(lhs,
false) ||
4404 parseOptionalInfo())
4407 locationProcessor.setLoc(startTok.getLoc());
4408 emitInvalidate(lhs);
4412ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4414 auto startTok = consumeToken();
4415 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4416 "consumed an unexpected token");
4417 auto loc = startTok.getLoc();
4420 if (parseId(
id,
"expected layer identifer") ||
4421 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4422 parseOptionalInfo())
4425 locationProcessor.setLoc(loc);
4427 StringRef rootLayer;
4428 SmallVector<FlatSymbolRefAttr> nestedLayers;
4432 rootLayer = layerSym.getRootReference();
4433 auto nestedRefs = layerSym.getNestedReferences();
4434 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4435 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4438 auto layerBlockOp = LayerBlockOp::create(
4440 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4441 layerBlockOp->getRegion(0).push_back(
new Block());
4443 if (getIndentation() > indent)
4444 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4445 layerBlockOp.getLayerName()))
4453ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4454 auto loc = getToken().getLoc();
4457 if (consumeIf(FIRToken::kw_is)) {
4458 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4459 parseOptionalInfo())
4462 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4465 locationProcessor.setLoc(loc);
4466 emitInvalidate(lhs);
4470 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4473 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4477 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4480 locationProcessor.setLoc(loc);
4482 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4483 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4484 if (!lhsType || !rhsType)
4485 return emitError(loc,
"cannot connect reference or property types");
4487 if (lhsType.containsReference() || rhsType.containsReference())
4488 return emitError(loc,
"cannot connect types containing references");
4491 return emitError(loc,
"cannot connect non-equivalent type ")
4492 << rhsType <<
" to " << lhsType;
4501ParseResult FIRStmtParser::parseInstance() {
4502 auto startTok = consumeToken(FIRToken::kw_inst);
4506 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4510 StringRef moduleName;
4511 if (parseId(
id,
"expected instance name") ||
4512 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4513 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4516 locationProcessor.setLoc(startTok.getLoc());
4519 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4520 if (!referencedModule)
4523 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4525 auto annotations = getConstants().emptyArrayAttr;
4526 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4528 hw::InnerSymAttr sym = {};
4529 auto result = InstanceOp::create(
4530 builder, referencedModule,
id, NameKindEnum::InterestingName,
4531 annotations.getValue(), portAnnotations,
false,
false, sym);
4537 unbundledValueEntry.reserve(modulePorts.size());
4538 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4539 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4543 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4544 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4545 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4550ParseResult FIRStmtParser::parseInstanceChoice() {
4551 auto startTok = consumeToken(FIRToken::kw_instchoice);
4552 SMLoc loc = startTok.getLoc();
4555 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4562 StringRef defaultModuleName;
4563 StringRef optionGroupName;
4564 if (parseId(
id,
"expected instance name") ||
4565 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4566 parseId(defaultModuleName,
"expected module name") ||
4567 parseToken(FIRToken::comma,
"expected ','") ||
4568 parseId(optionGroupName,
"expected option group name") ||
4569 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4570 parseOptionalInfo())
4573 locationProcessor.setLoc(startTok.getLoc());
4577 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4581 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4584 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4586 return emitError(loc,
4587 "use of undefined option group '" + optionGroupName +
"'");
4589 auto baseIndent = getIndentation();
4590 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4591 while (getIndentation() == baseIndent) {
4593 StringRef caseModuleName;
4594 if (parseId(caseId,
"expected a case identifier") ||
4595 parseToken(FIRToken::equal_greater,
4596 "expected '=> in instance choice definition") ||
4597 parseId(caseModuleName,
"expected module name"))
4600 auto caseModule = getReferencedModule(loc, caseModuleName);
4604 for (
const auto &[defaultPort, casePort] :
4605 llvm::zip(modulePorts, caseModule.getPorts())) {
4606 if (defaultPort.name != casePort.name)
4607 return emitError(loc,
"instance case module port '")
4608 << casePort.name.getValue()
4609 <<
"' does not match the default module port '"
4610 << defaultPort.name.getValue() <<
"'";
4611 if (defaultPort.type != casePort.type)
4612 return emitError(loc,
"instance case port '")
4613 << casePort.name.getValue()
4614 <<
"' type does not match the default module port";
4618 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4620 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4621 caseModules.emplace_back(optionCase, caseModule);
4624 auto annotations = getConstants().emptyArrayAttr;
4625 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4629 auto result = InstanceChoiceOp::create(
4630 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4631 annotations.getValue(), portAnnotations, sym);
4635 unbundledValueEntry.reserve(modulePorts.size());
4636 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4637 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4639 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4640 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4641 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4644FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4645 StringRef moduleName) {
4646 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4647 if (!referencedModule) {
4649 "use of undefined module name '" + moduleName +
"' in instance");
4652 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4653 emitError(loc,
"cannot create instance of class '" + moduleName +
4654 "', did you mean object?");
4657 return referencedModule;
4661ParseResult FIRStmtParser::parseObject() {
4662 auto startTok = consumeToken(FIRToken::kw_object);
4666 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4673 StringRef className;
4674 if (parseId(
id,
"expected object name") ||
4675 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4676 parseId(className,
"expected class name") || parseOptionalInfo())
4679 locationProcessor.setLoc(startTok.getLoc());
4682 const auto &classMap = getConstants().classMap;
4683 auto lookup = classMap.find(className);
4684 if (lookup == classMap.end())
4685 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4686 className +
"' in object");
4687 auto referencedClass = lookup->getSecond();
4688 auto result = ObjectOp::create(builder, referencedClass,
id);
4689 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4693ParseResult FIRStmtParser::parseCombMem() {
4695 auto startTok = consumeToken(FIRToken::kw_cmem);
4699 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4704 if (parseId(
id,
"expected cmem name") ||
4705 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4706 parseType(type,
"expected cmem type") || parseOptionalInfo())
4709 locationProcessor.setLoc(startTok.getLoc());
4712 auto vectorType = type_dyn_cast<FVectorType>(type);
4714 return emitError(
"cmem requires vector type");
4716 auto annotations = getConstants().emptyArrayAttr;
4717 StringAttr sym = {};
4718 auto result = CombMemOp::create(
4719 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4720 NameKindEnum::InterestingName, annotations, sym);
4721 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4725ParseResult FIRStmtParser::parseSeqMem() {
4727 auto startTok = consumeToken(FIRToken::kw_smem);
4731 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4736 RUWBehavior ruw = RUWBehavior::Undefined;
4738 if (parseId(
id,
"expected smem name") ||
4739 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4743 if (consumeIf(FIRToken::comma)) {
4748 if (parseOptionalInfo()) {
4752 locationProcessor.setLoc(startTok.getLoc());
4755 auto vectorType = type_dyn_cast<FVectorType>(type);
4757 return emitError(
"smem requires vector type");
4759 auto annotations = getConstants().emptyArrayAttr;
4760 StringAttr sym = {};
4761 auto result = SeqMemOp::create(
4762 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4763 id, NameKindEnum::InterestingName, annotations, sym);
4764 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4776ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4777 auto startTok = consumeToken(FIRToken::kw_mem);
4781 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4785 if (parseId(
id,
"expected mem name") ||
4786 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4790 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4791 RUWBehavior ruw = RUWBehavior::Undefined;
4793 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4797 auto nextIndent = getIndentation();
4798 if (!nextIndent || *nextIndent <= memIndent)
4801 auto spelling = getTokenSpelling();
4802 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4803 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4806 if (spelling ==
"data-type") {
4808 return emitError(
"'mem' type specified multiple times"), failure();
4810 if (
parseType(type,
"expected type in data-type declaration"))
4814 if (spelling ==
"depth") {
4815 if (parseIntLit(depth,
"expected integer in depth specification"))
4819 if (spelling ==
"read-latency") {
4820 if (parseIntLit(readLatency,
"expected integer latency"))
4824 if (spelling ==
"write-latency") {
4825 if (parseIntLit(writeLatency,
"expected integer latency"))
4829 if (spelling ==
"read-under-write") {
4830 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4831 FIRToken::kw_undefined))
4832 return emitError(
"expected specifier"), failure();
4834 if (parseOptionalRUW(ruw))
4839 MemOp::PortKind portKind;
4840 if (spelling ==
"reader")
4841 portKind = MemOp::PortKind::Read;
4842 else if (spelling ==
"writer")
4843 portKind = MemOp::PortKind::Write;
4844 else if (spelling ==
"readwriter")
4845 portKind = MemOp::PortKind::ReadWrite;
4847 return emitError(
"unexpected field in 'mem' declaration"), failure();
4850 if (parseId(portName,
"expected port name"))
4852 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4854 return emitError(
"unexpected type, must be base type");
4855 ports.push_back({builder.getStringAttr(portName),
4856 MemOp::getTypeForPort(depth, baseType, portKind)});
4858 while (!getIndentation().has_value()) {
4859 if (parseId(portName,
"expected port name"))
4861 ports.push_back({builder.getStringAttr(portName),
4862 MemOp::getTypeForPort(depth, baseType, portKind)});
4873 llvm::array_pod_sort(ports.begin(), ports.end(),
4874 [](
const std::pair<StringAttr, Type> *lhs,
4875 const std::pair<StringAttr, Type> *rhs) ->
int {
4876 return lhs->first.getValue().compare(
4877 rhs->first.getValue());
4880 auto annotations = getConstants().emptyArrayAttr;
4881 SmallVector<Attribute, 4> resultNames;
4882 SmallVector<Type, 4> resultTypes;
4883 SmallVector<Attribute, 4> resultAnnotations;
4884 for (
auto p : ports) {
4885 resultNames.push_back(p.first);
4886 resultTypes.push_back(p.second);
4887 resultAnnotations.push_back(annotations);
4890 locationProcessor.setLoc(startTok.getLoc());
4892 auto result = MemOp::create(
4893 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4894 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
4895 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4896 MemoryInitAttr(), StringAttr());
4899 unbundledValueEntry.reserve(result.getNumResults());
4900 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4901 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4903 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4904 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4905 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4909ParseResult FIRStmtParser::parseNode() {
4910 auto startTok = consumeToken(FIRToken::kw_node);
4914 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4919 if (parseId(
id,
"expected node name") ||
4920 parseToken(FIRToken::equal,
"expected '=' in node") ||
4921 parseExp(initializer,
"expected expression for node") ||
4922 parseOptionalInfo())
4925 locationProcessor.setLoc(startTok.getLoc());
4937 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4938 auto initializerBaseType =
4939 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4940 if (type_isa<AnalogType>(initializerType) ||
4941 !(initializerBaseType && initializerBaseType.isPassive())) {
4942 emitError(startTok.getLoc())
4943 <<
"Node cannot be analog and must be passive or passive under a flip "
4944 << initializer.getType();
4948 auto annotations = getConstants().emptyArrayAttr;
4949 StringAttr sym = {};
4951 auto result = NodeOp::create(builder, initializer,
id,
4952 NameKindEnum::InterestingName, annotations, sym);
4953 return moduleContext.addSymbolEntry(
id, result.getResult(),
4958ParseResult FIRStmtParser::parseWire() {
4959 auto startTok = consumeToken(FIRToken::kw_wire);
4963 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4968 if (parseId(
id,
"expected wire name") ||
4969 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4970 parseType(type,
"expected wire type") || parseOptionalInfo())
4973 locationProcessor.setLoc(startTok.getLoc());
4975 auto annotations = getConstants().emptyArrayAttr;
4976 StringAttr sym = {};
4979 auto namekind = isa<PropertyType, RefType>(type)
4980 ? NameKindEnum::DroppableName
4981 : NameKindEnum::InterestingName;
4983 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
4984 return moduleContext.addSymbolEntry(
id, result.getResult(),
4998ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
4999 auto startTok = consumeToken(FIRToken::kw_reg);
5003 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5012 if (parseId(
id,
"expected reg name") ||
5013 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5015 parseToken(FIRToken::comma,
"expected ','") ||
5016 parseExp(clock,
"expected expression for register clock"))
5019 if (!type_isa<FIRRTLBaseType>(type))
5020 return emitError(startTok.getLoc(),
"register must have base type");
5023 Value resetSignal, resetValue;
5024 if (consumeIf(FIRToken::kw_with)) {
5025 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5028 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5036 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5038 auto indent = getIndentation();
5039 if (!indent || *indent <= regIndent)
5040 if (!hasExtraLParen)
5041 return emitError(
"expected indented reset specifier in reg"), failure();
5043 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5044 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5045 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5046 parseExp(resetSignal,
"expected expression for reset signal") ||
5047 parseToken(FIRToken::comma,
"expected ','"))
5055 if (getTokenSpelling() ==
id) {
5057 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5059 resetSignal = Value();
5061 if (parseExp(resetValue,
"expected expression for reset value") ||
5062 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5066 if (hasExtraLParen &&
5067 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5073 if (parseOptionalInfo())
5076 locationProcessor.setLoc(startTok.getLoc());
5078 ArrayAttr annotations = getConstants().emptyArrayAttr;
5080 StringAttr sym = {};
5083 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5084 NameKindEnum::InterestingName, annotations, sym)
5087 result = RegOp::create(builder, type, clock,
id,
5088 NameKindEnum::InterestingName, annotations, sym)
5090 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5098ParseResult FIRStmtParser::parseRegisterWithReset() {
5099 auto startTok = consumeToken(FIRToken::kw_regreset);
5103 Value clock, resetSignal, resetValue;
5105 if (parseId(
id,
"expected reg name") ||
5106 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5108 parseToken(FIRToken::comma,
"expected ','") ||
5109 parseExp(clock,
"expected expression for register clock") ||
5110 parseToken(FIRToken::comma,
"expected ','") ||
5111 parseExp(resetSignal,
"expected expression for register reset") ||
5112 parseToken(FIRToken::comma,
"expected ','") ||
5113 parseExp(resetValue,
"expected expression for register reset value") ||
5114 parseOptionalInfo())
5117 if (!type_isa<FIRRTLBaseType>(type))
5118 return emitError(startTok.getLoc(),
"register must have base type");
5120 locationProcessor.setLoc(startTok.getLoc());
5123 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5124 NameKindEnum::InterestingName,
5125 getConstants().emptyArrayAttr, StringAttr{})
5128 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5133ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5137 auto startTok = consumeToken(FIRToken::kw_contract);
5140 SmallVector<StringRef> ids;
5141 SmallVector<SMLoc> locs;
5142 SmallVector<Value> values;
5143 SmallVector<Type> types;
5144 if (!consumeIf(FIRToken::colon)) {
5145 auto parseContractId = [&] {
5147 locs.push_back(getToken().
getLoc());
5148 if (parseId(
id,
"expected contract result name"))
5153 auto parseContractValue = [&] {
5155 if (parseExp(value,
"expected expression for contract result"))
5157 values.push_back(value);
5158 types.push_back(value.getType());
5161 if (parseListUntil(FIRToken::equal, parseContractId) ||
5162 parseListUntil(FIRToken::colon, parseContractValue))
5165 if (parseOptionalInfo())
5169 if (ids.size() != values.size())
5170 return emitError(startTok.getLoc())
5171 <<
"contract requires same number of results and expressions; got "
5172 << ids.size() <<
" results and " << values.size()
5173 <<
" expressions instead";
5175 locationProcessor.setLoc(startTok.getLoc());
5179 auto contract = ContractOp::create(builder, types, values);
5180 auto &block = contract.getBody().emplaceBlock();
5184 FIRModuleContext::ContextScope scope(moduleContext, &block);
5185 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5186 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5187 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5190 if (getIndentation() > blockIndent)
5191 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5196 for (
auto [
id, loc, value, result] :
5197 llvm::zip(ids, locs, values, contract.getResults())) {
5199 moduleContext.removeSymbolEntry(
id);
5200 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5213struct FIRCircuitParser :
public FIRParser {
5214 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5216 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5219 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5220 mlir::TimingScope &ts);
5225 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5226 SmallVectorImpl<Attribute> &attrs);
5228 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5230 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5231 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5232 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5233 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5234 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5235 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5236 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5238 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5240 ParseResult parseLayerName(SymbolRefAttr &result);
5241 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5242 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5243 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5244 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5245 ParseResult parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5246 ArrayAttr &knownLayers);
5248 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5249 SmallVectorImpl<SMLoc> &resultPortLocs,
5252 ParseResult parseRefList(ArrayRef<PortInfo> portList,
5253 ArrayAttr &internalPathsResult);
5255 ParseResult skipToModuleEnd(
unsigned indent);
5257 ParseResult parseTypeDecl();
5259 ParseResult parseOptionDecl(CircuitOp circuit);
5261 ParseResult parseLayer(CircuitOp circuit);
5263 struct DeferredModuleToParse {
5264 FModuleLike moduleOp;
5265 SmallVector<SMLoc> portLocs;
5270 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5271 DeferredModuleToParse &deferredModule,
5272 InnerSymFixups &fixups);
5274 SmallVector<DeferredModuleToParse, 0> deferredModules;
5276 SmallVector<InnerSymFixups, 0> moduleFixups;
5280 ModuleOp mlirModule;
5285FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5286 SmallVectorImpl<Attribute> &attrs) {
5288 auto annotations = json::parse(annotationsStr);
5289 if (
auto err = annotations.takeError()) {
5290 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5291 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5292 diag.attachNote() << a.message();
5297 json::Path::Root root;
5298 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5301 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5302 std::string jsonErrorMessage =
5303 "See inline comments for problem area in JSON:\n";
5304 llvm::raw_string_ostream s(jsonErrorMessage);
5305 root.printErrorContext(annotations.get(), s);
5306 diag.attachNote() << jsonErrorMessage;
5313ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5314 auto *context = getContext();
5315 SmallVector<StringRef> strings;
5318 if (parseId(name,
"expected layer name"))
5320 strings.push_back(name);
5321 }
while (consumeIf(FIRToken::period));
5323 SmallVector<FlatSymbolRefAttr> nested;
5324 nested.reserve(strings.size() - 1);
5325 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5326 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5328 result = SymbolRefAttr::get(context, strings[0], nested);
5332ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5333 SmallVector<Attribute> enabledLayersBuffer;
5335 auto tokenKind = getToken().getKind();
5337 if (tokenKind == FIRToken::kw_enablelayer) {
5338 if (parseEnableLayerSpec(enabledLayersBuffer))
5346 if (enabledLayersBuffer.size() != 0)
5347 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5350 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5354ParseResult FIRCircuitParser::parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5355 ArrayAttr &knownLayers) {
5356 SmallVector<Attribute> enabledLayersBuffer;
5357 SmallVector<Attribute> knownLayersBuffer;
5359 auto tokenKind = getToken().getKind();
5361 if (tokenKind == FIRToken::kw_enablelayer) {
5362 if (parseEnableLayerSpec(enabledLayersBuffer))
5367 if (tokenKind == FIRToken::kw_knownlayer) {
5368 if (parseKnownLayerSpec(knownLayersBuffer))
5376 if (enabledLayersBuffer.size() != 0)
5377 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5380 if (knownLayersBuffer.size() != 0)
5381 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5384 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5385 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5390FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5392 SymbolRefAttr layer;
5393 if (parseLayerName(layer))
5395 result.push_back(layer);
5396 }
while (consumeIf(FIRToken::comma));
5401FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5402 consumeToken(FIRToken::kw_enablelayer);
5403 return parseLayerList(result);
5407FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5408 consumeToken(FIRToken::kw_knownlayer);
5409 return parseLayerList(result);
5416FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5417 SmallVectorImpl<SMLoc> &resultPortLocs,
5420 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5422 getIndentation() > indent) {
5428 auto backtrackState = getLexer().getCursor();
5430 bool isOutput = getToken().is(FIRToken::kw_output);
5435 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5436 !getToken().isKeyword()) {
5437 backtrackState.restore(getLexer());
5444 if (parseId(name,
"expected port name") ||
5445 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5446 parseType(type,
"expected a type in port declaration") ||
5447 info.parseOptionalInfo())
5450 StringAttr innerSym = {};
5451 resultPorts.push_back(
5453 resultPortLocs.push_back(
info.getFIRLoc());
5458 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5459 PortInfo &port = std::get<0>(portAndLoc);
5460 auto &entry = portIds[port.
name];
5461 if (!entry.isValid()) {
5462 entry = std::get<1>(portAndLoc);
5466 emitError(std::get<1>(portAndLoc),
5467 "redefinition of name '" + port.
getName() +
"'")
5468 .attachNote(translateLocation(entry))
5469 <<
"previous definition here";
5478ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
5479 ArrayAttr &internalPathsResult) {
5480 struct RefStatementInfo {
5482 InternalPathAttr resolvedPath;
5486 SmallVector<RefStatementInfo> refStatements;
5487 SmallPtrSet<StringAttr, 8> seenNames;
5488 SmallPtrSet<StringAttr, 8> seenRefs;
5491 if (getToken().is(FIRToken::kw_ref) &&
5492 (requireFeature({2, 0, 0},
"ref statements") ||
5493 removedFeature({4, 0, 0},
"ref statements")))
5497 while (consumeIf(FIRToken::kw_ref)) {
5498 auto loc = getToken().getLoc();
5502 if (parseId(refName,
"expected ref name"))
5504 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
5506 loc,
"ref statements for aggregate elements not yet supported");
5507 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
5510 if (!seenRefs.insert(refName).second)
5511 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
5514 auto kind = getToken().getKind();
5515 if (kind != FIRToken::string)
5516 return emitError(loc,
"expected string in ref statement");
5517 auto resolved = InternalPathAttr::get(
5519 StringAttr::get(getContext(), getToken().getStringValue()));
5520 consumeToken(FIRToken::string);
5522 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
5526 SmallVector<Attribute> internalPaths(portList.size(),
5527 InternalPathAttr::get(getContext()));
5529 llvm::SmallBitVector usedRefs(refStatements.size());
5530 size_t matchedPaths = 0;
5531 for (
auto [idx, port] :
llvm::enumerate(portList)) {
5532 if (!type_isa<RefType>(port.
type))
5538 return mlir::emitError(
5540 "references in ports must be output on extmodule and intmodule");
5542 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
5543 return r.refName == pname;
5546 if (refStmtIt == refStatements.end()) {
5547 if (!refStatements.empty())
5548 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
5553 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
5554 internalPaths[idx] = refStmtIt->resolvedPath;
5558 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
5559 assert(matchedPaths < refStatements.size());
5561 auto idx = usedRefs.find_first_unset();
5563 return emitError(refStatements[idx].loc,
"unused ref statement");
5567 internalPathsResult = ArrayAttr::get(getContext(), internalPaths);
5573ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5575 switch (getToken().getKind()) {
5579 case FIRToken::error:
5583 case FIRToken::kw_class:
5584 case FIRToken::kw_declgroup:
5585 case FIRToken::kw_extclass:
5586 case FIRToken::kw_extmodule:
5587 case FIRToken::kw_intmodule:
5588 case FIRToken::kw_formal:
5589 case FIRToken::kw_module:
5590 case FIRToken::kw_public:
5591 case FIRToken::kw_layer:
5592 case FIRToken::kw_option:
5593 case FIRToken::kw_simulation:
5594 case FIRToken::kw_type:
5598 if (getIndentation() == indent)
5610ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5611 SmallVector<Attribute, 8> parameters;
5612 SmallPtrSet<StringAttr, 8> seen;
5613 while (consumeIf(FIRToken::kw_parameter)) {
5617 if (parseParameter(name, value, loc))
5619 auto typedValue = dyn_cast<TypedAttr>(value);
5621 return emitError(loc)
5622 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5623 if (!seen.insert(name).second)
5624 return emitError(loc,
5625 "redefinition of parameter '" + name.getValue() +
"'");
5626 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5628 resultParameters = ArrayAttr::get(getContext(), parameters);
5633ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5635 SmallVector<PortInfo, 8> portList;
5636 SmallVector<SMLoc> portLocs;
5642 consumeToken(FIRToken::kw_class);
5643 if (parseId(name,
"expected class name") ||
5644 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5648 if (name == circuit.getName())
5649 return mlir::emitError(
info.getLoc(),
5650 "class cannot be the top of a circuit");
5652 for (
auto &portInfo : portList)
5654 return
mlir::emitError(portInfo.loc,
5655 "ports on classes must be properties");
5658 auto builder = circuit.getBodyBuilder();
5659 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5660 classOp.setPrivate();
5661 deferredModules.emplace_back(
5662 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5665 getConstants().classMap[name.getValue()] = classOp;
5666 return skipToModuleEnd(indent);
5670ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5673 SmallVector<PortInfo, 8> portList;
5674 SmallVector<SMLoc> portLocs;
5680 consumeToken(FIRToken::kw_extclass);
5681 if (parseId(name,
"expected extclass name") ||
5682 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5686 if (name == circuit.getName())
5687 return mlir::emitError(
info.getLoc(),
5688 "extclass cannot be the top of a circuit");
5690 for (
auto &portInfo : portList)
5692 return
mlir::emitError(portInfo.loc,
5693 "ports on extclasses must be properties");
5696 auto builder = circuit.getBodyBuilder();
5697 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5700 getConstants().classMap[name.getValue()] = extClassOp;
5701 return skipToModuleEnd(indent);
5708ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5711 ArrayAttr enabledLayers;
5712 ArrayAttr knownLayers;
5713 SmallVector<PortInfo, 8> portList;
5714 SmallVector<SMLoc> portLocs;
5716 consumeToken(FIRToken::kw_extmodule);
5717 if (parseId(name,
"expected extmodule name") ||
5718 parseExtModuleLayerSpec(enabledLayers, knownLayers) ||
5719 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5724 if (consumeIf(FIRToken::kw_defname)) {
5725 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5726 parseId(defName,
"expected defname name"))
5730 ArrayAttr parameters;
5731 ArrayAttr internalPaths;
5736 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5737 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5738 if (ftype.hasUninferredWidth())
5739 return emitError(loc,
"extmodule port must have known width");
5744 auto builder = circuit.getBodyBuilder();
5745 auto isMainModule = (name == circuit.getName());
5747 (isMainModule && getConstants().options.scalarizePublicModules) ||
5748 getConstants().options.scalarizeExtModules
5749 ? Convention::Scalarized
5750 : Convention::Internal;
5751 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5752 auto annotations = ArrayAttr::get(getContext(), {});
5753 auto extModuleOp = FExtModuleOp::create(
5754 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5755 defName, annotations, parameters, internalPaths, enabledLayers);
5756 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5757 : SymbolTable::Visibility::Private;
5758 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5766ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5770 ArrayAttr enabledLayers;
5771 SmallVector<PortInfo, 8> portList;
5772 SmallVector<SMLoc> portLocs;
5774 consumeToken(FIRToken::kw_intmodule);
5775 if (parseId(name,
"expected intmodule name") ||
5776 parseModuleLayerSpec(enabledLayers) ||
5777 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5779 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5780 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5781 parseId(intName,
"expected intrinsic name"))
5784 ArrayAttr parameters;
5785 ArrayAttr internalPaths;
5789 ArrayAttr annotations = getConstants().emptyArrayAttr;
5790 auto builder = circuit.getBodyBuilder();
5791 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5792 annotations, parameters, internalPaths, enabledLayers)
5798ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5801 SmallVector<PortInfo, 8> portList;
5802 SmallVector<SMLoc> portLocs;
5803 ArrayAttr enabledLayers;
5804 auto modLoc = getToken().getLoc();
5805 LocWithInfo
info(modLoc,
this);
5806 consumeToken(FIRToken::kw_module);
5807 if (parseId(name,
"expected module name") ||
5808 parseModuleLayerSpec(enabledLayers) ||
5809 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5814 if (name == circuit.getName()) {
5815 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5820 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5821 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5822 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5823 if (ftype.hasUninferredWidth())
5824 return emitError(loc,
"public module port must have known width");
5825 if (ftype.hasUninferredReset())
5826 return emitError(loc,
5827 "public module port must have concrete reset type");
5832 ArrayAttr annotations = getConstants().emptyArrayAttr;
5833 auto convention = Convention::Internal;
5834 if (isPublic && getConstants().options.scalarizePublicModules)
5835 convention = Convention::Scalarized;
5836 if (!isPublic && getConstants().options.scalarizeInternalModules)
5837 convention = Convention::Scalarized;
5838 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5839 auto builder = circuit.getBodyBuilder();
5841 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
5842 annotations, enabledLayers);
5844 auto visibility = isPublic ? SymbolTable::Visibility::Public
5845 : SymbolTable::Visibility::Private;
5846 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5850 deferredModules.emplace_back(DeferredModuleToParse{
5851 moduleOp, portLocs, getLexer().getCursor(), indent});
5853 if (skipToModuleEnd(indent))
5859ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5860 consumeToken(FIRToken::kw_formal);
5861 return parseFormalLike<FormalOp>(circuit, indent);
5865ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5867 consumeToken(FIRToken::kw_simulation);
5868 return parseFormalLike<SimulationOp>(circuit, indent);
5875ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5877 StringRef id, moduleName;
5880 auto builder = circuit.getBodyBuilder();
5883 if (parseId(
id,
"expected test name") ||
5884 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5885 parseId(moduleName,
"expected module name"))
5889 NamedAttrList params;
5890 if (consumeIf(FIRToken::comma)) {
5892 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5893 return emitError(
"expected 'bound' after ','");
5895 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5896 parseIntLit(bound,
"expected integer bound after '='"))
5899 return emitError(
"bound must be a positive integer");
5900 if (
info.parseOptionalInfo())
5902 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5905 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5906 info.parseOptionalInfo())
5908 while (getIndentation() > indent) {
5909 StringAttr paramName;
5910 Attribute paramValue;
5912 if (parseParameter(paramName, paramValue, paramLoc,
5915 if (params.set(paramName, paramValue))
5916 return emitError(paramLoc,
"redefinition of parameter '" +
5917 paramName.getValue() +
"'");
5921 Op::create(builder,
info.getLoc(),
id, moduleName,
5922 params.getDictionary(getContext()));
5926ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5928 switch (getToken().getKind()) {
5929 case FIRToken::kw_class:
5930 return parseClass(circuit, indent);
5931 case FIRToken::kw_declgroup:
5932 if (requireFeature({3, 2, 0},
"optional groups") ||
5933 removedFeature({3, 3, 0},
"optional groups"))
5935 return parseLayer(circuit);
5936 case FIRToken::kw_extclass:
5937 return parseExtClass(circuit, indent);
5938 case FIRToken::kw_extmodule:
5939 return parseExtModule(circuit, indent);
5940 case FIRToken::kw_formal:
5941 if (requireFeature({4, 0, 0},
"formal tests"))
5943 return parseFormal(circuit, indent);
5944 case FIRToken::kw_intmodule:
5945 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
5946 removedFeature({4, 0, 0},
"intrinsic modules"))
5948 return parseIntModule(circuit, indent);
5949 case FIRToken::kw_layer:
5950 if (requireFeature({3, 3, 0},
"layers"))
5952 return parseLayer(circuit);
5953 case FIRToken::kw_module:
5954 return parseModule(circuit,
false, indent);
5955 case FIRToken::kw_public:
5956 if (requireFeature({3, 3, 0},
"public modules"))
5959 if (getToken().getKind() == FIRToken::kw_module)
5960 return parseModule(circuit,
true, indent);
5961 return emitError(getToken().
getLoc(),
"only modules may be public");
5962 case FIRToken::kw_simulation:
5965 return parseSimulation(circuit, indent);
5966 case FIRToken::kw_type:
5967 return parseTypeDecl();
5968 case FIRToken::kw_option:
5971 return parseOptionDecl(circuit);
5973 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
5978ParseResult FIRCircuitParser::parseTypeDecl() {
5982 auto loc = getToken().getLoc();
5984 if (getToken().isKeyword())
5985 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5986 <<
"' for type alias name";
5988 if (parseId(
id,
"expected type name") ||
5989 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5992 auto name = StringAttr::get(type.getContext(),
id);
5995 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5996 type = BaseTypeAliasType::get(name, base);
5999 <<
"type alias for non-base type " << type
6000 <<
" is currently not supported. Type alias is stripped immediately";
6002 if (!getConstants().aliasMap.insert({id, type}).second)
6003 return emitError(loc) <<
"type alias `" << name.getValue()
6004 <<
"` is already defined";
6009ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6012 auto loc = getToken().getLoc();
6015 if (parseId(
id,
"expected an option group name") ||
6016 parseToken(FIRToken::colon,
6017 "expected ':' after option group definition") ||
6018 info.parseOptionalInfo())
6021 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6022 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6023 auto *block =
new Block;
6024 optionOp.getBody().push_back(block);
6025 builder.setInsertionPointToEnd(block);
6027 auto baseIndent = getIndentation();
6029 while (getIndentation() == baseIndent) {
6031 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6032 if (parseId(
id,
"expected an option case ID") ||
6033 caseInfo.parseOptionalInfo())
6036 if (!cases.insert(
id).second)
6037 return emitError(loc)
6038 <<
"duplicate option case definition '" <<
id <<
"'";
6040 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6047ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6048 auto baseIndent = getIndentation();
6051 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6054 auto parseOne = [&](
Block *block) -> ParseResult {
6055 auto indent = getIndentation();
6056 StringRef id, convention;
6059 if (parseId(
id,
"expected layer name") ||
6060 parseToken(FIRToken::comma,
"expected ','") ||
6061 parseGetSpelling(convention))
6064 auto layerConvention = symbolizeLayerConvention(convention);
6065 if (!layerConvention) {
6066 emitError() <<
"unknown convention '" << convention
6067 <<
"' (did you misspell it?)";
6070 if (layerConvention == LayerConvention::Inline &&
6071 requireFeature({4, 1, 0},
"inline layers"))
6075 hw::OutputFileAttr outputDir;
6076 if (consumeIf(FIRToken::comma)) {
6077 if (getToken().getKind() == FIRToken::string) {
6078 auto text = getToken().getStringValue();
6080 return emitError() <<
"output directory must not be blank";
6081 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6082 consumeToken(FIRToken::string);
6086 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6087 info.parseOptionalInfo())
6089 auto builder = OpBuilder::atBlockEnd(block);
6092 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6093 layerOp->getRegion(0).push_back(
new Block());
6095 layerOp->setAttr(
"output_file", outputDir);
6096 layerStack.push_back({indent, layerOp});
6100 if (parseOne(circuit.getBodyBlock()))
6104 while (getIndentation() > baseIndent) {
6105 switch (getToken().getKind()) {
6106 case FIRToken::kw_declgroup:
6107 case FIRToken::kw_layer: {
6110 while (layerStack.back().first >= getIndentation())
6111 layerStack.pop_back();
6112 auto parentLayer = layerStack.back().second;
6113 if (parseOne(&parentLayer.getBody().front()))
6118 return emitError(
"expected 'layer'"), failure();
6127FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6128 DeferredModuleToParse &deferredModule,
6129 InnerSymFixups &fixups) {
6130 FModuleLike moduleOp = deferredModule.moduleOp;
6131 auto &body = moduleOp->getRegion(0).front();
6132 auto &portLocs = deferredModule.portLocs;
6136 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6139 deferredModule.lexerCursor.restore(moduleBodyLexer);
6141 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6146 auto portList = moduleOp.getPorts();
6147 auto portArgs = body.getArguments();
6148 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6149 PortInfo &port = std::get<0>(tuple);
6150 llvm::SMLoc loc = std::get<1>(tuple);
6151 BlockArgument portArg = std::get<2>(tuple);
6153 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6157 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6160 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6166 size_t numVerifPrintfs = 0;
6167 std::optional<Location> printfLoc;
6169 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6174 printfLoc = printFOp.getLoc();
6177 if (numVerifPrintfs > 0) {
6179 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6181 <<
" printf-encoded verification operation(s), which are no longer "
6183 diag.attachNote(*printfLoc)
6184 <<
"example printf here, this is now just a printf and nothing more";
6185 diag.attachNote() <<
"For more information, see "
6186 "https://github.com/llvm/circt/issues/6970";
6200ParseResult FIRCircuitParser::parseCircuit(
6201 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6202 mlir::TimingScope &ts) {
6204 auto indent = getIndentation();
6205 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6207 if (!indent.has_value())
6208 return emitError(
"'FIRRTL' must be first token on its line");
6209 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6210 parseVersionLit(
"expected version literal"))
6212 indent = getIndentation();
6214 if (!indent.has_value())
6215 return emitError(
"'circuit' must be first token on its line");
6216 unsigned circuitIndent = *indent;
6220 SMLoc inlineAnnotationsLoc;
6221 StringRef inlineAnnotations;
6224 if (parseToken(FIRToken::kw_circuit,
6225 "expected a top-level 'circuit' definition") ||
6226 parseId(name,
"expected circuit name") ||
6227 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6228 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6229 info.parseOptionalInfo())
6233 OpBuilder b(mlirModule.getBodyRegion());
6234 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6237 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6243 SmallVector<Attribute> annos;
6244 if (!inlineAnnotations.empty())
6245 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6249 for (
auto *annotationsBuf : annotationsBufs)
6250 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6254 parseAnnotationTimer.stop();
6262 auto parseTimer = ts.nest(
"Parse modules");
6263 deferredModules.reserve(16);
6267 switch (getToken().getKind()) {
6275 case FIRToken::error:
6279 emitError(
"unexpected token in circuit");
6282 case FIRToken::kw_class:
6283 case FIRToken::kw_declgroup:
6284 case FIRToken::kw_extclass:
6285 case FIRToken::kw_extmodule:
6286 case FIRToken::kw_intmodule:
6287 case FIRToken::kw_layer:
6288 case FIRToken::kw_formal:
6289 case FIRToken::kw_module:
6290 case FIRToken::kw_option:
6291 case FIRToken::kw_public:
6292 case FIRToken::kw_simulation:
6293 case FIRToken::kw_type: {
6294 auto indent = getIndentation();
6295 if (!indent.has_value())
6296 return emitError(
"'module' must be first token on its line"), failure();
6297 unsigned definitionIndent = *indent;
6299 if (definitionIndent <= circuitIndent)
6300 return emitError(
"module should be indented more"), failure();
6302 if (parseToplevelDefinition(circuit, definitionIndent))
6316 (void)getLexer().translateLocation(
info.getFIRLoc());
6322 DenseMap<Attribute, Location> nameToOrigLoc;
6326 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6331 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6334 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6335 .attachNote(it.first->second)
6336 .append(
"see existing symbol definition here");
6342 SymbolTable circuitSymTbl(circuit);
6344 moduleFixups.resize(deferredModules.size());
6349 for (
auto &d : deferredModules)
6350 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6353 auto anyFailed = mlir::failableParallelForEachN(
6354 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6355 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6356 moduleFixups[index]))
6360 if (failed(anyFailed))
6365 for (
auto &fixups : moduleFixups) {
6366 if (failed(fixups.resolve(innerSymbolNamespaces)))
6372 auto parseLayerName = [&](StringRef name) -> Attribute {
6374 auto [head, rest] = name.split(
".");
6375 SmallVector<FlatSymbolRefAttr> nestedRefs;
6376 while (!rest.empty()) {
6378 std::tie(next, rest) = rest.split(
".");
6379 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6381 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6384 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6385 SmallVector<Attribute> attrArray;
6386 auto *context = getContext();
6387 for (
const auto &str : strArray)
6388 attrArray.push_back(getAttr(str));
6389 if (attrArray.empty())
6391 return ArrayAttr::get(context, attrArray);
6394 if (
auto enableLayers =
6395 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6396 circuit.setEnableLayersAttr(enableLayers);
6397 if (
auto disableLayers =
6398 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6399 circuit.setDisableLayersAttr(disableLayers);
6401 auto getStrAttr = [&](StringRef str) -> Attribute {
6402 return StringAttr::get(getContext(), str);
6405 if (
auto selectInstChoice =
6406 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6407 circuit.setSelectInstChoiceAttr(selectInstChoice);
6409 circuit.setDefaultLayerSpecialization(
6410 getConstants().options.defaultLayerSpecialization);
6423 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6424 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6425 unsigned fileID = 1;
6427 annotationsBufs.push_back(
6428 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6430 context->loadDialect<CHIRRTLDialect>();
6431 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6435 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6438 SharedParserConstants state(context, options);
6439 FIRLexer lexer(sourceMgr, context);
6441 .parseCircuit(annotationsBufs, ts))
6446 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6447 if (failed(verify(*module)))
6454 static mlir::TranslateToMLIRRegistration fromFIR(
6455 "import-firrtl",
"import .fir",
6456 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6457 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
bool isRecognizedPrintfEncodedVerif(PrintFOp printOp)
Classifier for legacy verif intent captured in printf + when's.
constexpr FIRVersion nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
The FIRRTL specification version.
This holds the name and type that describes the module's ports.
bool isOutput() const
Return true if this is a simple output-only port.
StringRef getName() const