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/LogicalResult.h"
44#include "llvm/Support/SourceMgr.h"
45#include "llvm/Support/raw_ostream.h"
50using namespace firrtl;
51using namespace chirrtl;
55using mlir::LocationAttr;
68struct SharedParserConstants {
72 loIdentifier(StringAttr::get(
context,
"lo")),
73 hiIdentifier(StringAttr::get(
context,
"hi")),
74 amountIdentifier(StringAttr::get(
context,
"amount")),
76 hw::InnerRefAttr::get(StringAttr::get(
context,
"module"),
77 StringAttr::get(
context,
"placeholder"))) {}
86 llvm::StringMap<FIRRTLType> aliasMap;
89 llvm::DenseMap<StringRef, ClassLike> classMap;
92 const ArrayAttr emptyArrayAttr;
95 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
98 const hw::InnerRefAttr placeholderInnerRef;
101 SharedParserConstants(
const SharedParserConstants &) =
delete;
102 void operator=(
const SharedParserConstants &) =
delete;
115 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
117 : version(version), constants(constants), lexer(lexer),
118 locatorFilenameCache(constants.loIdentifier ) {
122 SharedParserConstants &getConstants()
const {
return constants; }
123 MLIRContext *getContext()
const {
return constants.context; }
125 FIRLexer &getLexer() {
return lexer; }
128 std::optional<unsigned> getIndentation()
const {
133 const FIRToken &getToken()
const {
return lexer.getToken(); }
134 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
141 InFlightDiagnostic emitError(
const Twine &message = {}) {
142 return emitError(getToken().
getLoc(), message);
144 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
147 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
148 return emitWarning(getToken().
getLoc(), message);
151 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
161 Location translateLocation(llvm::SMLoc loc) {
162 return lexer.translateLocation(loc);
167 ParseResult parseOptionalInfoLocator(LocationAttr &result);
171 ParseResult parseOptionalName(StringAttr &name);
177 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
178 return requireFeature(minimum, feature, getToken().
getLoc());
181 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
182 if (version < minimum)
183 return emitError(loc)
184 << feature <<
" are a FIRRTL " << minimum
185 <<
"+ feature, but the specified FIRRTL version was " << version;
189 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
190 return removedFeature(removedVersion, feature, getToken().
getLoc());
193 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
195 if (version >= removedVersion)
196 return emitError(loc)
197 << feature <<
" were removed in FIRRTL " << removedVersion
198 <<
", but the specified FIRRTL version was " << version;
208 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
217 if (getToken().isNot(kind))
227 FIRToken consumedToken = getToken();
228 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
229 "shouldn't advance past EOF or errors");
231 return consumedToken;
240 FIRToken consumedToken = getToken();
241 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
243 return consumedToken;
248 ParseResult parseGetSpelling(StringRef &spelling) {
249 spelling = getTokenSpelling();
255 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
260 const std::function<ParseResult()> &parseElement);
267 ParseResult parseIntLit(APInt &result,
const Twine &message);
268 ParseResult parseIntLit(int64_t &result,
const Twine &message);
269 ParseResult parseIntLit(int32_t &result,
const Twine &message);
272 ParseResult parseVersionLit(
const Twine &message);
275 template <
typename T>
276 ParseResult parseOptionalWidth(T &result);
279 ParseResult parseId(StringRef &result,
const Twine &message);
280 ParseResult parseId(StringAttr &result,
const Twine &message);
281 ParseResult parseFieldId(StringRef &result,
const Twine &message);
282 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
283 const Twine &message);
284 ParseResult parseEnumType(
FIRRTLType &result);
285 ParseResult parseListType(
FIRRTLType &result);
288 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
290 ParseResult parseRUW(RUWBehavior &result);
291 ParseResult parseOptionalRUW(RUWBehavior &result);
293 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
294 SMLoc &resultLoc,
bool allowAggregates =
false);
295 ParseResult parseParameterValue(Attribute &resultValue,
296 bool allowAggregates =
false);
302 FIRParser(
const FIRParser &) =
delete;
303 void operator=(
const FIRParser &) =
delete;
307 SharedParserConstants &constants;
311 StringAttr locatorFilenameCache;
313 FileLineColLoc fileLineColLocCache;
322InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
323 auto diag = mlir::emitError(translateLocation(loc), message);
327 if (getToken().is(FIRToken::error))
332InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
333 return mlir::emitWarning(translateLocation(loc), message);
343 const Twine &message) {
344 if (consumeIf(expectedToken))
346 return emitError(message);
353 const std::function<ParseResult()> &parseElement) {
354 if (consumeIf(rightToken))
360 while (consumeIf(FIRToken::comma)) {
365 if (parseToken(rightToken,
"expected ','"))
397 if (failed(
parser->parseOptionalInfoLocator(loc)))
401 switch (
parser->constants.options.infoLocatorHandling) {
402 case ILH::IgnoreInfo:
403 assert(0 &&
"Should not return info locations if ignoring");
405 case ILH::PreferInfo:
409 infoLoc = FusedLoc::get(loc.getContext(),
410 {loc, parser->translateLocation(firLoc)});
437ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
438 if (getToken().isNot(FIRToken::fileinfo))
441 auto loc = getToken().getLoc();
443 auto spelling = getTokenSpelling();
444 consumeToken(FIRToken::fileinfo);
448 constants.options.infoLocatorHandling ==
449 FIRParserOptions::InfoLocHandling::IgnoreInfo,
450 locatorFilenameCache, fileLineColLocCache, getContext());
453 if (!locationPair.first) {
454 mlir::emitWarning(translateLocation(loc),
455 "ignoring unknown @ info record format");
461 if (locationPair.first && constants.options.infoLocatorHandling ==
462 FIRParserOptions::InfoLocHandling::IgnoreInfo)
466 result = *locationPair.second;
474ParseResult FIRParser::parseOptionalName(StringAttr &name) {
476 if (getToken().isNot(FIRToken::colon)) {
477 name = StringAttr::get(getContext(),
"");
481 consumeToken(FIRToken::colon);
483 if (parseId(nameRef,
"expected result name"))
486 name = StringAttr::get(getContext(), nameRef);
497ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
499 if (getToken().isNot(FIRToken::inlineannotation))
502 loc = getToken().getLoc();
504 result = getTokenSpelling().drop_front(2).drop_back(1);
505 consumeToken(FIRToken::inlineannotation);
523ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
524 auto spelling = getTokenSpelling();
525 bool isNegative =
false;
526 switch (getToken().getKind()) {
527 case FIRToken::signed_integer:
528 isNegative = spelling[0] ==
'-';
529 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
530 spelling = spelling.drop_front();
532 case FIRToken::integer:
533 if (spelling.getAsInteger(10, result))
534 return emitError(message), failure();
538 if (result.isNegative())
539 result = result.zext(result.getBitWidth() + 1);
548 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
549 result = result.trunc(32);
553 case FIRToken::radix_specified_integer: {
554 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
556 if (spelling[0] ==
'-') {
558 spelling = spelling.drop_front();
560 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
565 spelling = spelling.drop_front(2);
566 if (spelling.getAsInteger(base, result))
567 return emitError(
"invalid character in integer literal"), failure();
568 if (result.isNegative())
569 result = result.zext(result.getBitWidth() + 1);
575 case FIRToken::string: {
578 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
581 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
582 spelling = spelling.drop_back().drop_front();
586 switch (spelling.empty() ?
' ' : spelling.front()) {
597 return emitError(
"expected base specifier (h/o/b) in integer literal"),
600 spelling = spelling.drop_front();
603 bool isNegative =
false;
604 if (!spelling.empty() && spelling.front() ==
'+')
605 spelling = spelling.drop_front();
606 else if (!spelling.empty() && spelling.front() ==
'-') {
608 spelling = spelling.drop_front();
612 if (spelling.empty())
613 return emitError(
"expected digits in integer literal"), failure();
615 if (spelling.getAsInteger(base, result))
616 return emitError(
"invalid character in integer literal"), failure();
621 if (result.isNegative())
622 result = result.zext(result.getBitWidth() + 1);
627 consumeToken(FIRToken::string);
632 return emitError(
"expected integer literal"), failure();
636ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
638 auto loc = getToken().getLoc();
639 if (parseIntLit(value, message))
642 result = (int64_t)value.getLimitedValue(INT64_MAX);
644 return emitError(loc,
"value is too big to handle"), failure();
648ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
650 auto loc = getToken().getLoc();
651 if (parseIntLit(value, message))
654 result = (int32_t)value.getLimitedValue(INT32_MAX);
656 return emitError(loc,
"value is too big to handle"), failure();
662ParseResult FIRParser::parseVersionLit(
const Twine &message) {
663 auto spelling = getTokenSpelling();
664 if (getToken().getKind() != FIRToken::version)
665 return emitError(message), failure();
667 auto [a, d] = spelling.split(
".");
668 auto [b, c] = d.split(
".");
669 APInt aInt, bInt, cInt;
670 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
671 c.getAsInteger(10, cInt))
672 return emitError(
"failed to parse version string"), failure();
673 version.major = aInt.getLimitedValue(UINT32_MAX);
674 version.minor = bInt.getLimitedValue(UINT32_MAX);
675 version.patch = cInt.getLimitedValue(UINT32_MAX);
676 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
677 return emitError(
"integers out of range"), failure();
681 consumeToken(FIRToken::version);
689ParseResult FIRParser::parseOptionalWidth(T &result) {
690 if (!consumeIf(FIRToken::less))
691 return result = -1, success();
694 auto widthLoc = getToken().getLoc();
695 if (parseIntLit(result,
"expected width") ||
696 parseToken(FIRToken::greater,
"expected >"))
700 return emitError(widthLoc,
"invalid width specifier"), failure();
709ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
710 switch (getToken().getKind()) {
712 case FIRToken::identifier:
713 case FIRToken::literal_identifier:
715#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
716#include "FIRTokenKinds.def"
721 if (getToken().getKind() == FIRToken::literal_identifier)
722 result = getTokenSpelling().drop_front().drop_back();
724 result = getTokenSpelling();
734ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
736 if (parseId(name, message))
739 result = StringAttr::get(getContext(), name);
748ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
750 result = getTokenSpelling();
751 if (consumeIf(FIRToken::integer))
757 if (parseId(result, message))
769ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
770 const Twine &message) {
772 StringRef tmp = getTokenSpelling();
774 if (consumeIf(FIRToken::integer)) {
775 result.push_back(tmp);
779 if (consumeIf(FIRToken::floatingpoint)) {
783 auto [a, b] = tmp.split(
".");
789 if (consumeIf(FIRToken::version)) {
791 auto [a, d] = tmp.split(
".");
792 auto [b, c] = d.split(
".");
800 if (parseId(tmp, message))
802 result.push_back(tmp);
808ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
809 if (parseToken(FIRToken::l_brace_bar,
810 "expected leading '{|' in enumeration type"))
812 SmallVector<StringAttr> names;
813 SmallVector<APInt> values;
814 SmallVector<FIRRTLBaseType> types;
815 SmallVector<SMLoc> locs;
816 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
817 auto fieldLoc = getToken().getLoc();
818 locs.push_back(fieldLoc);
822 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
824 auto name = StringAttr::get(getContext(), nameStr);
825 names.push_back(name);
831 if (consumeIf(FIRToken::equal)) {
832 if (parseIntLit(value,
"expected integer value for enumeration tag"))
834 if (value.isNegative())
835 return emitError(fieldLoc,
"enum tag value must be non-negative");
836 }
else if (values.empty()) {
842 auto &prev = values.back();
843 if (prev.isMaxValue())
844 value = prev.zext(prev.getBitWidth() + 1);
849 values.push_back(std::move(value));
853 if (consumeIf(FIRToken::colon)) {
855 if (
parseType(parsedType,
"expected enumeration type"))
857 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
859 return emitError(fieldLoc,
"field must be a base type");
862 type = UIntType::get(getContext(), 0);
864 types.push_back(type);
866 auto r = type.getRecursiveTypeProperties();
868 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
869 if (r.containsAnalog)
870 return emitError(fieldLoc)
871 <<
"enum field " << name <<
" contains analog";
872 if (r.hasUninferredWidth)
873 return emitError(fieldLoc)
874 <<
"enum field " << name <<
" has uninferred width";
875 if (r.hasUninferredReset)
876 return emitError(fieldLoc)
877 <<
"enum field " << name <<
" has uninferred reset";
883 SmallPtrSet<StringAttr, 4> nameSet;
884 for (
auto [name, loc] :
llvm::zip(names, locs))
885 if (!nameSet.insert(name).second)
886 return emitError(loc,
887 "duplicate variant name in enum: " + name.getValue());
890 unsigned bitwidth = 0;
891 for (
auto &value : values)
892 bitwidth = std::max(bitwidth, value.getActiveBits());
894 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
898 SmallPtrSet<IntegerAttr, 4> valueSet;
899 SmallVector<FEnumType::EnumElement, 4> elements;
900 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
901 auto tagValue = value.zextOrTrunc(bitwidth);
902 auto attr = IntegerAttr::get(tagType, tagValue);
904 if (!valueSet.insert(attr).second)
905 return emitError(loc,
"duplicate variant value in enum: ") << attr;
906 elements.push_back({name, attr, type});
909 llvm::sort(elements);
910 result = FEnumType::get(getContext(), elements);
914ParseResult FIRParser::parsePropertyType(
PropertyType &result,
915 const Twine &message) {
919 auto prop = type_dyn_cast<PropertyType>(type);
921 return emitError(
"expected property type");
927ParseResult FIRParser::parseListType(
FIRRTLType &result) {
928 consumeToken(FIRToken::kw_List);
931 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
932 parsePropertyType(
elementType,
"expected List element type") ||
933 parseToken(FIRToken::greater,
"expected '>' in List type"))
959ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
960 switch (getToken().getKind()) {
962 return emitError(message), failure();
964 case FIRToken::kw_Clock:
965 consumeToken(FIRToken::kw_Clock);
966 result = ClockType::get(getContext());
969 case FIRToken::kw_Inst: {
973 consumeToken(FIRToken::kw_Inst);
974 if (parseToken(FIRToken::less,
"expected < in Inst type"))
977 auto loc = getToken().getLoc();
979 if (parseId(
id,
"expected class name in Inst type"))
983 const auto &classMap = getConstants().classMap;
984 auto lookup = classMap.find(
id);
985 if (lookup == classMap.end())
986 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
988 auto classOp = lookup->second;
990 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
993 result = classOp.getInstanceType();
997 case FIRToken::kw_AnyRef: {
1001 consumeToken(FIRToken::kw_AnyRef);
1002 result = AnyRefType::get(getContext());
1006 case FIRToken::kw_Reset:
1007 consumeToken(FIRToken::kw_Reset);
1008 result = ResetType::get(getContext());
1011 case FIRToken::kw_AsyncReset:
1012 consumeToken(FIRToken::kw_AsyncReset);
1013 result = AsyncResetType::get(getContext());
1016 case FIRToken::kw_UInt:
1017 case FIRToken::kw_SInt:
1018 case FIRToken::kw_Analog: {
1019 auto kind = getToken().getKind();
1024 if (parseOptionalWidth(width))
1027 if (kind == FIRToken::kw_SInt)
1028 result = SIntType::get(getContext(), width);
1029 else if (kind == FIRToken::kw_UInt)
1030 result = UIntType::get(getContext(), width);
1032 assert(kind == FIRToken::kw_Analog);
1033 result = AnalogType::get(getContext(), width);
1038 case FIRToken::kw_Domain: {
1042 result = DomainType::get(getContext());
1046 case FIRToken::kw_Probe:
1047 case FIRToken::kw_RWProbe: {
1048 auto kind = getToken().getKind();
1049 auto loc = getToken().getLoc();
1054 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1055 parseType(type,
"expected probe data type"))
1058 SmallVector<StringRef> layers;
1059 if (consumeIf(FIRToken::comma)) {
1060 if (requireFeature({4, 0, 0},
"colored probes"))
1065 loc = getToken().getLoc();
1066 if (parseId(layer,
"expected layer name"))
1068 layers.push_back(layer);
1069 }
while (consumeIf(FIRToken::period));
1072 if (!consumeIf(FIRToken::greater))
1073 return emitError(loc,
"expected '>' to end reference type");
1075 bool forceable = kind == FIRToken::kw_RWProbe;
1077 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1079 return emitError(loc,
"invalid probe inner type, must be base-type");
1082 return emitError(loc,
"probe inner type must be passive");
1084 if (forceable &&
innerType.containsConst())
1085 return emitError(loc,
"rwprobe cannot contain const");
1087 SymbolRefAttr layer;
1088 if (!layers.empty()) {
1090 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1091 return FlatSymbolRefAttr::get(getContext(), a);
1093 layer = SymbolRefAttr::get(getContext(), layers.front(),
1094 llvm::to_vector(nestedLayers));
1097 result = RefType::get(innerType, forceable, layer);
1101 case FIRToken::l_brace: {
1102 consumeToken(FIRToken::l_brace);
1104 SmallVector<OpenBundleType::BundleElement, 4> elements;
1105 SmallPtrSet<StringAttr, 4> nameSet;
1106 bool bundleCompatible =
true;
1107 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1108 bool isFlipped = consumeIf(FIRToken::kw_flip);
1110 auto loc = getToken().getLoc();
1111 StringRef fieldNameStr;
1112 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1113 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1115 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1118 if (!nameSet.insert(fieldName).second)
1119 return emitError(loc,
"duplicate field name in bundle: " +
1120 fieldName.getValue());
1123 if (
parseType(type,
"expected bundle field type"))
1126 elements.push_back({fieldName, isFlipped, type});
1127 bundleCompatible &= isa<BundleType::ElementType>(type);
1134 if (bundleCompatible) {
1135 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1136 return BundleType::BundleElement{
1137 element.name, element.isFlip,
1138 cast<BundleType::ElementType>(element.type)};
1140 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1142 result = OpenBundleType::get(getContext(), elements);
1146 case FIRToken::l_brace_bar: {
1147 if (parseEnumType(result))
1152 case FIRToken::identifier: {
1154 auto loc = getToken().getLoc();
1155 if (parseId(
id,
"expected a type alias name"))
1157 auto it = constants.aliasMap.find(
id);
1158 if (it == constants.aliasMap.end()) {
1159 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1162 result = it->second;
1166 case FIRToken::kw_const: {
1167 consumeToken(FIRToken::kw_const);
1168 auto nextToken = getToken();
1169 auto loc = nextToken.getLoc();
1172 if (nextToken.is(FIRToken::kw_const))
1173 return emitError(loc,
"'const' can only be specified once on a type");
1178 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1180 return emitError(loc,
"only hardware types can be 'const'");
1182 result = baseType.getConstType(
true);
1186 case FIRToken::kw_String:
1187 if (requireFeature({3, 1, 0},
"Strings"))
1189 consumeToken(FIRToken::kw_String);
1190 result = StringType::get(getContext());
1192 case FIRToken::kw_Integer:
1193 if (requireFeature({3, 1, 0},
"Integers"))
1195 consumeToken(FIRToken::kw_Integer);
1196 result = FIntegerType::get(getContext());
1198 case FIRToken::kw_Bool:
1201 consumeToken(FIRToken::kw_Bool);
1202 result = BoolType::get(getContext());
1204 case FIRToken::kw_Double:
1207 consumeToken(FIRToken::kw_Double);
1208 result = DoubleType::get(getContext());
1210 case FIRToken::kw_Path:
1213 consumeToken(FIRToken::kw_Path);
1214 result = PathType::get(getContext());
1216 case FIRToken::kw_List:
1217 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1223 while (consumeIf(FIRToken::l_square)) {
1224 auto sizeLoc = getToken().getLoc();
1226 if (parseIntLit(size,
"expected width") ||
1227 parseToken(FIRToken::r_square,
"expected ]"))
1231 return emitError(sizeLoc,
"invalid size specifier"), failure();
1233 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1235 result = FVectorType::get(baseType, size);
1237 result = OpenVectorType::get(result, size);
1244ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1245 switch (getToken().getKind()) {
1247 case FIRToken::kw_old:
1248 result = RUWBehavior::Old;
1249 consumeToken(FIRToken::kw_old);
1251 case FIRToken::kw_new:
1252 result = RUWBehavior::New;
1253 consumeToken(FIRToken::kw_new);
1255 case FIRToken::kw_undefined:
1256 result = RUWBehavior::Undefined;
1257 consumeToken(FIRToken::kw_undefined);
1267ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1268 switch (getToken().getKind()) {
1272 case FIRToken::kw_old:
1273 result = RUWBehavior::Old;
1274 consumeToken(FIRToken::kw_old);
1276 case FIRToken::kw_new:
1277 result = RUWBehavior::New;
1278 consumeToken(FIRToken::kw_new);
1280 case FIRToken::kw_undefined:
1281 result = RUWBehavior::Undefined;
1282 consumeToken(FIRToken::kw_undefined);
1290ParseResult FIRParser::parseParameter(StringAttr &resultName,
1291 Attribute &resultValue, SMLoc &resultLoc,
1292 bool allowAggregates) {
1293 auto loc = getToken().getLoc();
1297 if (parseId(name,
"expected parameter name") ||
1298 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1303 if (parseParameterValue(value, allowAggregates))
1306 resultName = StringAttr::get(getContext(), name);
1307 resultValue = value;
1318ParseResult FIRParser::parseParameterValue(Attribute &value,
1319 bool allowAggregates) {
1320 mlir::Builder builder(getContext());
1321 switch (getToken().getKind()) {
1324 case FIRToken::integer:
1325 case FIRToken::signed_integer: {
1327 if (parseIntLit(result,
"invalid integer parameter"))
1333 if (result.getBitWidth() < 32)
1334 result = result.sext(32);
1336 value = builder.getIntegerAttr(
1337 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1343 case FIRToken::string: {
1345 value = builder.getStringAttr(getToken().getStringValue());
1346 consumeToken(FIRToken::string);
1351 case FIRToken::verbatim_string: {
1353 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1354 value = hw::ParamVerbatimAttr::get(text);
1355 consumeToken(FIRToken::verbatim_string);
1360 case FIRToken::floatingpoint: {
1362 if (!llvm::to_float(getTokenSpelling(), v))
1363 return emitError(
"invalid float parameter syntax"), failure();
1365 value = builder.getF64FloatAttr(v);
1366 consumeToken(FIRToken::floatingpoint);
1371 case FIRToken::l_square: {
1372 if (!allowAggregates)
1373 return emitError(
"expected non-aggregate parameter value");
1376 SmallVector<Attribute> elements;
1377 auto parseElement = [&] {
1378 return parseParameterValue(elements.emplace_back(),
1381 if (parseListUntil(FIRToken::r_square, parseElement))
1384 value = builder.getArrayAttr(elements);
1389 case FIRToken::l_brace: {
1390 if (!allowAggregates)
1391 return emitError(
"expected non-aggregate parameter value");
1394 NamedAttrList fields;
1395 auto parseField = [&]() -> ParseResult {
1396 StringAttr fieldName;
1397 Attribute fieldValue;
1399 if (parseParameter(fieldName, fieldValue, fieldLoc,
1402 if (fields.set(fieldName, fieldValue))
1403 return emitError(fieldLoc)
1404 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1407 if (parseListUntil(FIRToken::r_brace, parseField))
1410 value = fields.getDictionary(getContext());
1415 return emitError(
"expected parameter value");
1430 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1438struct UnbundledValueRestorer {
1440 size_t startingSize;
1442 startingSize = list.size();
1444 ~UnbundledValueRestorer() { list.resize(startingSize); }
1453struct FIRModuleContext :
public FIRParser {
1454 explicit FIRModuleContext(Block *topLevelBlock,
1455 SharedParserConstants &constants,
FIRLexer &lexer,
1457 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1460 template <
typename OpTy = ConstantOp,
typename... Args>
1461 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1462 Type type, Args &&...args) {
1463 auto &result = constantCache[{attr, type}];
1469 OpBuilder::InsertPoint savedIP;
1472 if (builder.getInsertionBlock() != topLevelBlock) {
1473 savedIP = builder.saveInsertionPoint();
1474 auto *block = builder.getInsertionBlock();
1476 auto *op = block->getParentOp();
1477 if (!op || !op->getBlock()) {
1479 builder.setInsertionPointToEnd(topLevelBlock);
1482 if (op->getBlock() == topLevelBlock) {
1483 builder.setInsertionPoint(op);
1486 block = op->getBlock();
1490 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1492 if (savedIP.isSet())
1493 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1504 Value &getCachedSubaccess(Value value,
unsigned index) {
1505 auto &result = subaccessCache[{value, index}];
1508 auto it = scopeMap.find(value.getParentBlock());
1509 if (it != scopeMap.end())
1510 it->second->scopedSubaccesses.push_back({result, index});
1520 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1521 bool insertNameIntoGlobalScope =
false);
1522 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1523 bool insertNameIntoGlobalScope =
false) {
1525 insertNameIntoGlobalScope);
1529 void removeSymbolEntry(StringRef name);
1533 SMLoc loc,
bool fatal =
true);
1538 StringRef field, SMLoc loc);
1546 assert(index < unbundledValues.size());
1547 return unbundledValues[index];
1557 struct ContextScope {
1558 friend struct FIRModuleContext;
1559 ContextScope(FIRModuleContext &moduleContext, Block *block)
1560 : moduleContext(moduleContext), block(block),
1561 previousScope(moduleContext.currentScope) {
1562 moduleContext.currentScope =
this;
1563 moduleContext.scopeMap[block] =
this;
1568 for (
auto *entryPtr : scopedDecls)
1569 entryPtr->second.first = SMLoc();
1572 for (
auto subaccess : scopedSubaccesses)
1573 moduleContext.subaccessCache.erase(subaccess);
1575 moduleContext.scopeMap.erase(block);
1577 moduleContext.currentScope = previousScope;
1581 void operator=(
const ContextScope &) =
delete;
1582 ContextScope(
const ContextScope &) =
delete;
1584 FIRModuleContext &moduleContext;
1586 ContextScope *previousScope;
1587 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1588 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1593 Block *topLevelBlock;
1599 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1611 DenseMap<Block *, ContextScope *> scopeMap;
1616 ContextScope *currentScope =
nullptr;
1622void FIRModuleContext::removeSymbolEntry(StringRef name) {
1623 symbolTable.erase(name);
1632ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1634 bool insertNameIntoGlobalScope) {
1637 auto [entryIt, inserted] =
1642 if (entryIt->second.first.isValid()) {
1644 emitError(loc,
"redefinition of name '" + name +
"' ")
1645 .attachNote(translateLocation(entryIt->second.first))
1646 <<
"previous definition here.";
1649 emitError(loc,
"redefinition of name '" + name +
"' ")
1650 <<
"- FIRRTL has flat namespace and requires all "
1651 <<
"declarations in a module to have unique names.";
1658 entryIt->second = {loc, entry};
1659 if (currentScope && !insertNameIntoGlobalScope)
1660 currentScope->scopedDecls.push_back(&*entryIt);
1667 StringRef name, SMLoc loc) {
1668 auto &entry = symbolTable[name];
1669 if (!entry.first.isValid())
1670 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1671 result = entry.second;
1672 assert(result &&
"name in symbol table without definition");
1676ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1678 SMLoc loc,
bool fatal) {
1679 if (!isa<Value>(entry)) {
1681 emitError(loc,
"bundle value should only be used from subfield");
1684 result = cast<Value>(entry);
1688ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1690 StringRef fieldName,
1692 if (!isa<UnbundledID>(entry)) {
1693 emitError(loc,
"value should not be used from subfield");
1697 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1699 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1700 assert(unbundledId < unbundledValues.size());
1702 for (
auto elt : ubEntry) {
1703 if (elt.first == fieldAttr) {
1704 result = elt.second;
1709 emitError(loc,
"use of invalid field name '")
1710 << fieldName <<
"' on bundle value";
1736struct LazyLocationListener :
public OpBuilder::Listener {
1737 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1738 assert(builder.getListener() ==
nullptr);
1739 builder.setListener(
this);
1742 ~LazyLocationListener() {
1743 assert(subOps.empty() &&
"didn't process parsed operations");
1744 assert(builder.getListener() ==
this);
1745 builder.setListener(
nullptr);
1748 void startStatement() {
1749 assert(!isActive &&
"Already processing a statement");
1755 void endStatement(FIRParser &parser) {
1756 assert(isActive &&
"Not parsing a statement");
1760 for (
auto opAndSMLoc : subOps) {
1764 switch (parser.getConstants().options.infoLocatorHandling) {
1765 case ILH::IgnoreInfo:
1767 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1769 case ILH::PreferInfo:
1770 opAndSMLoc.first->setLoc(infoLoc);
1772 case ILH::FusedInfo:
1773 opAndSMLoc.first->setLoc(FusedLoc::get(
1774 infoLoc.getContext(),
1775 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1782 for (
auto opAndSMLoc : subOps)
1783 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1788 infoLoc = LocationAttr();
1789 currentSMLoc = SMLoc();
1794 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1797 void setInfoLoc(LocationAttr loc) {
1798 assert(!infoLoc &&
"Info location multiply specified");
1804 void notifyOperationInserted(Operation *op,
1805 mlir::IRRewriter::InsertPoint)
override {
1806 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1807 assert(isActive &&
"Not parsing a statement");
1808 subOps.push_back({op, currentSMLoc});
1813 bool isActive =
false;
1821 LocationAttr infoLoc;
1828 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1830 void operator=(
const LazyLocationListener &) =
delete;
1831 LazyLocationListener(
const LazyLocationListener &) =
delete;
1839struct InnerSymFixups {
1842 fixups.push_back({user, target});
1851 hw::InnerRefUserOpInterface innerRefUser;
1854 SmallVector<Fixup, 0> fixups;
1860 for (
auto &f : fixups) {
1863 return isnc.get(module);
1865 assert(ref &&
"unable to resolve inner symbol target");
1869 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1870 .Case<RWProbeOp>([ref](RWProbeOp op) {
1871 op.setTargetAttr(ref);
1874 .Default([](
auto *op) {
1875 return op->emitError(
"unknown inner-ref user requiring fixup");
1886struct FIRStmtParser :
public FIRParser {
1887 explicit FIRStmtParser(Block &blockToInsertInto,
1888 FIRModuleContext &moduleContext,
1889 InnerSymFixups &innerSymFixups,
1890 const SymbolTable &circuitSymTbl,
FIRVersion version,
1891 SymbolRefAttr layerSym = {})
1892 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1894 builder(UnknownLoc::
get(getContext()), getContext()),
1895 locationProcessor(this->builder), moduleContext(moduleContext),
1896 innerSymFixups(innerSymFixups), layerSym(layerSym),
1897 circuitSymTbl(circuitSymTbl) {
1898 builder.setInsertionPointToEnd(&blockToInsertInto);
1901 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1902 ParseResult parseSimpleStmtBlock(
unsigned indent);
1905 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1908 void emitInvalidate(Value val,
Flow flow);
1914 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1917 ParseResult parseOptionalInfo() {
1919 if (failed(parseOptionalInfoLocator(loc)))
1921 locationProcessor.setInfoLoc(loc);
1926 ParseResult parseExpImpl(Value &result,
const Twine &message,
1927 bool isLeadingStmt);
1928 ParseResult parseExp(Value &result,
const Twine &message) {
1929 return parseExpImpl(result, message,
false);
1931 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1932 return parseExpImpl(result, message,
true);
1934 ParseResult parseEnumExp(Value &result);
1935 ParseResult parsePathExp(Value &result);
1936 ParseResult parseDomainExp(Value &result);
1937 ParseResult parseRefExp(Value &result,
const Twine &message);
1938 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1939 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1940 const Twine &message);
1943 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1944 ParseResult parseIntrinsicStmt() {
1946 return parseIntrinsic(unused,
true);
1948 ParseResult parseIntrinsicExp(Value &result) {
1949 return parseIntrinsic(result,
false);
1951 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1953 template <
typename subop>
1954 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1955 ParseResult parseOptionalExpPostscript(Value &result,
1956 bool allowDynamic =
true);
1957 ParseResult parsePostFixFieldId(Value &result);
1958 ParseResult parsePostFixIntSubscript(Value &result);
1959 ParseResult parsePostFixDynamicSubscript(Value &result);
1960 ParseResult parseIntegerLiteralExp(Value &result);
1961 ParseResult parseListExp(Value &result);
1962 ParseResult parseListConcatExp(Value &result);
1963 ParseResult parseCatExp(Value &result);
1964 ParseResult parseUnsafeDomainCast(Value &result);
1966 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1967 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1969 auto loc = getToken().getLoc();
1970 locationProcessor.setLoc(loc);
1973 auto vals = std::array<Value, M>();
1974 auto ints = std::array<int64_t, N>();
1978 for (
size_t i = 0; i < M; ++i) {
1980 if (parseToken(FIRToken::comma,
"expected ','"))
1982 if (parseExp(vals[i],
"expected expression in primitive operand"))
1988 for (
size_t i = 0; i < N; ++i) {
1990 if (parseToken(FIRToken::comma,
"expected ','"))
1992 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
1997 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2001 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2005 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2006 translateLocation(loc));
2011 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2012 result = op.getResult();
2016 template <
typename T,
unsigned M,
unsigned N>
2017 ParseResult parsePrimExp(Value &result) {
2018 auto ms = std::make_index_sequence<M>();
2019 auto ns = std::make_index_sequence<N>();
2020 return parsePrim<T, M, N>(ms, ns, result);
2023 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2026 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2027 SymbolRefAttr layerSym);
2028 ParseResult parseAttach();
2029 ParseResult parseMemPort(MemDirAttr direction);
2035 ArrayRef<Value> specOperands,
2036 StringAttr &formatStringResult,
2037 SmallVectorImpl<Value> &operands);
2038 ParseResult parsePrintf();
2039 ParseResult parseFPrintf();
2040 ParseResult parseFFlush();
2041 ParseResult parseSkip();
2042 ParseResult parseStop();
2043 ParseResult parseAssert();
2044 ParseResult parseAssume();
2045 ParseResult parseCover();
2046 ParseResult parseWhen(
unsigned whenIndent);
2047 ParseResult parseMatch(
unsigned matchIndent);
2048 ParseResult parseDomainDefine();
2049 ParseResult parseRefDefine();
2050 ParseResult parseRefForce();
2051 ParseResult parseRefForceInitial();
2052 ParseResult parseRefRelease();
2053 ParseResult parseRefReleaseInitial();
2054 ParseResult parseRefRead(Value &result);
2055 ParseResult parseProbe(Value &result);
2056 ParseResult parsePropAssign();
2057 ParseResult parseRWProbe(Value &result);
2058 ParseResult parseLeadingExpStmt(Value lhs);
2059 ParseResult parseConnect();
2060 ParseResult parseInvalidate();
2061 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2064 ParseResult parseInstance();
2065 ParseResult parseInstanceChoice();
2066 ParseResult parseObject();
2067 ParseResult parseCombMem();
2068 ParseResult parseSeqMem();
2069 ParseResult parseMem(
unsigned memIndent);
2070 ParseResult parseNode();
2071 ParseResult parseWire();
2072 ParseResult parseRegister(
unsigned regIndent);
2073 ParseResult parseRegisterWithReset();
2074 ParseResult parseContract(
unsigned blockIndent);
2077 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2080 ImplicitLocOpBuilder builder;
2081 LazyLocationListener locationProcessor;
2084 FIRModuleContext &moduleContext;
2087 InnerSymFixups &innerSymFixups;
2091 SymbolRefAttr layerSym;
2093 const SymbolTable &circuitSymTbl;
2100void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2101 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2108 auto props = tpe.getRecursiveTypeProperties();
2109 if (props.isPassive && !props.containsAnalog) {
2110 if (flow == Flow::Source)
2112 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2123 TypeSwitch<FIRRTLType>(tpe)
2124 .Case<BundleType>([&](
auto tpe) {
2125 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2126 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2128 OpBuilder::InsertionGuard guard(builder);
2129 builder.setInsertionPointAfterValue(val);
2130 subfield = SubfieldOp::create(builder, val, i);
2132 emitInvalidate(subfield,
2133 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2136 .Case<FVectorType>([&](
auto tpe) {
2137 auto tpex = tpe.getElementType();
2138 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2139 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2141 OpBuilder::InsertionGuard guard(builder);
2142 builder.setInsertionPointAfterValue(val);
2143 subindex = SubindexOp::create(builder, tpex, val, i);
2145 emitInvalidate(subindex, flow);
2173ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2174 bool isLeadingStmt) {
2175 auto token = getToken();
2176 auto kind = token.getKind();
2178 case FIRToken::lp_integer_add:
2179 case FIRToken::lp_integer_mul:
2180 case FIRToken::lp_integer_shr:
2181 case FIRToken::lp_integer_shl:
2182 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2191#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2193 case FIRToken::lp_##SPELLING: \
2194 if (requireFeature(VERSION, FEATURE)) \
2196 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2199#include "FIRTokenKinds.def"
2201 case FIRToken::l_brace_bar:
2203 return emitError(
"unexpected enumeration as start of statement");
2204 if (parseEnumExp(result))
2207 case FIRToken::lp_read:
2209 return emitError(
"unexpected read() as start of statement");
2210 if (parseRefRead(result))
2213 case FIRToken::lp_probe:
2215 return emitError(
"unexpected probe() as start of statement");
2216 if (parseProbe(result))
2219 case FIRToken::lp_rwprobe:
2221 return emitError(
"unexpected rwprobe() as start of statement");
2222 if (parseRWProbe(result))
2226 case FIRToken::kw_UInt:
2227 case FIRToken::kw_SInt:
2228 if (parseIntegerLiteralExp(result))
2231 case FIRToken::kw_String: {
2232 if (requireFeature({3, 1, 0},
"Strings"))
2234 locationProcessor.setLoc(getToken().
getLoc());
2235 consumeToken(FIRToken::kw_String);
2237 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2238 parseGetSpelling(spelling) ||
2239 parseToken(FIRToken::string,
2240 "expected string literal in String expression") ||
2241 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2244 result = moduleContext.getCachedConstant<StringConstantOp>(
2245 builder, attr, builder.getType<StringType>(), attr);
2248 case FIRToken::kw_Integer: {
2249 if (requireFeature({3, 1, 0},
"Integers"))
2251 locationProcessor.setLoc(getToken().
getLoc());
2252 consumeToken(FIRToken::kw_Integer);
2254 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2255 parseIntLit(value,
"expected integer literal in Integer expression") ||
2256 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2258 APSInt apint(value,
false);
2259 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2260 builder, IntegerAttr::get(getContext(), apint),
2261 builder.getType<FIntegerType>(), apint);
2264 case FIRToken::kw_Bool: {
2267 locationProcessor.setLoc(getToken().
getLoc());
2268 consumeToken(FIRToken::kw_Bool);
2269 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2272 if (consumeIf(FIRToken::kw_true))
2274 else if (consumeIf(FIRToken::kw_false))
2277 return emitError(
"expected true or false in Bool expression");
2278 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2280 auto attr = builder.getBoolAttr(value);
2281 result = moduleContext.getCachedConstant<BoolConstantOp>(
2282 builder, attr, builder.getType<BoolType>(), value);
2285 case FIRToken::kw_Double: {
2288 locationProcessor.setLoc(getToken().
getLoc());
2289 consumeToken(FIRToken::kw_Double);
2290 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2292 auto spelling = getTokenSpelling();
2293 if (parseToken(FIRToken::floatingpoint,
2294 "expected floating point in Double expression") ||
2295 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2300 if (!llvm::to_float(spelling, d))
2301 return emitError(
"invalid double");
2302 auto attr = builder.getF64FloatAttr(d);
2303 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2304 builder, attr, builder.getType<DoubleType>(), attr);
2307 case FIRToken::kw_List: {
2308 if (requireFeature({4, 0, 0},
"Lists"))
2311 return emitError(
"unexpected List<>() as start of statement");
2312 if (parseListExp(result))
2317 case FIRToken::lp_list_concat: {
2319 return emitError(
"unexpected list_create() as start of statement");
2320 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2325 case FIRToken::lp_path:
2327 return emitError(
"unexpected path() as start of statement");
2332 case FIRToken::lp_intrinsic:
2333 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2334 parseIntrinsicExp(result))
2338 case FIRToken::lp_cat:
2339 if (parseCatExp(result))
2343 case FIRToken::lp_unsafe_domain_cast:
2345 parseUnsafeDomainCast(result))
2351 case FIRToken::identifier:
2352 case FIRToken::literal_identifier:
2355 auto loc = getToken().getLoc();
2357 if (parseId(name, message) ||
2358 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2362 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2365 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2370 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2371 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2372 parseOptionalInfo())
2375 locationProcessor.setLoc(loc);
2377 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2379 moduleContext.getUnbundledEntry(unbundledId);
2380 for (
auto elt : ubEntry)
2381 emitInvalidate(elt.second);
2389 StringRef fieldName;
2390 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2391 parseFieldId(fieldName,
"expected field name") ||
2392 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2400 case FIRToken::lp_shr:
2403 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2404 result = PadPrimOp::create(builder, result, 1);
2410 return parseOptionalExpPostscript(result);
2420ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2421 bool allowDynamic) {
2426 if (consumeIf(FIRToken::period)) {
2427 if (parsePostFixFieldId(result))
2434 if (consumeIf(FIRToken::l_square)) {
2435 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2436 if (parsePostFixIntSubscript(result))
2441 return emitError(
"subaccess not allowed here");
2442 if (parsePostFixDynamicSubscript(result))
2452template <
typename subop>
2454FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2456 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2462 auto baseType = cast<FIRRTLType>(base.getType());
2463 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2466 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2472 locationProcessor.setLoc(loc);
2473 OpBuilder::InsertionGuard guard(builder);
2474 builder.setInsertionPointAfterValue(base);
2475 auto op = subop::create(builder, resultType, base, indexNo);
2478 return value = op.getResult();
2485ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2486 auto loc = getToken().getLoc();
2487 SmallVector<StringRef, 3> fields;
2488 if (parseFieldIdSeq(fields,
"expected field name"))
2490 for (
auto fieldName : fields) {
2491 std::optional<unsigned> indexV;
2492 auto type = result.getType();
2493 if (
auto refTy = type_dyn_cast<RefType>(type))
2494 type = refTy.getType();
2495 if (
auto bundle = type_dyn_cast<BundleType>(type))
2496 indexV = bundle.getElementIndex(fieldName);
2497 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2498 indexV = bundle.getElementIndex(fieldName);
2499 else if (
auto klass = type_dyn_cast<ClassType>(type))
2500 indexV = klass.getElementIndex(fieldName);
2502 return emitError(loc,
"subfield requires bundle or object operand ");
2504 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2505 << result.getType();
2506 auto indexNo = *indexV;
2508 FailureOr<Value> subResult;
2509 if (type_isa<RefType>(result.getType()))
2510 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2511 else if (type_isa<ClassType>(type))
2512 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2513 else if (type_isa<BundleType>(type))
2514 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2516 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2518 if (failed(subResult))
2520 result = *subResult;
2529ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2530 auto loc = getToken().getLoc();
2532 if (parseIntLit(indexNo,
"expected index") ||
2533 parseToken(FIRToken::r_square,
"expected ']'"))
2537 return emitError(loc,
"invalid index specifier"), failure();
2539 FailureOr<Value> subResult;
2540 if (type_isa<RefType>(result.getType()))
2541 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2542 else if (type_isa<FVectorType>(result.getType()))
2543 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2545 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2547 if (failed(subResult))
2549 result = *subResult;
2557ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2558 auto loc = getToken().getLoc();
2560 if (parseExp(index,
"expected subscript index expression") ||
2561 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2565 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2567 return emitError(
"expected base type for index expression");
2568 indexType = indexType.getPassiveType();
2569 locationProcessor.setLoc(loc);
2574 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2577 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2578 translateLocation(loc));
2583 auto op = SubaccessOp::create(builder, resultType, result, index);
2584 result = op.getResult();
2590ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2591 bool isSigned = getToken().is(FIRToken::kw_SInt);
2592 auto loc = getToken().getLoc();
2598 if (parseOptionalWidth(width) ||
2599 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2600 parseIntLit(value,
"expected integer value") ||
2601 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2606 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2608 IntegerType::SignednessSemantics signedness =
2609 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2611 if (!value.isZero())
2612 return emitError(loc,
"zero bit constant must be zero");
2613 value = value.trunc(0);
2614 }
else if (width != -1) {
2616 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2618 return emitError(loc,
"initializer too wide for declared width");
2619 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2623 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2624 auto attr = builder.getIntegerAttr(attrType, value);
2626 locationProcessor.setLoc(loc);
2627 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2632ParseResult FIRStmtParser::parseListExp(Value &result) {
2633 auto loc = getToken().getLoc();
2635 if (parseListType(type))
2637 auto listType = type_cast<ListType>(type);
2640 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2643 SmallVector<Value, 3> operands;
2644 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2646 locationProcessor.setLoc(loc);
2647 if (parseExp(operand,
"expected expression in List expression"))
2651 if (!isa<AnyRefType>(elementType) ||
2652 !isa<ClassType>(operand.getType()))
2653 return emitError(loc,
"unexpected expression of type ")
2654 << operand.getType() <<
" in List expression of type "
2656 operand = ObjectAnyRefCastOp::create(builder, operand);
2659 operands.push_back(operand);
2664 locationProcessor.setLoc(loc);
2665 result = ListCreateOp::create(builder, listType, operands);
2670ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2671 consumeToken(FIRToken::lp_list_concat);
2673 auto loc = getToken().getLoc();
2675 SmallVector<Value, 3> operands;
2676 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2678 locationProcessor.setLoc(loc);
2679 if (parseExp(operand,
"expected expression in List concat expression"))
2682 if (!type_isa<ListType>(operand.getType()))
2683 return emitError(loc,
"unexpected expression of type ")
2684 << operand.getType() <<
" in List concat expression";
2687 type = type_cast<ListType>(operand.getType());
2689 if (operand.getType() != type)
2690 return emitError(loc,
"unexpected expression of type ")
2691 << operand.getType() <<
" in List concat expression of type "
2694 operands.push_back(operand);
2699 if (operands.empty())
2700 return emitError(loc,
"need at least one List to concatenate");
2702 locationProcessor.setLoc(loc);
2703 result = ListConcatOp::create(builder, type, operands);
2708ParseResult FIRStmtParser::parseCatExp(Value &result) {
2709 consumeToken(FIRToken::lp_cat);
2711 auto loc = getToken().getLoc();
2712 SmallVector<Value, 3> operands;
2713 std::optional<bool> isSigned;
2714 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2716 locationProcessor.setLoc(loc);
2717 auto operandLoc = getToken().getLoc();
2718 if (parseExp(operand,
"expected expression in cat expression"))
2720 if (!type_isa<IntType>(operand.getType())) {
2721 auto diag = emitError(loc,
"all operands must be Int type");
2722 diag.attachNote(translateLocation(operandLoc))
2723 <<
"non-integer operand is here";
2727 isSigned = type_isa<SIntType>(operand.getType());
2728 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2729 auto diag = emitError(loc,
"all operands must have same signedness");
2730 diag.attachNote(translateLocation(operandLoc))
2731 <<
"operand with different signedness is here";
2735 operands.push_back(operand);
2740 if (operands.size() != 2) {
2745 locationProcessor.setLoc(loc);
2746 result = CatPrimOp::create(builder, operands);
2750ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2751 consumeToken(FIRToken::lp_unsafe_domain_cast);
2753 auto loc = getToken().getLoc();
2755 if (parseExp(input,
"expected input"))
2758 SmallVector<Value> domains;
2759 if (consumeIf(FIRToken::comma)) {
2760 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2762 if (parseExp(domain,
"expected domain"))
2764 domains.push_back(domain);
2768 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2772 locationProcessor.setLoc(loc);
2773 result = UnsafeDomainCastOp::create(builder, input, domains);
2794std::optional<ParseResult>
2795FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2796 switch (getToken().getKind()) {
2799 return std::nullopt;
2801 case FIRToken::period:
2802 case FIRToken::l_square:
2803 case FIRToken::kw_is:
2804 case FIRToken::less_equal:
2810 auto loc = keyword.
getLoc();
2812 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2813 return ParseResult(failure());
2819 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2822 if (!consumeIf(FIRToken::period))
2823 return ParseResult(failure());
2825 StringRef fieldName;
2826 if (parseFieldId(fieldName,
"expected field name") ||
2827 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2828 return ParseResult(failure());
2832 if (parseOptionalExpPostscript(lhs))
2833 return ParseResult(failure());
2835 return parseLeadingExpStmt(lhs);
2841ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2844 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2847 auto subIndent = getIndentation();
2848 if (!subIndent.has_value())
2849 return emitError(
"expected statement to be on its own line"), failure();
2851 if (*subIndent <= indent)
2855 if (parseSimpleStmt(*subIndent))
2860ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2861 locationProcessor.startStatement();
2862 auto result = parseSimpleStmtImpl(stmtIndent);
2863 locationProcessor.endStatement(*
this);
2885ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2886 auto kind = getToken().getKind();
2889 case FIRToken::kw_invalidate:
2890 case FIRToken::kw_connect:
2891 case FIRToken::kw_regreset:
2895 kind = FIRToken::identifier;
2902 case FIRToken::kw_attach:
2903 return parseAttach();
2904 case FIRToken::kw_infer:
2905 return parseMemPort(MemDirAttr::Infer);
2906 case FIRToken::kw_read:
2907 return parseMemPort(MemDirAttr::Read);
2908 case FIRToken::kw_write:
2909 return parseMemPort(MemDirAttr::Write);
2910 case FIRToken::kw_rdwr:
2911 return parseMemPort(MemDirAttr::ReadWrite);
2912 case FIRToken::kw_connect:
2913 return parseConnect();
2914 case FIRToken::kw_propassign:
2915 if (requireFeature({3, 1, 0},
"properties"))
2917 return parsePropAssign();
2918 case FIRToken::kw_invalidate:
2919 return parseInvalidate();
2920 case FIRToken::lp_printf:
2921 return parsePrintf();
2922 case FIRToken::lp_fprintf:
2923 return parseFPrintf();
2924 case FIRToken::lp_fflush:
2925 return parseFFlush();
2926 case FIRToken::kw_skip:
2928 case FIRToken::lp_stop:
2930 case FIRToken::lp_assert:
2931 return parseAssert();
2932 case FIRToken::lp_assume:
2933 return parseAssume();
2934 case FIRToken::lp_cover:
2935 return parseCover();
2936 case FIRToken::kw_when:
2937 return parseWhen(stmtIndent);
2938 case FIRToken::kw_match:
2939 return parseMatch(stmtIndent);
2940 case FIRToken::kw_domain_define:
2941 return parseDomainDefine();
2942 case FIRToken::kw_define:
2943 return parseRefDefine();
2944 case FIRToken::lp_force:
2945 return parseRefForce();
2946 case FIRToken::lp_force_initial:
2947 return parseRefForceInitial();
2948 case FIRToken::lp_release:
2949 return parseRefRelease();
2950 case FIRToken::lp_release_initial:
2951 return parseRefReleaseInitial();
2952 case FIRToken::kw_group:
2953 if (requireFeature({3, 2, 0},
"optional groups") ||
2954 removedFeature({3, 3, 0},
"optional groups"))
2956 return parseLayerBlockOrGroup(stmtIndent);
2957 case FIRToken::kw_layerblock:
2958 if (requireFeature({3, 3, 0},
"layers"))
2960 return parseLayerBlockOrGroup(stmtIndent);
2961 case FIRToken::lp_intrinsic:
2962 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2964 return parseIntrinsicStmt();
2968 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2975 return parseLeadingExpStmt(lhs);
2979 case FIRToken::kw_inst:
2980 return parseInstance();
2981 case FIRToken::kw_instchoice:
2982 return parseInstanceChoice();
2983 case FIRToken::kw_object:
2984 return parseObject();
2985 case FIRToken::kw_cmem:
2986 return parseCombMem();
2987 case FIRToken::kw_smem:
2988 return parseSeqMem();
2989 case FIRToken::kw_mem:
2990 return parseMem(stmtIndent);
2991 case FIRToken::kw_node:
2993 case FIRToken::kw_wire:
2995 case FIRToken::kw_reg:
2996 return parseRegister(stmtIndent);
2997 case FIRToken::kw_regreset:
2998 return parseRegisterWithReset();
2999 case FIRToken::kw_contract:
3000 return parseContract(stmtIndent);
3004ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3006 SymbolRefAttr layerSym) {
3008 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3009 moduleContext, &blockToInsertInto);
3014 UnbundledValueRestorer x(moduleContext.unbundledValues);
3018 auto subParser = std::make_unique<FIRStmtParser>(
3019 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3023 auto stmtIndent = getIndentation();
3026 if (!stmtIndent.has_value())
3027 return subParser->parseSimpleStmt(indent);
3029 if (*stmtIndent <= indent)
3030 return emitError(
"statement must be indented more than previous statement"),
3034 return subParser->parseSimpleStmtBlock(indent);
3038ParseResult FIRStmtParser::parseAttach() {
3039 auto startTok = consumeToken(FIRToken::kw_attach);
3042 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3045 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3048 SmallVector<Value, 4> operands;
3049 operands.push_back({});
3050 if (parseExp(operands.back(),
"expected operand in attach"))
3053 while (consumeIf(FIRToken::comma)) {
3054 operands.push_back({});
3055 if (parseExp(operands.back(),
"expected operand in attach"))
3058 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3061 if (parseOptionalInfo())
3064 locationProcessor.setLoc(startTok.getLoc());
3065 AttachOp::create(builder, operands);
3072ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3073 auto startTok = consumeToken();
3074 auto startLoc = startTok.getLoc();
3078 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3084 Value memory, indexExp, clock;
3085 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3086 parseId(
id,
"expected result name") ||
3087 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3088 parseId(memName,
"expected memory name") ||
3089 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3090 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3091 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3092 parseExp(indexExp,
"expected index expression") ||
3093 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3094 parseToken(FIRToken::comma,
"expected ','") ||
3095 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3098 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3100 return emitError(startLoc,
3101 "memory port should have behavioral memory type");
3102 auto resultType = memVType.getElementType();
3104 ArrayAttr annotations = getConstants().emptyArrayAttr;
3105 locationProcessor.setLoc(startLoc);
3108 Value memoryPort, memoryData;
3110 OpBuilder::InsertionGuard guard(builder);
3111 builder.setInsertionPointAfterValue(memory);
3112 auto memoryPortOp = MemoryPortOp::create(
3113 builder, resultType, CMemoryPortType::get(getContext()), memory,
3114 direction,
id, annotations);
3115 memoryData = memoryPortOp.getResult(0);
3116 memoryPort = memoryPortOp.getResult(1);
3120 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3122 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3128ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3129 StringRef formatString,
3130 ArrayRef<Value> specOperands,
3131 StringAttr &formatStringResult,
3132 SmallVectorImpl<Value> &operands) {
3135 operands.append(specOperands.begin(), specOperands.end());
3136 formatStringResult =
3142 auto loc = translateLocation(formatStringLoc);
3145 formatStringResult, operands);
3150ParseResult FIRStmtParser::parsePrintf() {
3151 auto startTok = consumeToken(FIRToken::lp_printf);
3153 Value clock, condition;
3154 StringRef formatString;
3155 if (parseExp(clock,
"expected clock expression in printf") ||
3156 parseToken(FIRToken::comma,
"expected ','") ||
3157 parseExp(condition,
"expected condition in printf") ||
3158 parseToken(FIRToken::comma,
"expected ','"))
3161 auto formatStringLoc = getToken().getLoc();
3162 if (parseGetSpelling(formatString) ||
3163 parseToken(FIRToken::string,
"expected format string in printf"))
3166 SmallVector<Value, 4> specOperands;
3167 while (consumeIf(FIRToken::comma)) {
3168 specOperands.push_back({});
3169 if (parseExp(specOperands.back(),
"expected operand in printf"))
3174 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3175 parseOptionalName(name) || parseOptionalInfo())
3178 locationProcessor.setLoc(startTok.getLoc());
3180 StringAttr formatStrUnescaped;
3181 SmallVector<Value> operands;
3183 formatStrUnescaped, operands))
3186 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3192ParseResult FIRStmtParser::parseFPrintf() {
3195 auto startTok = consumeToken(FIRToken::lp_fprintf);
3197 Value clock, condition;
3198 StringRef outputFile, formatString;
3199 if (parseExp(clock,
"expected clock expression in fprintf") ||
3200 parseToken(FIRToken::comma,
"expected ','") ||
3201 parseExp(condition,
"expected condition in fprintf") ||
3202 parseToken(FIRToken::comma,
"expected ','"))
3205 auto outputFileLoc = getToken().getLoc();
3206 if (parseGetSpelling(outputFile) ||
3207 parseToken(FIRToken::string,
"expected output file in fprintf"))
3210 SmallVector<Value, 4> outputFileSpecOperands;
3211 while (consumeIf(FIRToken::comma)) {
3213 if (getToken().getKind() == FIRToken::string)
3215 outputFileSpecOperands.push_back({});
3216 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3220 auto formatStringLoc = getToken().getLoc();
3221 if (parseGetSpelling(formatString) ||
3222 parseToken(FIRToken::string,
"expected format string in printf"))
3225 SmallVector<Value, 4> specOperands;
3226 while (consumeIf(FIRToken::comma)) {
3227 specOperands.push_back({});
3228 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3233 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3234 parseOptionalName(name) || parseOptionalInfo())
3237 locationProcessor.setLoc(startTok.getLoc());
3239 StringAttr outputFileNameStrUnescaped;
3240 SmallVector<Value> outputFileOperands;
3242 outputFileNameStrUnescaped, outputFileOperands))
3245 StringAttr formatStrUnescaped;
3246 SmallVector<Value> operands;
3248 formatStrUnescaped, operands))
3251 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3252 outputFileOperands, formatStrUnescaped, operands, name);
3257ParseResult FIRStmtParser::parseFFlush() {
3261 auto startTok = consumeToken(FIRToken::lp_fflush);
3263 Value clock, condition;
3264 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3265 parseToken(FIRToken::comma,
"expected ','") ||
3266 parseExp(condition,
"expected condition in 'fflush'"))
3269 locationProcessor.setLoc(startTok.getLoc());
3270 StringAttr outputFileNameStrUnescaped;
3271 SmallVector<Value> outputFileOperands;
3273 if (consumeIf(FIRToken::comma)) {
3274 SmallVector<Value, 4> outputFileSpecOperands;
3275 auto outputFileLoc = getToken().getLoc();
3276 StringRef outputFile;
3277 if (parseGetSpelling(outputFile) ||
3278 parseToken(FIRToken::string,
"expected output file in fflush"))
3281 while (consumeIf(FIRToken::comma)) {
3282 outputFileSpecOperands.push_back({});
3283 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3288 outputFileNameStrUnescaped, outputFileOperands))
3292 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3293 parseOptionalInfo())
3296 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3297 outputFileOperands);
3302ParseResult FIRStmtParser::parseSkip() {
3303 auto startTok = consumeToken(FIRToken::kw_skip);
3307 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3310 if (parseOptionalInfo())
3313 locationProcessor.setLoc(startTok.getLoc());
3314 SkipOp::create(builder);
3319ParseResult FIRStmtParser::parseStop() {
3320 auto startTok = consumeToken(FIRToken::lp_stop);
3322 Value clock, condition;
3325 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3326 parseToken(FIRToken::comma,
"expected ','") ||
3327 parseExp(condition,
"expected condition in 'stop'") ||
3328 parseToken(FIRToken::comma,
"expected ','") ||
3329 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3330 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3331 parseOptionalName(name) || parseOptionalInfo())
3334 locationProcessor.setLoc(startTok.getLoc());
3335 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3341ParseResult FIRStmtParser::parseAssert() {
3342 auto startTok = consumeToken(FIRToken::lp_assert);
3344 Value clock, predicate, enable;
3345 StringRef formatString;
3347 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3348 parseToken(FIRToken::comma,
"expected ','") ||
3349 parseExp(predicate,
"expected predicate in 'assert'") ||
3350 parseToken(FIRToken::comma,
"expected ','") ||
3351 parseExp(enable,
"expected enable in 'assert'") ||
3352 parseToken(FIRToken::comma,
"expected ','") ||
3353 parseGetSpelling(formatString) ||
3354 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3357 SmallVector<Value, 4> operands;
3358 while (!consumeIf(FIRToken::r_paren)) {
3359 operands.push_back({});
3360 if (parseToken(FIRToken::comma,
"expected ','") ||
3361 parseExp(operands.back(),
"expected operand in 'assert'"))
3365 if (parseOptionalName(name) || parseOptionalInfo())
3368 locationProcessor.setLoc(startTok.getLoc());
3370 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3371 operands, name.getValue());
3376ParseResult FIRStmtParser::parseAssume() {
3377 auto startTok = consumeToken(FIRToken::lp_assume);
3379 Value clock, predicate, enable;
3380 StringRef formatString;
3382 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3383 parseToken(FIRToken::comma,
"expected ','") ||
3384 parseExp(predicate,
"expected predicate in 'assume'") ||
3385 parseToken(FIRToken::comma,
"expected ','") ||
3386 parseExp(enable,
"expected enable in 'assume'") ||
3387 parseToken(FIRToken::comma,
"expected ','") ||
3388 parseGetSpelling(formatString) ||
3389 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3392 SmallVector<Value, 4> operands;
3393 while (!consumeIf(FIRToken::r_paren)) {
3394 operands.push_back({});
3395 if (parseToken(FIRToken::comma,
"expected ','") ||
3396 parseExp(operands.back(),
"expected operand in 'assume'"))
3400 if (parseOptionalName(name) || parseOptionalInfo())
3403 locationProcessor.setLoc(startTok.getLoc());
3405 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3406 operands, name.getValue());
3411ParseResult FIRStmtParser::parseCover() {
3412 auto startTok = consumeToken(FIRToken::lp_cover);
3414 Value clock, predicate, enable;
3417 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3418 parseToken(FIRToken::comma,
"expected ','") ||
3419 parseExp(predicate,
"expected predicate in 'cover'") ||
3420 parseToken(FIRToken::comma,
"expected ','") ||
3421 parseExp(enable,
"expected enable in 'cover'") ||
3422 parseToken(FIRToken::comma,
"expected ','") ||
3423 parseGetSpelling(message) ||
3424 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3425 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3426 parseOptionalName(name) || parseOptionalInfo())
3429 locationProcessor.setLoc(startTok.getLoc());
3431 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3432 ValueRange{}, name.getValue());
3438ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3439 auto startTok = consumeToken(FIRToken::kw_when);
3443 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3447 if (parseExp(condition,
"expected condition in 'when'") ||
3448 parseToken(FIRToken::colon,
"expected ':' in when") ||
3449 parseOptionalInfo())
3452 locationProcessor.setLoc(startTok.getLoc());
3454 auto whenStmt = WhenOp::create(builder, condition,
false);
3457 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3461 if (getToken().isNot(FIRToken::kw_else))
3466 auto elseIndent = getIndentation();
3467 if (elseIndent && *elseIndent < whenIndent)
3470 consumeToken(FIRToken::kw_else);
3473 whenStmt.createElseRegion();
3479 if (getToken().is(FIRToken::kw_when)) {
3481 auto subParser = std::make_unique<FIRStmtParser>(
3482 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3485 return subParser->parseSimpleStmt(whenIndent);
3489 LocationAttr elseLoc;
3490 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3491 parseOptionalInfoLocator(elseLoc) ||
3492 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3501ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3502 auto startLoc = getToken().getLoc();
3503 locationProcessor.setLoc(startLoc);
3505 if (parseEnumType(type))
3509 auto enumType = type_dyn_cast<FEnumType>(type);
3511 return emitError(startLoc,
3512 "expected enumeration type in enumeration expression");
3515 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3516 parseId(tag,
"expected enumeration tag"))
3520 if (consumeIf(FIRToken::r_paren)) {
3523 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3524 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3525 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3526 input = ConstantOp::create(builder, type, attr);
3529 if (parseToken(FIRToken::comma,
"expected ','") ||
3530 parseExp(input,
"expected expression in enumeration value") ||
3531 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3535 value = FEnumCreateOp::create(builder, enumType, tag, input);
3543ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3544 auto startTok = consumeToken(FIRToken::kw_match);
3546 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3550 if (parseExp(input,
"expected expression in 'match'") ||
3551 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3552 parseOptionalInfo())
3555 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3557 return mlir::emitError(
3559 "expected enumeration type for 'match' statement, but got ")
3562 locationProcessor.setLoc(startTok.getLoc());
3564 SmallVector<Attribute> tags;
3565 SmallVector<std::unique_ptr<Region>> regions;
3567 auto tagLoc = getToken().getLoc();
3570 auto caseIndent = getIndentation();
3571 if (!caseIndent || *caseIndent <= matchIndent)
3575 StringRef tagSpelling;
3576 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3578 auto tagIndex = enumType.getElementIndex(tagSpelling);
3580 return emitError(tagLoc,
"tag ")
3581 << tagSpelling <<
" not a member of enumeration " << enumType;
3582 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3583 tags.push_back(tag);
3586 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3589 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3594 UnbundledValueRestorer x(moduleContext.unbundledValues);
3597 if (consumeIf(FIRToken::l_paren)) {
3598 StringAttr identifier;
3599 if (parseId(identifier,
"expected identifier for 'case' binding"))
3603 auto dataType = enumType.getElementType(*tagIndex);
3604 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3606 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3610 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3614 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3615 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3618 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3622 auto subParser = std::make_unique<FIRStmtParser>(
3623 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3625 if (subParser->parseSimpleStmtBlock(*caseIndent))
3629 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3636ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3637 auto loc = getToken().getLoc();
3640 if (parseId(
id,
"expected domain expression") ||
3641 moduleContext.lookupSymbolEntry(entry,
id, loc))
3644 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3646 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3647 parseFieldId(field,
"expected field name") ||
3648 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3652 if (parseOptionalExpPostscript(result,
false))
3655 auto type = result.getType();
3656 if (!type_isa<DomainType>(type))
3657 return emitError(loc) <<
"expected domain-type expression, got " << type;
3664ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3665 auto token = getToken().getKind();
3666 if (token == FIRToken::lp_probe)
3667 return parseProbe(result);
3668 if (token == FIRToken::lp_rwprobe)
3669 return parseRWProbe(result);
3674 return parseStaticRefExp(result, message);
3681ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3682 const Twine &message) {
3683 auto parseIdOrInstance = [&]() -> ParseResult {
3685 auto loc = getToken().getLoc();
3687 if (parseId(
id, message) ||
3688 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3692 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3695 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3698 StringRef fieldName;
3700 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3701 parseFieldId(fieldName,
"expected field name") ||
3702 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3704 return failure(parseIdOrInstance() ||
3705 parseOptionalExpPostscript(result,
false));
3716ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3718 const Twine &message) {
3719 auto loc = getToken().getLoc();
3723 if (parseId(
id, message) ||
3724 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3736 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3738 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3740 StringRef fieldName;
3741 auto loc = getToken().getLoc();
3742 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3743 parseFieldId(fieldName,
"expected field name"))
3748 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3749 for (
auto &elt : ubEntry) {
3750 if (elt.first == fieldAttr) {
3753 auto &instResult = elt.second;
3756 auto *defining = instResult.getDefiningOp();
3758 if (isa<WireOp>(defining)) {
3759 result = instResult;
3764 auto type = instResult.getType();
3768 bool forceable =
static_cast<bool>(
3771 return emitError(loc,
"unable to force instance result of type ")
3775 auto annotations = getConstants().emptyArrayAttr;
3776 StringAttr sym = {};
3777 SmallString<64> name;
3778 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3779 locationProcessor.setLoc(loc);
3780 OpBuilder::InsertionGuard guard(builder);
3781 builder.setInsertionPoint(defining);
3783 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3785 auto bounceVal = bounce.getData();
3788 instResult.replaceAllUsesWith(bounceVal);
3791 builder.setInsertionPointAfter(defining);
3792 if (
foldFlow(instResult) == Flow::Source)
3799 result = instResult = bounce.getDataRaw();
3805 emitError(loc,
"use of invalid field name '")
3806 << fieldName <<
"' on bundle value";
3811 result = cast<Value>(symtabEntry);
3815 assert(isa<BlockArgument>(result) ||
3816 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3822 type = result.getType();
3824 if (consumeIf(FIRToken::period)) {
3825 SmallVector<StringRef, 3> fields;
3826 if (parseFieldIdSeq(fields,
"expected field name"))
3828 for (
auto fieldName : fields) {
3829 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3830 if (
auto index = bundle.getElementIndex(fieldName)) {
3831 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3832 type = bundle.getElementTypePreservingConst(*index);
3835 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3836 if (
auto index = bundle.getElementIndex(fieldName)) {
3837 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3838 type = bundle.getElementTypePreservingConst(*index);
3842 return emitError(loc,
"subfield requires bundle operand")
3843 <<
"got " << type <<
"\n";
3845 return emitError(loc,
3846 "unknown field '" + fieldName +
"' in bundle type ")
3851 if (consumeIf(FIRToken::l_square)) {
3852 auto loc = getToken().
getLoc();
3854 if (parseIntLit(index,
"expected index") ||
3855 parseToken(FIRToken::r_square,
"expected ']'"))
3859 return emitError(loc,
"invalid index specifier");
3861 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3862 if ((
unsigned)index < vector.getNumElements()) {
3863 refResult = refResult.
getSubField(vector.getFieldID(index));
3864 type = vector.getElementTypePreservingConst();
3867 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3868 if ((
unsigned)index < vector.getNumElements()) {
3869 refResult = refResult.
getSubField(vector.getFieldID(index));
3870 type = vector.getElementTypePreservingConst();
3874 return emitError(loc,
"subindex requires vector operand");
3876 return emitError(loc,
"out of range index '")
3877 << index <<
"' for vector type " << type;
3885ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3886 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3887 StringRef intrinsic;
3888 ArrayAttr parameters;
3891 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3892 parseOptionalParams(parameters))
3895 if (consumeIf(FIRToken::colon)) {
3896 if (
parseType(type,
"expected intrinsic return type"))
3898 }
else if (!isStatement)
3899 return emitError(
"expected ':' in intrinsic expression");
3901 SmallVector<Value> operands;
3902 auto loc = startTok.getLoc();
3903 if (consumeIf(FIRToken::comma)) {
3904 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3906 if (parseExp(operand,
"expected operand in intrinsic"))
3908 operands.push_back(operand);
3909 locationProcessor.setLoc(loc);
3914 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3919 if (parseOptionalInfo())
3922 locationProcessor.setLoc(loc);
3924 auto op = GenericIntrinsicOp::create(
3925 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
3927 result = op.getResult();
3932ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3933 if (!consumeIf(FIRToken::less))
3936 SmallVector<Attribute, 8> parameters;
3937 SmallPtrSet<StringAttr, 8> seen;
3938 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3942 if (parseParameter(name, value, loc))
3944 auto typedValue = dyn_cast<TypedAttr>(value);
3946 return emitError(loc)
3947 <<
"invalid value for parameter '" << name.getValue() <<
"'";
3948 if (!seen.insert(name).second)
3949 return emitError(loc,
"redefinition of parameter '" +
3950 name.getValue() +
"'");
3951 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3956 resultParameters = ArrayAttr::get(getContext(), parameters);
3962ParseResult FIRStmtParser::parsePathExp(Value &result) {
3963 auto startTok = consumeToken(FIRToken::lp_path);
3964 locationProcessor.setLoc(startTok.getLoc());
3966 if (parseGetSpelling(target) ||
3967 parseToken(FIRToken::string,
3968 "expected target string in path expression") ||
3969 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3971 result = UnresolvedPathOp::create(
3977ParseResult FIRStmtParser::parseDomainDefine() {
3978 auto startTok = consumeToken(FIRToken::kw_domain_define);
3979 auto startLoc = startTok.getLoc();
3980 locationProcessor.setLoc(startLoc);
3984 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
3985 parseDomainExp(src) || parseOptionalInfo())
3993ParseResult FIRStmtParser::parseRefDefine() {
3994 auto startTok = consumeToken(FIRToken::kw_define);
3997 if (parseStaticRefExp(target,
3998 "expected static reference expression in 'define'") ||
3999 parseToken(FIRToken::equal,
4000 "expected '=' after define reference expression") ||
4001 parseRefExp(src,
"expected reference expression in 'define'") ||
4002 parseOptionalInfo())
4006 if (!type_isa<RefType>(target.getType()))
4007 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4008 "'define' target (LHS), got ")
4009 << target.getType();
4010 if (!type_isa<RefType>(src.getType()))
4011 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4012 "'define' source (RHS), got ")
4017 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4018 return emitError(startTok.getLoc(),
4019 "cannot define into a sub-element of a reference");
4021 locationProcessor.setLoc(startTok.getLoc());
4024 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4025 << target.getType() <<
" with incompatible reference of type "
4035ParseResult FIRStmtParser::parseRefRead(Value &result) {
4036 auto startTok = consumeToken(FIRToken::lp_read);
4039 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4040 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4043 locationProcessor.setLoc(startTok.getLoc());
4046 if (!type_isa<RefType>(ref.getType()))
4047 return emitError(startTok.getLoc(),
4048 "expected reference-type expression in 'read', got ")
4051 result = RefResolveOp::create(builder, ref);
4057ParseResult FIRStmtParser::parseProbe(Value &result) {
4058 auto startTok = consumeToken(FIRToken::lp_probe);
4061 if (parseStaticRefExp(staticRef,
4062 "expected static reference expression in 'probe'") ||
4063 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4066 locationProcessor.setLoc(startTok.getLoc());
4069 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4070 return emitError(startTok.getLoc(),
4071 "expected base-type expression in 'probe', got ")
4072 << staticRef.getType();
4076 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4077 MemoryDebugPortOp, MemoryPortAccessOp>(
4078 staticRef.getDefiningOp()))
4079 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4081 result = RefSendOp::create(builder, staticRef);
4087ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4088 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4091 Type parsedTargetType;
4092 if (parseRWProbeStaticRefExp(
4093 staticRef, parsedTargetType,
4094 "expected static reference expression in 'rwprobe'") ||
4095 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4098 locationProcessor.setLoc(startTok.getLoc());
4104 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4106 return emitError(startTok.getLoc(),
4107 "expected base-type expression in 'rwprobe', got ")
4108 << parsedTargetType;
4111 auto *definingOp = root.getDefiningOp();
4113 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4114 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4115 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4119 return emitError(startTok.getLoc(),
"cannot force target of type ")
4123 auto op = RWProbeOp::create(builder, forceableType,
4124 getConstants().placeholderInnerRef);
4131ParseResult FIRStmtParser::parseRefForce() {
4132 auto startTok = consumeToken(FIRToken::lp_force);
4134 Value clock, pred, dest, src;
4135 if (parseExp(clock,
"expected clock expression in force") ||
4136 parseToken(FIRToken::comma,
"expected ','") ||
4137 parseExp(pred,
"expected predicate expression in force") ||
4138 parseToken(FIRToken::comma,
"expected ','") ||
4139 parseRefExp(dest,
"expected destination reference expression in force") ||
4140 parseToken(FIRToken::comma,
"expected ','") ||
4141 parseExp(src,
"expected source expression in force") ||
4142 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4143 parseOptionalInfo())
4147 auto ref = type_dyn_cast<RefType>(dest.getType());
4148 if (!ref || !ref.getForceable())
4151 "expected rwprobe-type expression for force destination, got ")
4153 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4155 return emitError(startTok.getLoc(),
4156 "expected base-type for force source, got ")
4158 if (!srcBaseType.isPassive())
4159 return emitError(startTok.getLoc(),
4160 "expected passive value for force source, got ")
4163 locationProcessor.setLoc(startTok.getLoc());
4166 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4167 if (noConstSrcType != ref.getType()) {
4169 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4171 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4173 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4174 << src.getType() <<
" cannot target destination "
4178 RefForceOp::create(builder, clock, pred, dest, src);
4184ParseResult FIRStmtParser::parseRefForceInitial() {
4185 auto startTok = consumeToken(FIRToken::lp_force_initial);
4189 dest,
"expected destination reference expression in force_initial") ||
4190 parseToken(FIRToken::comma,
"expected ','") ||
4191 parseExp(src,
"expected source expression in force_initial") ||
4192 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4193 parseOptionalInfo())
4197 auto ref = type_dyn_cast<RefType>(dest.getType());
4198 if (!ref || !ref.getForceable())
4199 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4200 "force_initial destination, got ")
4202 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4204 return emitError(startTok.getLoc(),
4205 "expected base-type expression for force_initial "
4208 if (!srcBaseType.isPassive())
4209 return emitError(startTok.getLoc(),
4210 "expected passive value for force_initial source, got ")
4213 locationProcessor.setLoc(startTok.getLoc());
4216 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4217 if (noConstSrcType != ref.getType()) {
4219 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4221 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4223 return emitError(startTok.getLoc(),
4224 "incompatible force_initial source of type ")
4225 << src.getType() <<
" cannot target destination "
4229 auto value = APInt::getAllOnes(1);
4230 auto type = UIntType::get(builder.getContext(), 1);
4231 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4232 value.getBitWidth(),
4233 IntegerType::Unsigned),
4235 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4236 RefForceInitialOp::create(builder, pred, dest, src);
4242ParseResult FIRStmtParser::parseRefRelease() {
4243 auto startTok = consumeToken(FIRToken::lp_release);
4245 Value clock, pred, dest;
4246 if (parseExp(clock,
"expected clock expression in release") ||
4247 parseToken(FIRToken::comma,
"expected ','") ||
4248 parseExp(pred,
"expected predicate expression in release") ||
4249 parseToken(FIRToken::comma,
"expected ','") ||
4251 "expected destination reference expression in release") ||
4252 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4253 parseOptionalInfo())
4257 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4258 !ref || !ref.getForceable())
4261 "expected rwprobe-type expression for release destination, got ")
4264 locationProcessor.setLoc(startTok.getLoc());
4266 RefReleaseOp::create(builder, clock, pred, dest);
4272ParseResult FIRStmtParser::parseRefReleaseInitial() {
4273 auto startTok = consumeToken(FIRToken::lp_release_initial);
4278 "expected destination reference expression in release_initial") ||
4279 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4280 parseOptionalInfo())
4284 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4285 !ref || !ref.getForceable())
4286 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4287 "release_initial destination, got ")
4290 locationProcessor.setLoc(startTok.getLoc());
4292 auto value = APInt::getAllOnes(1);
4293 auto type = UIntType::get(builder.getContext(), 1);
4294 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4295 value.getBitWidth(),
4296 IntegerType::Unsigned),
4298 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4299 RefReleaseInitialOp::create(builder, pred, dest);
4305ParseResult FIRStmtParser::parseConnect() {
4306 auto startTok = consumeToken(FIRToken::kw_connect);
4307 auto loc = startTok.getLoc();
4310 if (parseExp(lhs,
"expected connect expression") ||
4311 parseToken(FIRToken::comma,
"expected ','") ||
4312 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4315 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4316 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4317 if (!lhsType || !rhsType)
4318 return emitError(loc,
"cannot connect reference or property types");
4320 if (lhsType.containsReference() || rhsType.containsReference())
4321 return emitError(loc,
"cannot connect types containing references");
4324 return emitError(loc,
"cannot connect non-equivalent type ")
4325 << rhsType <<
" to " << lhsType;
4327 locationProcessor.setLoc(loc);
4333ParseResult FIRStmtParser::parsePropAssign() {
4334 auto startTok = consumeToken(FIRToken::kw_propassign);
4335 auto loc = startTok.getLoc();
4338 if (parseExp(lhs,
"expected propassign expression") ||
4339 parseToken(FIRToken::comma,
"expected ','") ||
4340 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4343 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4344 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4345 if (!lhsType || !rhsType)
4346 return emitError(loc,
"can only propassign property types");
4347 locationProcessor.setLoc(loc);
4348 if (lhsType != rhsType) {
4350 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4351 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4353 return emitError(loc,
"cannot propassign non-equivalent type ")
4354 << rhsType <<
" to " << lhsType;
4356 PropAssignOp::create(builder, lhs, rhs);
4361ParseResult FIRStmtParser::parseInvalidate() {
4362 auto startTok = consumeToken(FIRToken::kw_invalidate);
4367 auto loc = getToken().getLoc();
4369 if (parseId(
id,
"expected static reference expression") ||
4370 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4375 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4376 if (parseOptionalExpPostscript(lhs,
false) ||
4377 parseOptionalInfo())
4380 locationProcessor.setLoc(startTok.getLoc());
4381 emitInvalidate(lhs);
4388 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4390 if (getToken().isNot(FIRToken::period)) {
4391 locationProcessor.setLoc(loc);
4393 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4395 for (
auto elt : ubEntry)
4396 emitInvalidate(elt.second);
4402 StringRef fieldName;
4403 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4404 parseFieldId(fieldName,
"expected field name") ||
4405 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4409 if (parseOptionalExpPostscript(lhs,
false) ||
4410 parseOptionalInfo())
4413 locationProcessor.setLoc(startTok.getLoc());
4414 emitInvalidate(lhs);
4418ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4420 auto startTok = consumeToken();
4421 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4422 "consumed an unexpected token");
4423 auto loc = startTok.getLoc();
4426 if (parseId(
id,
"expected layer identifer") ||
4427 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4428 parseOptionalInfo())
4431 locationProcessor.setLoc(loc);
4433 StringRef rootLayer;
4434 SmallVector<FlatSymbolRefAttr> nestedLayers;
4438 rootLayer = layerSym.getRootReference();
4439 auto nestedRefs = layerSym.getNestedReferences();
4440 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4441 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4444 auto layerBlockOp = LayerBlockOp::create(
4446 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4447 layerBlockOp->getRegion(0).push_back(
new Block());
4449 if (getIndentation() > indent)
4450 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4451 layerBlockOp.getLayerName()))
4459ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4460 auto loc = getToken().getLoc();
4463 if (consumeIf(FIRToken::kw_is)) {
4464 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4465 parseOptionalInfo())
4468 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4471 locationProcessor.setLoc(loc);
4472 emitInvalidate(lhs);
4476 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4479 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4483 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4486 locationProcessor.setLoc(loc);
4488 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4489 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4490 if (!lhsType || !rhsType)
4491 return emitError(loc,
"cannot connect reference or property types");
4493 if (lhsType.containsReference() || rhsType.containsReference())
4494 return emitError(loc,
"cannot connect types containing references");
4497 return emitError(loc,
"cannot connect non-equivalent type ")
4498 << rhsType <<
" to " << lhsType;
4507ParseResult FIRStmtParser::parseInstance() {
4508 auto startTok = consumeToken(FIRToken::kw_inst);
4512 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4516 StringRef moduleName;
4517 if (parseId(
id,
"expected instance name") ||
4518 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4519 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4522 locationProcessor.setLoc(startTok.getLoc());
4525 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4526 if (!referencedModule)
4529 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4531 auto annotations = getConstants().emptyArrayAttr;
4532 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4534 hw::InnerSymAttr sym = {};
4535 auto result = InstanceOp::create(
4536 builder, referencedModule,
id, NameKindEnum::InterestingName,
4537 annotations.getValue(), portAnnotations,
false,
false, sym);
4543 unbundledValueEntry.reserve(modulePorts.size());
4544 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4545 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4549 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4550 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4551 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4556ParseResult FIRStmtParser::parseInstanceChoice() {
4557 auto startTok = consumeToken(FIRToken::kw_instchoice);
4558 SMLoc loc = startTok.getLoc();
4561 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4568 StringRef defaultModuleName;
4569 StringRef optionGroupName;
4570 if (parseId(
id,
"expected instance name") ||
4571 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4572 parseId(defaultModuleName,
"expected module name") ||
4573 parseToken(FIRToken::comma,
"expected ','") ||
4574 parseId(optionGroupName,
"expected option group name") ||
4575 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4576 parseOptionalInfo())
4579 locationProcessor.setLoc(startTok.getLoc());
4583 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4587 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4590 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4592 return emitError(loc,
4593 "use of undefined option group '" + optionGroupName +
"'");
4595 auto baseIndent = getIndentation();
4596 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4597 while (getIndentation() == baseIndent) {
4599 StringRef caseModuleName;
4600 if (parseId(caseId,
"expected a case identifier") ||
4601 parseToken(FIRToken::equal_greater,
4602 "expected '=> in instance choice definition") ||
4603 parseId(caseModuleName,
"expected module name"))
4606 auto caseModule = getReferencedModule(loc, caseModuleName);
4610 for (
const auto &[defaultPort, casePort] :
4611 llvm::zip(modulePorts, caseModule.getPorts())) {
4612 if (defaultPort.name != casePort.name)
4613 return emitError(loc,
"instance case module port '")
4614 << casePort.name.getValue()
4615 <<
"' does not match the default module port '"
4616 << defaultPort.name.getValue() <<
"'";
4617 if (defaultPort.type != casePort.type)
4618 return emitError(loc,
"instance case port '")
4619 << casePort.name.getValue()
4620 <<
"' type does not match the default module port";
4624 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4626 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4627 caseModules.emplace_back(optionCase, caseModule);
4630 auto annotations = getConstants().emptyArrayAttr;
4631 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4635 auto result = InstanceChoiceOp::create(
4636 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4637 annotations.getValue(), portAnnotations, sym);
4641 unbundledValueEntry.reserve(modulePorts.size());
4642 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4643 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4645 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4646 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4647 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4650FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4651 StringRef moduleName) {
4652 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4653 if (!referencedModule) {
4655 "use of undefined module name '" + moduleName +
"' in instance");
4658 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4659 emitError(loc,
"cannot create instance of class '" + moduleName +
4660 "', did you mean object?");
4663 return referencedModule;
4667ParseResult FIRStmtParser::parseObject() {
4668 auto startTok = consumeToken(FIRToken::kw_object);
4672 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4679 StringRef className;
4680 if (parseId(
id,
"expected object name") ||
4681 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4682 parseId(className,
"expected class name") || parseOptionalInfo())
4685 locationProcessor.setLoc(startTok.getLoc());
4688 const auto &classMap = getConstants().classMap;
4689 auto lookup = classMap.find(className);
4690 if (lookup == classMap.end())
4691 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4692 className +
"' in object");
4693 auto referencedClass = lookup->getSecond();
4694 auto result = ObjectOp::create(builder, referencedClass,
id);
4695 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4699ParseResult FIRStmtParser::parseCombMem() {
4701 auto startTok = consumeToken(FIRToken::kw_cmem);
4705 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4710 if (parseId(
id,
"expected cmem name") ||
4711 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4712 parseType(type,
"expected cmem type") || parseOptionalInfo())
4715 locationProcessor.setLoc(startTok.getLoc());
4718 auto vectorType = type_dyn_cast<FVectorType>(type);
4720 return emitError(
"cmem requires vector type");
4722 auto annotations = getConstants().emptyArrayAttr;
4723 StringAttr sym = {};
4724 auto result = CombMemOp::create(
4725 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4726 NameKindEnum::InterestingName, annotations, sym);
4727 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4731ParseResult FIRStmtParser::parseSeqMem() {
4733 auto startTok = consumeToken(FIRToken::kw_smem);
4737 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4742 RUWBehavior ruw = RUWBehavior::Undefined;
4744 if (parseId(
id,
"expected smem name") ||
4745 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4749 if (consumeIf(FIRToken::comma)) {
4754 if (parseOptionalInfo()) {
4758 locationProcessor.setLoc(startTok.getLoc());
4761 auto vectorType = type_dyn_cast<FVectorType>(type);
4763 return emitError(
"smem requires vector type");
4765 auto annotations = getConstants().emptyArrayAttr;
4766 StringAttr sym = {};
4767 auto result = SeqMemOp::create(
4768 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4769 id, NameKindEnum::InterestingName, annotations, sym);
4770 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4782ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4783 auto startTok = consumeToken(FIRToken::kw_mem);
4787 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4791 if (parseId(
id,
"expected mem name") ||
4792 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4796 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4797 RUWBehavior ruw = RUWBehavior::Undefined;
4799 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4803 auto nextIndent = getIndentation();
4804 if (!nextIndent || *nextIndent <= memIndent)
4807 auto spelling = getTokenSpelling();
4808 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4809 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4812 if (spelling ==
"data-type") {
4814 return emitError(
"'mem' type specified multiple times"), failure();
4816 if (
parseType(type,
"expected type in data-type declaration"))
4820 if (spelling ==
"depth") {
4821 if (parseIntLit(depth,
"expected integer in depth specification"))
4825 if (spelling ==
"read-latency") {
4826 if (parseIntLit(readLatency,
"expected integer latency"))
4830 if (spelling ==
"write-latency") {
4831 if (parseIntLit(writeLatency,
"expected integer latency"))
4835 if (spelling ==
"read-under-write") {
4836 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4837 FIRToken::kw_undefined))
4838 return emitError(
"expected specifier"), failure();
4840 if (parseOptionalRUW(ruw))
4845 MemOp::PortKind portKind;
4846 if (spelling ==
"reader")
4847 portKind = MemOp::PortKind::Read;
4848 else if (spelling ==
"writer")
4849 portKind = MemOp::PortKind::Write;
4850 else if (spelling ==
"readwriter")
4851 portKind = MemOp::PortKind::ReadWrite;
4853 return emitError(
"unexpected field in 'mem' declaration"), failure();
4856 if (parseId(portName,
"expected port name"))
4858 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4860 return emitError(
"unexpected type, must be base type");
4861 ports.push_back({builder.getStringAttr(portName),
4862 MemOp::getTypeForPort(depth, baseType, portKind)});
4864 while (!getIndentation().has_value()) {
4865 if (parseId(portName,
"expected port name"))
4867 ports.push_back({builder.getStringAttr(portName),
4868 MemOp::getTypeForPort(depth, baseType, portKind)});
4879 llvm::array_pod_sort(ports.begin(), ports.end(),
4880 [](
const std::pair<StringAttr, Type> *lhs,
4881 const std::pair<StringAttr, Type> *rhs) ->
int {
4882 return lhs->first.getValue().compare(
4883 rhs->first.getValue());
4886 auto annotations = getConstants().emptyArrayAttr;
4887 SmallVector<Attribute, 4> resultNames;
4888 SmallVector<Type, 4> resultTypes;
4889 SmallVector<Attribute, 4> resultAnnotations;
4890 for (
auto p : ports) {
4891 resultNames.push_back(p.first);
4892 resultTypes.push_back(p.second);
4893 resultAnnotations.push_back(annotations);
4896 locationProcessor.setLoc(startTok.getLoc());
4898 auto result = MemOp::create(
4899 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4900 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
4901 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4902 MemoryInitAttr(), StringAttr());
4905 unbundledValueEntry.reserve(result.getNumResults());
4906 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4907 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4909 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4910 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4911 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4915ParseResult FIRStmtParser::parseNode() {
4916 auto startTok = consumeToken(FIRToken::kw_node);
4920 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4925 if (parseId(
id,
"expected node name") ||
4926 parseToken(FIRToken::equal,
"expected '=' in node") ||
4927 parseExp(initializer,
"expected expression for node") ||
4928 parseOptionalInfo())
4931 locationProcessor.setLoc(startTok.getLoc());
4943 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4944 auto initializerBaseType =
4945 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4946 if (type_isa<AnalogType>(initializerType) ||
4947 !(initializerBaseType && initializerBaseType.isPassive())) {
4948 emitError(startTok.getLoc())
4949 <<
"Node cannot be analog and must be passive or passive under a flip "
4950 << initializer.getType();
4954 auto annotations = getConstants().emptyArrayAttr;
4955 StringAttr sym = {};
4957 auto result = NodeOp::create(builder, initializer,
id,
4958 NameKindEnum::InterestingName, annotations, sym);
4959 return moduleContext.addSymbolEntry(
id, result.getResult(),
4964ParseResult FIRStmtParser::parseWire() {
4965 auto startTok = consumeToken(FIRToken::kw_wire);
4969 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4974 if (parseId(
id,
"expected wire name") ||
4975 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4976 parseType(type,
"expected wire type") || parseOptionalInfo())
4979 locationProcessor.setLoc(startTok.getLoc());
4981 auto annotations = getConstants().emptyArrayAttr;
4982 StringAttr sym = {};
4985 auto namekind = isa<PropertyType, RefType>(type)
4986 ? NameKindEnum::DroppableName
4987 : NameKindEnum::InterestingName;
4989 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
4990 return moduleContext.addSymbolEntry(
id, result.getResult(),
5004ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5005 auto startTok = consumeToken(FIRToken::kw_reg);
5009 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5018 if (parseId(
id,
"expected reg name") ||
5019 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5021 parseToken(FIRToken::comma,
"expected ','") ||
5022 parseExp(clock,
"expected expression for register clock"))
5025 if (!type_isa<FIRRTLBaseType>(type))
5026 return emitError(startTok.getLoc(),
"register must have base type");
5029 Value resetSignal, resetValue;
5030 if (consumeIf(FIRToken::kw_with)) {
5031 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5034 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5042 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5044 auto indent = getIndentation();
5045 if (!indent || *indent <= regIndent)
5046 if (!hasExtraLParen)
5047 return emitError(
"expected indented reset specifier in reg"), failure();
5049 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5050 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5051 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5052 parseExp(resetSignal,
"expected expression for reset signal") ||
5053 parseToken(FIRToken::comma,
"expected ','"))
5061 if (getTokenSpelling() ==
id) {
5063 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5065 resetSignal = Value();
5067 if (parseExp(resetValue,
"expected expression for reset value") ||
5068 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5072 if (hasExtraLParen &&
5073 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5079 if (parseOptionalInfo())
5082 locationProcessor.setLoc(startTok.getLoc());
5084 ArrayAttr annotations = getConstants().emptyArrayAttr;
5086 StringAttr sym = {};
5089 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5090 NameKindEnum::InterestingName, annotations, sym)
5093 result = RegOp::create(builder, type, clock,
id,
5094 NameKindEnum::InterestingName, annotations, sym)
5096 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5104ParseResult FIRStmtParser::parseRegisterWithReset() {
5105 auto startTok = consumeToken(FIRToken::kw_regreset);
5109 Value clock, resetSignal, resetValue;
5111 if (parseId(
id,
"expected reg name") ||
5112 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5114 parseToken(FIRToken::comma,
"expected ','") ||
5115 parseExp(clock,
"expected expression for register clock") ||
5116 parseToken(FIRToken::comma,
"expected ','") ||
5117 parseExp(resetSignal,
"expected expression for register reset") ||
5118 parseToken(FIRToken::comma,
"expected ','") ||
5119 parseExp(resetValue,
"expected expression for register reset value") ||
5120 parseOptionalInfo())
5123 if (!type_isa<FIRRTLBaseType>(type))
5124 return emitError(startTok.getLoc(),
"register must have base type");
5126 locationProcessor.setLoc(startTok.getLoc());
5129 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5130 NameKindEnum::InterestingName,
5131 getConstants().emptyArrayAttr, StringAttr{})
5134 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5139ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5143 auto startTok = consumeToken(FIRToken::kw_contract);
5146 SmallVector<StringRef> ids;
5147 SmallVector<SMLoc> locs;
5148 SmallVector<Value> values;
5149 SmallVector<Type> types;
5150 if (!consumeIf(FIRToken::colon)) {
5151 auto parseContractId = [&] {
5153 locs.push_back(getToken().
getLoc());
5154 if (parseId(
id,
"expected contract result name"))
5159 auto parseContractValue = [&] {
5161 if (parseExp(value,
"expected expression for contract result"))
5163 values.push_back(value);
5164 types.push_back(value.getType());
5167 if (parseListUntil(FIRToken::equal, parseContractId) ||
5168 parseListUntil(FIRToken::colon, parseContractValue))
5171 if (parseOptionalInfo())
5175 if (ids.size() != values.size())
5176 return emitError(startTok.getLoc())
5177 <<
"contract requires same number of results and expressions; got "
5178 << ids.size() <<
" results and " << values.size()
5179 <<
" expressions instead";
5181 locationProcessor.setLoc(startTok.getLoc());
5185 auto contract = ContractOp::create(builder, types, values);
5186 auto &block = contract.getBody().emplaceBlock();
5190 FIRModuleContext::ContextScope scope(moduleContext, &block);
5191 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5192 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5193 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5196 if (getIndentation() > blockIndent)
5197 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5202 for (
auto [
id, loc, value, result] :
5203 llvm::zip(ids, locs, values, contract.getResults())) {
5205 moduleContext.removeSymbolEntry(
id);
5206 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5219struct FIRCircuitParser :
public FIRParser {
5220 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5222 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5225 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5226 mlir::TimingScope &ts);
5231 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5232 SmallVectorImpl<Attribute> &attrs);
5234 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5236 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5237 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5238 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5239 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5240 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5241 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5242 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5243 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5245 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5247 ParseResult parseLayerName(SymbolRefAttr &result);
5248 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5249 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5250 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5251 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5252 ParseResult parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5253 ArrayAttr &knownLayers);
5255 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5256 SmallVectorImpl<SMLoc> &resultPortLocs,
5260 ParseResult skipToModuleEnd(
unsigned indent);
5262 ParseResult parseTypeDecl();
5264 ParseResult parseOptionDecl(CircuitOp circuit);
5266 ParseResult parseLayer(CircuitOp circuit);
5268 ParseResult resolveDomains(
5269 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5270 const DenseMap<Attribute, size_t> &nameToIndex,
5271 SmallVectorImpl<Attribute> &domainsByIndex);
5274 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5275 const DenseMap<Attribute, size_t> &nameToIndex);
5277 struct DeferredModuleToParse {
5278 FModuleLike moduleOp;
5279 SmallVector<SMLoc> portLocs;
5284 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5285 DeferredModuleToParse &deferredModule,
5286 InnerSymFixups &fixups);
5288 SmallVector<DeferredModuleToParse, 0> deferredModules;
5290 SmallVector<InnerSymFixups, 0> moduleFixups;
5294 ModuleOp mlirModule;
5299FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5300 SmallVectorImpl<Attribute> &attrs) {
5302 auto annotations = json::parse(annotationsStr);
5303 if (
auto err = annotations.takeError()) {
5304 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5305 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5306 diag.attachNote() << a.message();
5311 json::Path::Root root;
5312 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5315 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5316 std::string jsonErrorMessage =
5317 "See inline comments for problem area in JSON:\n";
5318 llvm::raw_string_ostream s(jsonErrorMessage);
5319 root.printErrorContext(annotations.get(), s);
5320 diag.attachNote() << jsonErrorMessage;
5327ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5329 SmallVector<StringRef> strings;
5332 if (parseId(name,
"expected layer name"))
5334 strings.push_back(name);
5335 }
while (consumeIf(FIRToken::period));
5337 SmallVector<FlatSymbolRefAttr> nested;
5338 nested.reserve(strings.size() - 1);
5339 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5340 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5342 result = SymbolRefAttr::get(
context, strings[0], nested);
5346ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5347 SmallVector<Attribute> enabledLayersBuffer;
5349 auto tokenKind = getToken().getKind();
5351 if (tokenKind == FIRToken::kw_enablelayer) {
5352 if (parseEnableLayerSpec(enabledLayersBuffer))
5360 if (enabledLayersBuffer.size() != 0)
5361 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5364 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5368ParseResult FIRCircuitParser::parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5369 ArrayAttr &knownLayers) {
5370 SmallVector<Attribute> enabledLayersBuffer;
5371 SmallVector<Attribute> knownLayersBuffer;
5373 auto tokenKind = getToken().getKind();
5375 if (tokenKind == FIRToken::kw_enablelayer) {
5376 if (parseEnableLayerSpec(enabledLayersBuffer))
5381 if (tokenKind == FIRToken::kw_knownlayer) {
5382 if (parseKnownLayerSpec(knownLayersBuffer))
5390 if (enabledLayersBuffer.size() != 0)
5391 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5394 if (knownLayersBuffer.size() != 0)
5395 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5398 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5399 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5404FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5406 SymbolRefAttr layer;
5407 if (parseLayerName(layer))
5409 result.push_back(layer);
5410 }
while (consumeIf(FIRToken::comma));
5415FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5416 consumeToken(FIRToken::kw_enablelayer);
5417 return parseLayerList(result);
5421FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5422 consumeToken(FIRToken::kw_knownlayer);
5423 return parseLayerList(result);
5430FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5431 SmallVectorImpl<SMLoc> &resultPortLocs,
5437 DenseMap<Attribute, size_t> nameToIndex;
5438 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5441 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5443 getIndentation() > indent) {
5449 auto backtrackState = getLexer().getCursor();
5451 bool isOutput = getToken().is(FIRToken::kw_output);
5456 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5457 !getToken().isKeyword()) {
5458 backtrackState.restore(getLexer());
5465 if (parseId(name,
"expected port name") ||
5466 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5467 parseType(type,
"expected a type in port declaration"))
5469 Attribute domainInfoElement = {};
5470 size_t portIdx = resultPorts.size();
5471 if (isa<DomainType>(type)) {
5472 StringAttr domainKind;
5473 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type port") ||
5474 parseId(domainKind,
"expected domain kind"))
5476 domainInfoElement = FlatSymbolRefAttr::get(domainKind);
5478 if (getToken().is(FIRToken::kw_domains))
5479 if (parseDomains(domainNames[portIdx], nameToIndex))
5483 if (
info.parseOptionalInfo())
5486 StringAttr innerSym = {};
5487 resultPorts.push_back(
PortInfo{name,
5493 domainInfoElement});
5494 resultPortLocs.push_back(
info.getFIRLoc());
5495 nameToIndex.insert({name, portIdx});
5499 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5500 auto &port = resultPorts[portIdx];
5501 Attribute &attr = port.domains;
5505 SmallVector<Attribute> domainInfo;
5506 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5508 attr = ArrayAttr::get(getContext(), domainInfo);
5513 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5514 PortInfo &port = std::get<0>(portAndLoc);
5515 auto &entry = portIds[port.
name];
5516 if (!entry.isValid()) {
5517 entry = std::get<1>(portAndLoc);
5521 emitError(std::get<1>(portAndLoc),
5522 "redefinition of name '" + port.
getName() +
"'")
5523 .attachNote(translateLocation(entry))
5524 <<
"previous definition here";
5533ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5535 switch (getToken().getKind()) {
5539 case FIRToken::error:
5543 case FIRToken::kw_class:
5544 case FIRToken::kw_domain:
5545 case FIRToken::kw_declgroup:
5546 case FIRToken::kw_extclass:
5547 case FIRToken::kw_extmodule:
5548 case FIRToken::kw_intmodule:
5549 case FIRToken::kw_formal:
5550 case FIRToken::kw_module:
5551 case FIRToken::kw_public:
5552 case FIRToken::kw_layer:
5553 case FIRToken::kw_option:
5554 case FIRToken::kw_simulation:
5555 case FIRToken::kw_type:
5559 if (getIndentation() == indent)
5571ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5572 SmallVector<Attribute, 8> parameters;
5573 SmallPtrSet<StringAttr, 8> seen;
5574 while (consumeIf(FIRToken::kw_parameter)) {
5578 if (parseParameter(name, value, loc))
5580 auto typedValue = dyn_cast<TypedAttr>(value);
5582 return emitError(loc)
5583 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5584 if (!seen.insert(name).second)
5585 return emitError(loc,
5586 "redefinition of parameter '" + name.getValue() +
"'");
5587 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5589 resultParameters = ArrayAttr::get(getContext(), parameters);
5594ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5596 SmallVector<PortInfo, 8> portList;
5597 SmallVector<SMLoc> portLocs;
5603 consumeToken(FIRToken::kw_class);
5604 if (parseId(name,
"expected class name") ||
5605 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5609 if (name == circuit.getName())
5610 return mlir::emitError(
info.getLoc(),
5611 "class cannot be the top of a circuit");
5613 for (
auto &portInfo : portList)
5615 return
mlir::emitError(portInfo.loc,
5616 "ports on classes must be properties");
5619 auto builder = circuit.getBodyBuilder();
5620 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5621 classOp.setPrivate();
5622 deferredModules.emplace_back(
5623 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5626 getConstants().classMap[name.getValue()] = classOp;
5627 return skipToModuleEnd(indent);
5631ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5632 consumeToken(FIRToken::kw_domain);
5636 if (parseId(name,
"domain name") ||
5637 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5638 info.parseOptionalInfo())
5641 SmallVector<Attribute> fields;
5643 auto nextIndent = getIndentation();
5644 if (!nextIndent || *nextIndent <= indent)
5647 StringAttr fieldName;
5649 if (parseId(fieldName,
"field name") ||
5650 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5651 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5655 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5658 auto builder = circuit.getBodyBuilder();
5659 DomainOp::create(builder,
info.getLoc(), name, builder.getArrayAttr(fields));
5665ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5668 SmallVector<PortInfo, 8> portList;
5669 SmallVector<SMLoc> portLocs;
5675 consumeToken(FIRToken::kw_extclass);
5676 if (parseId(name,
"expected extclass name") ||
5677 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5681 if (name == circuit.getName())
5682 return mlir::emitError(
info.getLoc(),
5683 "extclass cannot be the top of a circuit");
5685 for (
auto &portInfo : portList)
5687 return
mlir::emitError(portInfo.loc,
5688 "ports on extclasses must be properties");
5691 auto builder = circuit.getBodyBuilder();
5692 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5695 getConstants().classMap[name.getValue()] = extClassOp;
5696 return skipToModuleEnd(indent);
5703ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5706 ArrayAttr enabledLayers;
5707 ArrayAttr knownLayers;
5708 SmallVector<PortInfo, 8> portList;
5709 SmallVector<SMLoc> portLocs;
5711 consumeToken(FIRToken::kw_extmodule);
5712 if (parseId(name,
"expected extmodule name") ||
5713 parseExtModuleLayerSpec(enabledLayers, knownLayers) ||
5714 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5719 if (consumeIf(FIRToken::kw_defname)) {
5720 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5721 parseId(defName,
"expected defname name"))
5725 ArrayAttr parameters;
5730 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5731 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5732 if (ftype.hasUninferredWidth())
5733 return emitError(loc,
"extmodule port must have known width");
5738 auto builder = circuit.getBodyBuilder();
5739 auto isMainModule = (name == circuit.getName());
5741 (isMainModule && getConstants().options.scalarizePublicModules) ||
5742 getConstants().options.scalarizeExtModules
5743 ? Convention::Scalarized
5744 : Convention::Internal;
5745 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5746 auto annotations = ArrayAttr::get(getContext(), {});
5747 auto extModuleOp = FExtModuleOp::create(
5748 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5749 defName, annotations, parameters, enabledLayers);
5750 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5751 : SymbolTable::Visibility::Private;
5752 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5760ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5764 ArrayAttr enabledLayers;
5765 SmallVector<PortInfo, 8> portList;
5766 SmallVector<SMLoc> portLocs;
5768 consumeToken(FIRToken::kw_intmodule);
5769 if (parseId(name,
"expected intmodule name") ||
5770 parseModuleLayerSpec(enabledLayers) ||
5771 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5773 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5774 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5775 parseId(intName,
"expected intrinsic name"))
5778 ArrayAttr parameters;
5782 ArrayAttr annotations = getConstants().emptyArrayAttr;
5783 auto builder = circuit.getBodyBuilder();
5784 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5785 annotations, parameters, enabledLayers)
5791ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5794 SmallVector<PortInfo, 8> portList;
5795 SmallVector<SMLoc> portLocs;
5796 ArrayAttr enabledLayers;
5797 auto modLoc = getToken().getLoc();
5798 LocWithInfo
info(modLoc,
this);
5799 consumeToken(FIRToken::kw_module);
5800 if (parseId(name,
"expected module name") ||
5801 parseModuleLayerSpec(enabledLayers) ||
5802 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5807 if (name == circuit.getName()) {
5808 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5813 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5814 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5815 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5816 if (ftype.hasUninferredWidth())
5817 return emitError(loc,
"public module port must have known width");
5818 if (ftype.hasUninferredReset())
5819 return emitError(loc,
5820 "public module port must have concrete reset type");
5825 ArrayAttr annotations = getConstants().emptyArrayAttr;
5826 auto convention = Convention::Internal;
5827 if (isPublic && getConstants().options.scalarizePublicModules)
5828 convention = Convention::Scalarized;
5829 if (!isPublic && getConstants().options.scalarizeInternalModules)
5830 convention = Convention::Scalarized;
5831 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5832 auto builder = circuit.getBodyBuilder();
5834 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
5835 annotations, enabledLayers);
5837 auto visibility = isPublic ? SymbolTable::Visibility::Public
5838 : SymbolTable::Visibility::Private;
5839 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5843 deferredModules.emplace_back(DeferredModuleToParse{
5844 moduleOp, portLocs, getLexer().getCursor(), indent});
5846 if (skipToModuleEnd(indent))
5852ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5853 consumeToken(FIRToken::kw_formal);
5854 return parseFormalLike<FormalOp>(circuit, indent);
5858ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5860 consumeToken(FIRToken::kw_simulation);
5861 return parseFormalLike<SimulationOp>(circuit, indent);
5868ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5870 StringRef id, moduleName;
5873 auto builder = circuit.getBodyBuilder();
5876 if (parseId(
id,
"expected test name") ||
5877 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5878 parseId(moduleName,
"expected module name"))
5882 NamedAttrList params;
5883 if (consumeIf(FIRToken::comma)) {
5885 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5886 return emitError(
"expected 'bound' after ','");
5888 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5889 parseIntLit(bound,
"expected integer bound after '='"))
5892 return emitError(
"bound must be a positive integer");
5893 if (
info.parseOptionalInfo())
5895 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5898 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5899 info.parseOptionalInfo())
5901 while (getIndentation() > indent) {
5902 StringAttr paramName;
5903 Attribute paramValue;
5905 if (parseParameter(paramName, paramValue, paramLoc,
5908 if (params.set(paramName, paramValue))
5909 return emitError(paramLoc,
"redefinition of parameter '" +
5910 paramName.getValue() +
"'");
5914 Op::create(builder,
info.getLoc(),
id, moduleName,
5915 params.getDictionary(getContext()));
5919ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5921 switch (getToken().getKind()) {
5922 case FIRToken::kw_class:
5923 return parseClass(circuit, indent);
5924 case FIRToken::kw_declgroup:
5925 if (requireFeature({3, 2, 0},
"optional groups") ||
5926 removedFeature({3, 3, 0},
"optional groups"))
5928 return parseLayer(circuit);
5929 case FIRToken::kw_domain:
5932 return parseDomain(circuit, indent);
5933 case FIRToken::kw_extclass:
5934 return parseExtClass(circuit, indent);
5935 case FIRToken::kw_extmodule:
5936 return parseExtModule(circuit, indent);
5937 case FIRToken::kw_formal:
5938 if (requireFeature({4, 0, 0},
"formal tests"))
5940 return parseFormal(circuit, indent);
5941 case FIRToken::kw_intmodule:
5942 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
5943 removedFeature({4, 0, 0},
"intrinsic modules"))
5945 return parseIntModule(circuit, indent);
5946 case FIRToken::kw_layer:
5947 if (requireFeature({3, 3, 0},
"layers"))
5949 return parseLayer(circuit);
5950 case FIRToken::kw_module:
5951 return parseModule(circuit,
false, indent);
5952 case FIRToken::kw_public:
5953 if (requireFeature({3, 3, 0},
"public modules"))
5956 if (getToken().getKind() == FIRToken::kw_module)
5957 return parseModule(circuit,
true, indent);
5958 return emitError(getToken().
getLoc(),
"only modules may be public");
5959 case FIRToken::kw_simulation:
5962 return parseSimulation(circuit, indent);
5963 case FIRToken::kw_type:
5964 return parseTypeDecl();
5965 case FIRToken::kw_option:
5968 return parseOptionDecl(circuit);
5970 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
5975ParseResult FIRCircuitParser::parseTypeDecl() {
5979 auto loc = getToken().getLoc();
5981 if (getToken().isKeyword())
5982 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
5983 <<
"' for type alias name";
5985 if (parseId(
id,
"expected type name") ||
5986 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
5989 auto name = StringAttr::get(type.getContext(),
id);
5992 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
5993 type = BaseTypeAliasType::get(name, base);
5996 <<
"type alias for non-base type " << type
5997 <<
" is currently not supported. Type alias is stripped immediately";
5999 if (!getConstants().aliasMap.insert({id, type}).second)
6000 return emitError(loc) <<
"type alias `" << name.getValue()
6001 <<
"` is already defined";
6006ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6009 auto loc = getToken().getLoc();
6012 if (parseId(
id,
"expected an option group name") ||
6013 parseToken(FIRToken::colon,
6014 "expected ':' after option group definition") ||
6015 info.parseOptionalInfo())
6018 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6019 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6020 auto *block =
new Block;
6021 optionOp.getBody().push_back(block);
6022 builder.setInsertionPointToEnd(block);
6024 auto baseIndent = getIndentation();
6026 while (getIndentation() == baseIndent) {
6028 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6029 if (parseId(
id,
"expected an option case ID") ||
6030 caseInfo.parseOptionalInfo())
6033 if (!cases.insert(
id).second)
6034 return emitError(loc)
6035 <<
"duplicate option case definition '" <<
id <<
"'";
6037 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6044ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6045 auto baseIndent = getIndentation();
6048 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6051 auto parseOne = [&](
Block *block) -> ParseResult {
6052 auto indent = getIndentation();
6053 StringRef id, convention;
6056 if (parseId(
id,
"expected layer name") ||
6057 parseToken(FIRToken::comma,
"expected ','") ||
6058 parseGetSpelling(convention))
6061 auto layerConvention = symbolizeLayerConvention(convention);
6062 if (!layerConvention) {
6063 emitError() <<
"unknown convention '" << convention
6064 <<
"' (did you misspell it?)";
6067 if (layerConvention == LayerConvention::Inline &&
6068 requireFeature({4, 1, 0},
"inline layers"))
6072 hw::OutputFileAttr outputDir;
6073 if (consumeIf(FIRToken::comma)) {
6074 if (getToken().getKind() == FIRToken::string) {
6075 auto text = getToken().getStringValue();
6077 return emitError() <<
"output directory must not be blank";
6078 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6079 consumeToken(FIRToken::string);
6083 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6084 info.parseOptionalInfo())
6086 auto builder = OpBuilder::atBlockEnd(block);
6089 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6090 layerOp->getRegion(0).push_back(
new Block());
6092 layerOp->setAttr(
"output_file", outputDir);
6093 layerStack.push_back({indent, layerOp});
6097 if (parseOne(circuit.getBodyBlock()))
6101 while (getIndentation() > baseIndent) {
6102 switch (getToken().getKind()) {
6103 case FIRToken::kw_declgroup:
6104 case FIRToken::kw_layer: {
6107 while (layerStack.back().first >= getIndentation())
6108 layerStack.pop_back();
6109 auto parentLayer = layerStack.back().second;
6110 if (parseOne(&parentLayer.getBody().front()))
6115 return emitError(
"expected 'layer'"), failure();
6122ParseResult FIRCircuitParser::resolveDomains(
6123 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6124 const DenseMap<Attribute, size_t> &nameToIndex,
6125 SmallVectorImpl<Attribute> &domainsByIndex) {
6127 for (
auto [attr, loc] : domainsByName) {
6128 auto domain = cast<StringAttr>(attr);
6129 auto indexItr = nameToIndex.find(domain);
6130 if (indexItr == nameToIndex.end()) {
6131 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6134 domainsByIndex.push_back(IntegerAttr::get(
6135 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6142ParseResult FIRCircuitParser::parseDomains(
6143 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6144 const DenseMap<Attribute, size_t> &nameToIndex) {
6147 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6148 parseToken(FIRToken::l_square,
"expected '['"))
6151 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6153 auto domainLoc = getToken().getLoc();
6154 if (parseId(domain,
"expected domain name"))
6156 domains.push_back({domain, domainLoc});
6166FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6167 DeferredModuleToParse &deferredModule,
6168 InnerSymFixups &fixups) {
6169 FModuleLike moduleOp = deferredModule.moduleOp;
6170 auto &body = moduleOp->getRegion(0).front();
6171 auto &portLocs = deferredModule.portLocs;
6175 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6178 deferredModule.lexerCursor.restore(moduleBodyLexer);
6180 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6185 auto portList = moduleOp.getPorts();
6186 auto portArgs = body.getArguments();
6187 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6188 PortInfo &port = std::get<0>(tuple);
6189 llvm::SMLoc loc = std::get<1>(tuple);
6190 BlockArgument portArg = std::get<2>(tuple);
6192 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6196 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6199 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6205 size_t numVerifPrintfs = 0;
6206 std::optional<Location> printfLoc;
6208 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6213 printfLoc = printFOp.getLoc();
6216 if (numVerifPrintfs > 0) {
6218 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6220 <<
" printf-encoded verification operation(s), which are no longer "
6222 diag.attachNote(*printfLoc)
6223 <<
"example printf here, this is now just a printf and nothing more";
6224 diag.attachNote() <<
"For more information, see "
6225 "https://github.com/llvm/circt/issues/6970";
6239ParseResult FIRCircuitParser::parseCircuit(
6240 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6241 mlir::TimingScope &ts) {
6243 auto indent = getIndentation();
6244 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6246 if (!indent.has_value())
6247 return emitError(
"'FIRRTL' must be first token on its line");
6248 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6249 parseVersionLit(
"expected version literal"))
6251 indent = getIndentation();
6253 if (!indent.has_value())
6254 return emitError(
"'circuit' must be first token on its line");
6255 unsigned circuitIndent = *indent;
6259 SMLoc inlineAnnotationsLoc;
6260 StringRef inlineAnnotations;
6263 if (parseToken(FIRToken::kw_circuit,
6264 "expected a top-level 'circuit' definition") ||
6265 parseId(name,
"expected circuit name") ||
6266 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6267 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6268 info.parseOptionalInfo())
6272 OpBuilder b(mlirModule.getBodyRegion());
6273 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6276 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6282 SmallVector<Attribute> annos;
6283 if (!inlineAnnotations.empty())
6284 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6288 for (
auto *annotationsBuf : annotationsBufs)
6289 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6293 parseAnnotationTimer.stop();
6301 auto parseTimer = ts.nest(
"Parse modules");
6302 deferredModules.reserve(16);
6306 switch (getToken().getKind()) {
6314 case FIRToken::error:
6318 emitError(
"unexpected token in circuit");
6321 case FIRToken::kw_class:
6322 case FIRToken::kw_declgroup:
6323 case FIRToken::kw_domain:
6324 case FIRToken::kw_extclass:
6325 case FIRToken::kw_extmodule:
6326 case FIRToken::kw_intmodule:
6327 case FIRToken::kw_layer:
6328 case FIRToken::kw_formal:
6329 case FIRToken::kw_module:
6330 case FIRToken::kw_option:
6331 case FIRToken::kw_public:
6332 case FIRToken::kw_simulation:
6333 case FIRToken::kw_type: {
6334 auto indent = getIndentation();
6335 if (!indent.has_value())
6336 return emitError(
"'module' must be first token on its line"), failure();
6337 unsigned definitionIndent = *indent;
6339 if (definitionIndent <= circuitIndent)
6340 return emitError(
"module should be indented more"), failure();
6342 if (parseToplevelDefinition(circuit, definitionIndent))
6356 (void)getLexer().translateLocation(
info.getFIRLoc());
6362 DenseMap<Attribute, Location> nameToOrigLoc;
6366 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6371 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6374 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6375 .attachNote(it.first->second)
6376 .append(
"see existing symbol definition here");
6382 SymbolTable circuitSymTbl(circuit);
6384 moduleFixups.resize(deferredModules.size());
6389 for (
auto &d : deferredModules)
6390 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6393 auto anyFailed = mlir::failableParallelForEachN(
6394 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6395 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6396 moduleFixups[index]))
6400 if (failed(anyFailed))
6405 for (
auto &fixups : moduleFixups) {
6406 if (failed(fixups.resolve(innerSymbolNamespaces)))
6412 auto parseLayerName = [&](StringRef name) -> Attribute {
6414 auto [head, rest] = name.split(
".");
6415 SmallVector<FlatSymbolRefAttr> nestedRefs;
6416 while (!rest.empty()) {
6418 std::tie(next, rest) = rest.split(
".");
6419 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6421 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6424 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6425 SmallVector<Attribute> attrArray;
6427 for (
const auto &str : strArray)
6428 attrArray.push_back(getAttr(str));
6429 if (attrArray.empty())
6431 return ArrayAttr::get(
context, attrArray);
6434 if (
auto enableLayers =
6435 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6436 circuit.setEnableLayersAttr(enableLayers);
6437 if (
auto disableLayers =
6438 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6439 circuit.setDisableLayersAttr(disableLayers);
6441 auto getStrAttr = [&](StringRef str) -> Attribute {
6442 return StringAttr::get(getContext(), str);
6445 if (
auto selectInstChoice =
6446 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6447 circuit.setSelectInstChoiceAttr(selectInstChoice);
6449 circuit.setDefaultLayerSpecialization(
6450 getConstants().options.defaultLayerSpecialization);
6463 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6464 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6465 unsigned fileID = 1;
6467 annotationsBufs.push_back(
6468 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6470 context->loadDialect<CHIRRTLDialect>();
6471 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6475 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6478 SharedParserConstants state(
context, options);
6481 .parseCircuit(annotationsBufs, ts))
6486 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6487 if (failed(verify(*module)))
6494 static mlir::TranslateToMLIRRegistration fromFIR(
6495 "import-firrtl",
"import .fir",
6496 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6497 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
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::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
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.
StringRef getName() const