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 {
70 : context(context), options(options),
71 emptyArrayAttr(ArrayAttr::
get(context, {})),
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"))) {}
80 MLIRContext *
const context;
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);
2034 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
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) {
3136 SmallVector<Attribute, 4> specialSubstitutions;
3137 SmallString<64> validatedFormatString;
3139 validatedFormatString = formatString;
3140 operands.append(specOperands.begin(), specOperands.end());
3142 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
3143 auto c = formatString[i];
3148 validatedFormatString.push_back(c);
3151 SmallString<6> width;
3152 c = formatString[++i];
3155 c = formatString[++i];
3161 if (!width.empty()) {
3162 emitError(formatStringLoc) <<
"ASCII character format specifiers "
3163 "('%c') may not specify a width";
3171 validatedFormatString.append(width);
3172 operands.push_back(specOperands[opIdx++]);
3175 if (!width.empty()) {
3176 emitError(formatStringLoc)
3177 <<
"literal percents ('%%') may not specify a width";
3183 emitError(formatStringLoc)
3184 <<
"unknown printf substitution '%" << width << c <<
"'";
3187 validatedFormatString.push_back(c);
3195 if (formatString[i + 1] !=
'{') {
3196 validatedFormatString.push_back(c);
3202 while (formatString[i] !=
'}')
3204 if (formatString[i] !=
'}') {
3205 llvm::errs() <<
"expected '}' to terminate special substitution";
3209 auto specialString = formatString.slice(start, i);
3210 if (specialString ==
"SimulationTime") {
3211 operands.push_back(TimeOp::create(builder));
3212 }
else if (specialString ==
"HierarchicalModuleName") {
3213 operands.push_back(HierarchicalModuleNameOp::create(builder));
3215 emitError(formatStringLoc)
3216 <<
"unknown printf substitution '" << specialString
3217 <<
"' (did you misspell it?)";
3221 validatedFormatString.append(
"{{}}");
3226 validatedFormatString.push_back(c);
3231 formatStringResult =
3237ParseResult FIRStmtParser::parsePrintf() {
3238 auto startTok = consumeToken(FIRToken::lp_printf);
3240 Value clock, condition;
3241 StringRef formatString;
3242 if (parseExp(clock,
"expected clock expression in printf") ||
3243 parseToken(FIRToken::comma,
"expected ','") ||
3244 parseExp(condition,
"expected condition in printf") ||
3245 parseToken(FIRToken::comma,
"expected ','"))
3248 auto formatStringLoc = getToken().getLoc();
3249 if (parseGetSpelling(formatString) ||
3250 parseToken(FIRToken::string,
"expected format string in printf"))
3253 SmallVector<Value, 4> specOperands;
3254 while (consumeIf(FIRToken::comma)) {
3255 specOperands.push_back({});
3256 if (parseExp(specOperands.back(),
"expected operand in printf"))
3261 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3262 parseOptionalName(name) || parseOptionalInfo())
3265 locationProcessor.setLoc(startTok.getLoc());
3267 StringAttr formatStrUnescaped;
3268 SmallVector<Value> operands;
3269 if (parseFormatString(formatStringLoc, formatString, specOperands,
3270 formatStrUnescaped, operands))
3273 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3279ParseResult FIRStmtParser::parseFPrintf() {
3282 auto startTok = consumeToken(FIRToken::lp_fprintf);
3284 Value clock, condition;
3285 StringRef outputFile, formatString;
3286 if (parseExp(clock,
"expected clock expression in fprintf") ||
3287 parseToken(FIRToken::comma,
"expected ','") ||
3288 parseExp(condition,
"expected condition in fprintf") ||
3289 parseToken(FIRToken::comma,
"expected ','"))
3292 auto outputFileLoc = getToken().getLoc();
3293 if (parseGetSpelling(outputFile) ||
3294 parseToken(FIRToken::string,
"expected output file in fprintf"))
3297 SmallVector<Value, 4> outputFileSpecOperands;
3298 while (consumeIf(FIRToken::comma)) {
3300 if (getToken().getKind() == FIRToken::string)
3302 outputFileSpecOperands.push_back({});
3303 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3307 auto formatStringLoc = getToken().getLoc();
3308 if (parseGetSpelling(formatString) ||
3309 parseToken(FIRToken::string,
"expected format string in printf"))
3312 SmallVector<Value, 4> specOperands;
3313 while (consumeIf(FIRToken::comma)) {
3314 specOperands.push_back({});
3315 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3320 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3321 parseOptionalName(name) || parseOptionalInfo())
3324 locationProcessor.setLoc(startTok.getLoc());
3326 StringAttr outputFileNameStrUnescaped;
3327 SmallVector<Value> outputFileOperands;
3328 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3329 outputFileNameStrUnescaped, outputFileOperands))
3332 StringAttr formatStrUnescaped;
3333 SmallVector<Value> operands;
3334 if (parseFormatString(formatStringLoc, formatString, specOperands,
3335 formatStrUnescaped, operands))
3338 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3339 outputFileOperands, formatStrUnescaped, operands, name);
3344ParseResult FIRStmtParser::parseFFlush() {
3348 auto startTok = consumeToken(FIRToken::lp_fflush);
3350 Value clock, condition;
3351 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3352 parseToken(FIRToken::comma,
"expected ','") ||
3353 parseExp(condition,
"expected condition in 'fflush'"))
3356 locationProcessor.setLoc(startTok.getLoc());
3357 StringAttr outputFileNameStrUnescaped;
3358 SmallVector<Value> outputFileOperands;
3360 if (consumeIf(FIRToken::comma)) {
3361 SmallVector<Value, 4> outputFileSpecOperands;
3362 auto outputFileLoc = getToken().getLoc();
3363 StringRef outputFile;
3364 if (parseGetSpelling(outputFile) ||
3365 parseToken(FIRToken::string,
"expected output file in fflush"))
3368 while (consumeIf(FIRToken::comma)) {
3369 outputFileSpecOperands.push_back({});
3370 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3374 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3375 outputFileNameStrUnescaped, outputFileOperands))
3379 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3380 parseOptionalInfo())
3383 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3384 outputFileOperands);
3389ParseResult FIRStmtParser::parseSkip() {
3390 auto startTok = consumeToken(FIRToken::kw_skip);
3394 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3397 if (parseOptionalInfo())
3400 locationProcessor.setLoc(startTok.getLoc());
3401 SkipOp::create(builder);
3406ParseResult FIRStmtParser::parseStop() {
3407 auto startTok = consumeToken(FIRToken::lp_stop);
3409 Value clock, condition;
3412 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3413 parseToken(FIRToken::comma,
"expected ','") ||
3414 parseExp(condition,
"expected condition in 'stop'") ||
3415 parseToken(FIRToken::comma,
"expected ','") ||
3416 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3417 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3418 parseOptionalName(name) || parseOptionalInfo())
3421 locationProcessor.setLoc(startTok.getLoc());
3422 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3428ParseResult FIRStmtParser::parseAssert() {
3429 auto startTok = consumeToken(FIRToken::lp_assert);
3431 Value clock, predicate, enable;
3432 StringRef formatString;
3434 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3435 parseToken(FIRToken::comma,
"expected ','") ||
3436 parseExp(predicate,
"expected predicate in 'assert'") ||
3437 parseToken(FIRToken::comma,
"expected ','") ||
3438 parseExp(enable,
"expected enable in 'assert'") ||
3439 parseToken(FIRToken::comma,
"expected ','") ||
3440 parseGetSpelling(formatString) ||
3441 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3444 SmallVector<Value, 4> operands;
3445 while (!consumeIf(FIRToken::r_paren)) {
3446 operands.push_back({});
3447 if (parseToken(FIRToken::comma,
"expected ','") ||
3448 parseExp(operands.back(),
"expected operand in 'assert'"))
3452 if (parseOptionalName(name) || parseOptionalInfo())
3455 locationProcessor.setLoc(startTok.getLoc());
3457 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3458 operands, name.getValue());
3463ParseResult FIRStmtParser::parseAssume() {
3464 auto startTok = consumeToken(FIRToken::lp_assume);
3466 Value clock, predicate, enable;
3467 StringRef formatString;
3469 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3470 parseToken(FIRToken::comma,
"expected ','") ||
3471 parseExp(predicate,
"expected predicate in 'assume'") ||
3472 parseToken(FIRToken::comma,
"expected ','") ||
3473 parseExp(enable,
"expected enable in 'assume'") ||
3474 parseToken(FIRToken::comma,
"expected ','") ||
3475 parseGetSpelling(formatString) ||
3476 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3479 SmallVector<Value, 4> operands;
3480 while (!consumeIf(FIRToken::r_paren)) {
3481 operands.push_back({});
3482 if (parseToken(FIRToken::comma,
"expected ','") ||
3483 parseExp(operands.back(),
"expected operand in 'assume'"))
3487 if (parseOptionalName(name) || parseOptionalInfo())
3490 locationProcessor.setLoc(startTok.getLoc());
3492 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3493 operands, name.getValue());
3498ParseResult FIRStmtParser::parseCover() {
3499 auto startTok = consumeToken(FIRToken::lp_cover);
3501 Value clock, predicate, enable;
3504 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3505 parseToken(FIRToken::comma,
"expected ','") ||
3506 parseExp(predicate,
"expected predicate in 'cover'") ||
3507 parseToken(FIRToken::comma,
"expected ','") ||
3508 parseExp(enable,
"expected enable in 'cover'") ||
3509 parseToken(FIRToken::comma,
"expected ','") ||
3510 parseGetSpelling(message) ||
3511 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3512 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3513 parseOptionalName(name) || parseOptionalInfo())
3516 locationProcessor.setLoc(startTok.getLoc());
3518 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3519 ValueRange{}, name.getValue());
3525ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3526 auto startTok = consumeToken(FIRToken::kw_when);
3530 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3534 if (parseExp(condition,
"expected condition in 'when'") ||
3535 parseToken(FIRToken::colon,
"expected ':' in when") ||
3536 parseOptionalInfo())
3539 locationProcessor.setLoc(startTok.getLoc());
3541 auto whenStmt = WhenOp::create(builder, condition,
false);
3544 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3548 if (getToken().isNot(FIRToken::kw_else))
3553 auto elseIndent = getIndentation();
3554 if (elseIndent && *elseIndent < whenIndent)
3557 consumeToken(FIRToken::kw_else);
3560 whenStmt.createElseRegion();
3566 if (getToken().is(FIRToken::kw_when)) {
3568 auto subParser = std::make_unique<FIRStmtParser>(
3569 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3572 return subParser->parseSimpleStmt(whenIndent);
3576 LocationAttr elseLoc;
3577 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3578 parseOptionalInfoLocator(elseLoc) ||
3579 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3588ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3589 auto startLoc = getToken().getLoc();
3590 locationProcessor.setLoc(startLoc);
3592 if (parseEnumType(type))
3596 auto enumType = type_dyn_cast<FEnumType>(type);
3598 return emitError(startLoc,
3599 "expected enumeration type in enumeration expression");
3602 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3603 parseId(tag,
"expected enumeration tag"))
3607 if (consumeIf(FIRToken::r_paren)) {
3610 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3611 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3612 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3613 input = ConstantOp::create(builder, type, attr);
3616 if (parseToken(FIRToken::comma,
"expected ','") ||
3617 parseExp(input,
"expected expression in enumeration value") ||
3618 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3622 value = FEnumCreateOp::create(builder, enumType, tag, input);
3630ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3631 auto startTok = consumeToken(FIRToken::kw_match);
3633 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3637 if (parseExp(input,
"expected expression in 'match'") ||
3638 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3639 parseOptionalInfo())
3642 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3644 return mlir::emitError(
3646 "expected enumeration type for 'match' statement, but got ")
3649 locationProcessor.setLoc(startTok.getLoc());
3651 SmallVector<Attribute> tags;
3652 SmallVector<std::unique_ptr<Region>> regions;
3654 auto tagLoc = getToken().getLoc();
3657 auto caseIndent = getIndentation();
3658 if (!caseIndent || *caseIndent <= matchIndent)
3662 StringRef tagSpelling;
3663 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3665 auto tagIndex = enumType.getElementIndex(tagSpelling);
3667 return emitError(tagLoc,
"tag ")
3668 << tagSpelling <<
" not a member of enumeration " << enumType;
3669 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3670 tags.push_back(tag);
3673 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3676 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3681 UnbundledValueRestorer x(moduleContext.unbundledValues);
3684 if (consumeIf(FIRToken::l_paren)) {
3685 StringAttr identifier;
3686 if (parseId(identifier,
"expected identifier for 'case' binding"))
3690 auto dataType = enumType.getElementType(*tagIndex);
3691 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3693 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3697 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3701 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3702 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3705 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3709 auto subParser = std::make_unique<FIRStmtParser>(
3710 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3712 if (subParser->parseSimpleStmtBlock(*caseIndent))
3716 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3723ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3724 auto loc = getToken().getLoc();
3727 if (parseId(
id,
"expected domain expression") ||
3728 moduleContext.lookupSymbolEntry(entry,
id, loc))
3731 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3733 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3734 parseFieldId(field,
"expected field name") ||
3735 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3739 if (parseOptionalExpPostscript(result,
false))
3742 auto type = result.getType();
3743 if (!type_isa<DomainType>(type))
3744 return emitError(loc) <<
"expected domain-type expression, got " << type;
3751ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3752 auto token = getToken().getKind();
3753 if (token == FIRToken::lp_probe)
3754 return parseProbe(result);
3755 if (token == FIRToken::lp_rwprobe)
3756 return parseRWProbe(result);
3761 return parseStaticRefExp(result, message);
3768ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3769 const Twine &message) {
3770 auto parseIdOrInstance = [&]() -> ParseResult {
3772 auto loc = getToken().getLoc();
3774 if (parseId(
id, message) ||
3775 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3779 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3782 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3785 StringRef fieldName;
3787 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3788 parseFieldId(fieldName,
"expected field name") ||
3789 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3791 return failure(parseIdOrInstance() ||
3792 parseOptionalExpPostscript(result,
false));
3803ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3805 const Twine &message) {
3806 auto loc = getToken().getLoc();
3810 if (parseId(
id, message) ||
3811 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3823 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3825 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3827 StringRef fieldName;
3828 auto loc = getToken().getLoc();
3829 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3830 parseFieldId(fieldName,
"expected field name"))
3835 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3836 for (
auto &elt : ubEntry) {
3837 if (elt.first == fieldAttr) {
3840 auto &instResult = elt.second;
3843 auto *defining = instResult.getDefiningOp();
3845 if (isa<WireOp>(defining)) {
3846 result = instResult;
3851 auto type = instResult.getType();
3855 bool forceable =
static_cast<bool>(
3858 return emitError(loc,
"unable to force instance result of type ")
3862 auto annotations = getConstants().emptyArrayAttr;
3863 StringAttr sym = {};
3864 SmallString<64> name;
3865 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3866 locationProcessor.setLoc(loc);
3867 OpBuilder::InsertionGuard guard(builder);
3868 builder.setInsertionPoint(defining);
3870 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3872 auto bounceVal = bounce.getData();
3875 instResult.replaceAllUsesWith(bounceVal);
3878 builder.setInsertionPointAfter(defining);
3879 if (
foldFlow(instResult) == Flow::Source)
3886 result = instResult = bounce.getDataRaw();
3892 emitError(loc,
"use of invalid field name '")
3893 << fieldName <<
"' on bundle value";
3898 result = cast<Value>(symtabEntry);
3902 assert(isa<BlockArgument>(result) ||
3903 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3909 type = result.getType();
3911 if (consumeIf(FIRToken::period)) {
3912 SmallVector<StringRef, 3> fields;
3913 if (parseFieldIdSeq(fields,
"expected field name"))
3915 for (
auto fieldName : fields) {
3916 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3917 if (
auto index = bundle.getElementIndex(fieldName)) {
3918 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3919 type = bundle.getElementTypePreservingConst(*index);
3922 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3923 if (
auto index = bundle.getElementIndex(fieldName)) {
3924 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3925 type = bundle.getElementTypePreservingConst(*index);
3929 return emitError(loc,
"subfield requires bundle operand")
3930 <<
"got " << type <<
"\n";
3932 return emitError(loc,
3933 "unknown field '" + fieldName +
"' in bundle type ")
3938 if (consumeIf(FIRToken::l_square)) {
3939 auto loc = getToken().
getLoc();
3941 if (parseIntLit(index,
"expected index") ||
3942 parseToken(FIRToken::r_square,
"expected ']'"))
3946 return emitError(loc,
"invalid index specifier");
3948 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3949 if ((
unsigned)index < vector.getNumElements()) {
3950 refResult = refResult.
getSubField(vector.getFieldID(index));
3951 type = vector.getElementTypePreservingConst();
3954 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3955 if ((
unsigned)index < vector.getNumElements()) {
3956 refResult = refResult.
getSubField(vector.getFieldID(index));
3957 type = vector.getElementTypePreservingConst();
3961 return emitError(loc,
"subindex requires vector operand");
3963 return emitError(loc,
"out of range index '")
3964 << index <<
"' for vector type " << type;
3972ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3973 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3974 StringRef intrinsic;
3975 ArrayAttr parameters;
3978 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3979 parseOptionalParams(parameters))
3982 if (consumeIf(FIRToken::colon)) {
3983 if (
parseType(type,
"expected intrinsic return type"))
3985 }
else if (!isStatement)
3986 return emitError(
"expected ':' in intrinsic expression");
3988 SmallVector<Value> operands;
3989 auto loc = startTok.getLoc();
3990 if (consumeIf(FIRToken::comma)) {
3991 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3993 if (parseExp(operand,
"expected operand in intrinsic"))
3995 operands.push_back(operand);
3996 locationProcessor.setLoc(loc);
4001 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4006 if (parseOptionalInfo())
4009 locationProcessor.setLoc(loc);
4011 auto op = GenericIntrinsicOp::create(
4012 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4014 result = op.getResult();
4019ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4020 if (!consumeIf(FIRToken::less))
4023 SmallVector<Attribute, 8> parameters;
4024 SmallPtrSet<StringAttr, 8> seen;
4025 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4029 if (parseParameter(name, value, loc))
4031 auto typedValue = dyn_cast<TypedAttr>(value);
4033 return emitError(loc)
4034 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4035 if (!seen.insert(name).second)
4036 return emitError(loc,
"redefinition of parameter '" +
4037 name.getValue() +
"'");
4038 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4043 resultParameters = ArrayAttr::get(getContext(), parameters);
4049ParseResult FIRStmtParser::parsePathExp(Value &result) {
4050 auto startTok = consumeToken(FIRToken::lp_path);
4051 locationProcessor.setLoc(startTok.getLoc());
4053 if (parseGetSpelling(target) ||
4054 parseToken(FIRToken::string,
4055 "expected target string in path expression") ||
4056 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4058 result = UnresolvedPathOp::create(
4064ParseResult FIRStmtParser::parseDomainDefine() {
4065 auto startTok = consumeToken(FIRToken::kw_domain_define);
4066 auto startLoc = startTok.getLoc();
4067 locationProcessor.setLoc(startLoc);
4071 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4072 parseDomainExp(src) || parseOptionalInfo())
4080ParseResult FIRStmtParser::parseRefDefine() {
4081 auto startTok = consumeToken(FIRToken::kw_define);
4084 if (parseStaticRefExp(target,
4085 "expected static reference expression in 'define'") ||
4086 parseToken(FIRToken::equal,
4087 "expected '=' after define reference expression") ||
4088 parseRefExp(src,
"expected reference expression in 'define'") ||
4089 parseOptionalInfo())
4093 if (!type_isa<RefType>(target.getType()))
4094 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4095 "'define' target (LHS), got ")
4096 << target.getType();
4097 if (!type_isa<RefType>(src.getType()))
4098 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4099 "'define' source (RHS), got ")
4104 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4105 return emitError(startTok.getLoc(),
4106 "cannot define into a sub-element of a reference");
4108 locationProcessor.setLoc(startTok.getLoc());
4111 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4112 << target.getType() <<
" with incompatible reference of type "
4122ParseResult FIRStmtParser::parseRefRead(Value &result) {
4123 auto startTok = consumeToken(FIRToken::lp_read);
4126 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4127 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4130 locationProcessor.setLoc(startTok.getLoc());
4133 if (!type_isa<RefType>(ref.getType()))
4134 return emitError(startTok.getLoc(),
4135 "expected reference-type expression in 'read', got ")
4138 result = RefResolveOp::create(builder, ref);
4144ParseResult FIRStmtParser::parseProbe(Value &result) {
4145 auto startTok = consumeToken(FIRToken::lp_probe);
4148 if (parseStaticRefExp(staticRef,
4149 "expected static reference expression in 'probe'") ||
4150 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4153 locationProcessor.setLoc(startTok.getLoc());
4156 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4157 return emitError(startTok.getLoc(),
4158 "expected base-type expression in 'probe', got ")
4159 << staticRef.getType();
4163 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4164 MemoryDebugPortOp, MemoryPortAccessOp>(
4165 staticRef.getDefiningOp()))
4166 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4168 result = RefSendOp::create(builder, staticRef);
4174ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4175 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4178 Type parsedTargetType;
4179 if (parseRWProbeStaticRefExp(
4180 staticRef, parsedTargetType,
4181 "expected static reference expression in 'rwprobe'") ||
4182 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4185 locationProcessor.setLoc(startTok.getLoc());
4191 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4193 return emitError(startTok.getLoc(),
4194 "expected base-type expression in 'rwprobe', got ")
4195 << parsedTargetType;
4198 auto *definingOp = root.getDefiningOp();
4200 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4201 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4202 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4206 return emitError(startTok.getLoc(),
"cannot force target of type ")
4210 auto op = RWProbeOp::create(builder, forceableType,
4211 getConstants().placeholderInnerRef);
4218ParseResult FIRStmtParser::parseRefForce() {
4219 auto startTok = consumeToken(FIRToken::lp_force);
4221 Value clock, pred, dest, src;
4222 if (parseExp(clock,
"expected clock expression in force") ||
4223 parseToken(FIRToken::comma,
"expected ','") ||
4224 parseExp(pred,
"expected predicate expression in force") ||
4225 parseToken(FIRToken::comma,
"expected ','") ||
4226 parseRefExp(dest,
"expected destination reference expression in force") ||
4227 parseToken(FIRToken::comma,
"expected ','") ||
4228 parseExp(src,
"expected source expression in force") ||
4229 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4230 parseOptionalInfo())
4234 auto ref = type_dyn_cast<RefType>(dest.getType());
4235 if (!ref || !ref.getForceable())
4238 "expected rwprobe-type expression for force destination, got ")
4240 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4242 return emitError(startTok.getLoc(),
4243 "expected base-type for force source, got ")
4245 if (!srcBaseType.isPassive())
4246 return emitError(startTok.getLoc(),
4247 "expected passive value for force source, got ")
4250 locationProcessor.setLoc(startTok.getLoc());
4253 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4254 if (noConstSrcType != ref.getType()) {
4256 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4258 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4260 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4261 << src.getType() <<
" cannot target destination "
4265 RefForceOp::create(builder, clock, pred, dest, src);
4271ParseResult FIRStmtParser::parseRefForceInitial() {
4272 auto startTok = consumeToken(FIRToken::lp_force_initial);
4276 dest,
"expected destination reference expression in force_initial") ||
4277 parseToken(FIRToken::comma,
"expected ','") ||
4278 parseExp(src,
"expected source expression in force_initial") ||
4279 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4280 parseOptionalInfo())
4284 auto ref = type_dyn_cast<RefType>(dest.getType());
4285 if (!ref || !ref.getForceable())
4286 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4287 "force_initial destination, got ")
4289 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4291 return emitError(startTok.getLoc(),
4292 "expected base-type expression for force_initial "
4295 if (!srcBaseType.isPassive())
4296 return emitError(startTok.getLoc(),
4297 "expected passive value for force_initial source, got ")
4300 locationProcessor.setLoc(startTok.getLoc());
4303 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4304 if (noConstSrcType != ref.getType()) {
4306 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4308 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4310 return emitError(startTok.getLoc(),
4311 "incompatible force_initial source of type ")
4312 << src.getType() <<
" cannot target destination "
4316 auto value = APInt::getAllOnes(1);
4317 auto type = UIntType::get(builder.getContext(), 1);
4318 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4319 value.getBitWidth(),
4320 IntegerType::Unsigned),
4322 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4323 RefForceInitialOp::create(builder, pred, dest, src);
4329ParseResult FIRStmtParser::parseRefRelease() {
4330 auto startTok = consumeToken(FIRToken::lp_release);
4332 Value clock, pred, dest;
4333 if (parseExp(clock,
"expected clock expression in release") ||
4334 parseToken(FIRToken::comma,
"expected ','") ||
4335 parseExp(pred,
"expected predicate expression in release") ||
4336 parseToken(FIRToken::comma,
"expected ','") ||
4338 "expected destination reference expression in release") ||
4339 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4340 parseOptionalInfo())
4344 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4345 !ref || !ref.getForceable())
4348 "expected rwprobe-type expression for release destination, got ")
4351 locationProcessor.setLoc(startTok.getLoc());
4353 RefReleaseOp::create(builder, clock, pred, dest);
4359ParseResult FIRStmtParser::parseRefReleaseInitial() {
4360 auto startTok = consumeToken(FIRToken::lp_release_initial);
4365 "expected destination reference expression in release_initial") ||
4366 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4367 parseOptionalInfo())
4371 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4372 !ref || !ref.getForceable())
4373 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4374 "release_initial destination, got ")
4377 locationProcessor.setLoc(startTok.getLoc());
4379 auto value = APInt::getAllOnes(1);
4380 auto type = UIntType::get(builder.getContext(), 1);
4381 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4382 value.getBitWidth(),
4383 IntegerType::Unsigned),
4385 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4386 RefReleaseInitialOp::create(builder, pred, dest);
4392ParseResult FIRStmtParser::parseConnect() {
4393 auto startTok = consumeToken(FIRToken::kw_connect);
4394 auto loc = startTok.getLoc();
4397 if (parseExp(lhs,
"expected connect expression") ||
4398 parseToken(FIRToken::comma,
"expected ','") ||
4399 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4402 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4403 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4404 if (!lhsType || !rhsType)
4405 return emitError(loc,
"cannot connect reference or property types");
4407 if (lhsType.containsReference() || rhsType.containsReference())
4408 return emitError(loc,
"cannot connect types containing references");
4411 return emitError(loc,
"cannot connect non-equivalent type ")
4412 << rhsType <<
" to " << lhsType;
4414 locationProcessor.setLoc(loc);
4420ParseResult FIRStmtParser::parsePropAssign() {
4421 auto startTok = consumeToken(FIRToken::kw_propassign);
4422 auto loc = startTok.getLoc();
4425 if (parseExp(lhs,
"expected propassign expression") ||
4426 parseToken(FIRToken::comma,
"expected ','") ||
4427 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4430 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4431 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4432 if (!lhsType || !rhsType)
4433 return emitError(loc,
"can only propassign property types");
4434 locationProcessor.setLoc(loc);
4435 if (lhsType != rhsType) {
4437 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4438 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4440 return emitError(loc,
"cannot propassign non-equivalent type ")
4441 << rhsType <<
" to " << lhsType;
4443 PropAssignOp::create(builder, lhs, rhs);
4448ParseResult FIRStmtParser::parseInvalidate() {
4449 auto startTok = consumeToken(FIRToken::kw_invalidate);
4454 auto loc = getToken().getLoc();
4456 if (parseId(
id,
"expected static reference expression") ||
4457 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4462 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4463 if (parseOptionalExpPostscript(lhs,
false) ||
4464 parseOptionalInfo())
4467 locationProcessor.setLoc(startTok.getLoc());
4468 emitInvalidate(lhs);
4475 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4477 if (getToken().isNot(FIRToken::period)) {
4478 locationProcessor.setLoc(loc);
4480 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4482 for (
auto elt : ubEntry)
4483 emitInvalidate(elt.second);
4489 StringRef fieldName;
4490 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4491 parseFieldId(fieldName,
"expected field name") ||
4492 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4496 if (parseOptionalExpPostscript(lhs,
false) ||
4497 parseOptionalInfo())
4500 locationProcessor.setLoc(startTok.getLoc());
4501 emitInvalidate(lhs);
4505ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4507 auto startTok = consumeToken();
4508 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4509 "consumed an unexpected token");
4510 auto loc = startTok.getLoc();
4513 if (parseId(
id,
"expected layer identifer") ||
4514 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4515 parseOptionalInfo())
4518 locationProcessor.setLoc(loc);
4520 StringRef rootLayer;
4521 SmallVector<FlatSymbolRefAttr> nestedLayers;
4525 rootLayer = layerSym.getRootReference();
4526 auto nestedRefs = layerSym.getNestedReferences();
4527 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4528 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4531 auto layerBlockOp = LayerBlockOp::create(
4533 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4534 layerBlockOp->getRegion(0).push_back(
new Block());
4536 if (getIndentation() > indent)
4537 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4538 layerBlockOp.getLayerName()))
4546ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4547 auto loc = getToken().getLoc();
4550 if (consumeIf(FIRToken::kw_is)) {
4551 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4552 parseOptionalInfo())
4555 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4558 locationProcessor.setLoc(loc);
4559 emitInvalidate(lhs);
4563 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4566 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4570 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4573 locationProcessor.setLoc(loc);
4575 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4576 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4577 if (!lhsType || !rhsType)
4578 return emitError(loc,
"cannot connect reference or property types");
4580 if (lhsType.containsReference() || rhsType.containsReference())
4581 return emitError(loc,
"cannot connect types containing references");
4584 return emitError(loc,
"cannot connect non-equivalent type ")
4585 << rhsType <<
" to " << lhsType;
4594ParseResult FIRStmtParser::parseInstance() {
4595 auto startTok = consumeToken(FIRToken::kw_inst);
4599 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4603 StringRef moduleName;
4604 if (parseId(
id,
"expected instance name") ||
4605 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4606 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4609 locationProcessor.setLoc(startTok.getLoc());
4612 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4613 if (!referencedModule)
4616 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4618 auto annotations = getConstants().emptyArrayAttr;
4619 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4621 hw::InnerSymAttr sym = {};
4622 auto result = InstanceOp::create(
4623 builder, referencedModule,
id, NameKindEnum::InterestingName,
4624 annotations.getValue(), portAnnotations,
false,
false, sym);
4630 unbundledValueEntry.reserve(modulePorts.size());
4631 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4632 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4636 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4637 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4638 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4643ParseResult FIRStmtParser::parseInstanceChoice() {
4644 auto startTok = consumeToken(FIRToken::kw_instchoice);
4645 SMLoc loc = startTok.getLoc();
4648 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4655 StringRef defaultModuleName;
4656 StringRef optionGroupName;
4657 if (parseId(
id,
"expected instance name") ||
4658 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4659 parseId(defaultModuleName,
"expected module name") ||
4660 parseToken(FIRToken::comma,
"expected ','") ||
4661 parseId(optionGroupName,
"expected option group name") ||
4662 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4663 parseOptionalInfo())
4666 locationProcessor.setLoc(startTok.getLoc());
4670 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4674 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4677 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4679 return emitError(loc,
4680 "use of undefined option group '" + optionGroupName +
"'");
4682 auto baseIndent = getIndentation();
4683 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4684 while (getIndentation() == baseIndent) {
4686 StringRef caseModuleName;
4687 if (parseId(caseId,
"expected a case identifier") ||
4688 parseToken(FIRToken::equal_greater,
4689 "expected '=> in instance choice definition") ||
4690 parseId(caseModuleName,
"expected module name"))
4693 auto caseModule = getReferencedModule(loc, caseModuleName);
4697 for (
const auto &[defaultPort, casePort] :
4698 llvm::zip(modulePorts, caseModule.getPorts())) {
4699 if (defaultPort.name != casePort.name)
4700 return emitError(loc,
"instance case module port '")
4701 << casePort.name.getValue()
4702 <<
"' does not match the default module port '"
4703 << defaultPort.name.getValue() <<
"'";
4704 if (defaultPort.type != casePort.type)
4705 return emitError(loc,
"instance case port '")
4706 << casePort.name.getValue()
4707 <<
"' type does not match the default module port";
4711 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4713 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4714 caseModules.emplace_back(optionCase, caseModule);
4717 auto annotations = getConstants().emptyArrayAttr;
4718 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4722 auto result = InstanceChoiceOp::create(
4723 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4724 annotations.getValue(), portAnnotations, sym);
4728 unbundledValueEntry.reserve(modulePorts.size());
4729 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4730 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4732 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4733 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4734 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4737FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4738 StringRef moduleName) {
4739 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4740 if (!referencedModule) {
4742 "use of undefined module name '" + moduleName +
"' in instance");
4745 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4746 emitError(loc,
"cannot create instance of class '" + moduleName +
4747 "', did you mean object?");
4750 return referencedModule;
4754ParseResult FIRStmtParser::parseObject() {
4755 auto startTok = consumeToken(FIRToken::kw_object);
4759 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4766 StringRef className;
4767 if (parseId(
id,
"expected object name") ||
4768 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4769 parseId(className,
"expected class name") || parseOptionalInfo())
4772 locationProcessor.setLoc(startTok.getLoc());
4775 const auto &classMap = getConstants().classMap;
4776 auto lookup = classMap.find(className);
4777 if (lookup == classMap.end())
4778 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4779 className +
"' in object");
4780 auto referencedClass = lookup->getSecond();
4781 auto result = ObjectOp::create(builder, referencedClass,
id);
4782 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4786ParseResult FIRStmtParser::parseCombMem() {
4788 auto startTok = consumeToken(FIRToken::kw_cmem);
4792 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4797 if (parseId(
id,
"expected cmem name") ||
4798 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4799 parseType(type,
"expected cmem type") || parseOptionalInfo())
4802 locationProcessor.setLoc(startTok.getLoc());
4805 auto vectorType = type_dyn_cast<FVectorType>(type);
4807 return emitError(
"cmem requires vector type");
4809 auto annotations = getConstants().emptyArrayAttr;
4810 StringAttr sym = {};
4811 auto result = CombMemOp::create(
4812 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4813 NameKindEnum::InterestingName, annotations, sym);
4814 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4818ParseResult FIRStmtParser::parseSeqMem() {
4820 auto startTok = consumeToken(FIRToken::kw_smem);
4824 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4829 RUWBehavior ruw = RUWBehavior::Undefined;
4831 if (parseId(
id,
"expected smem name") ||
4832 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4836 if (consumeIf(FIRToken::comma)) {
4841 if (parseOptionalInfo()) {
4845 locationProcessor.setLoc(startTok.getLoc());
4848 auto vectorType = type_dyn_cast<FVectorType>(type);
4850 return emitError(
"smem requires vector type");
4852 auto annotations = getConstants().emptyArrayAttr;
4853 StringAttr sym = {};
4854 auto result = SeqMemOp::create(
4855 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4856 id, NameKindEnum::InterestingName, annotations, sym);
4857 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4869ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4870 auto startTok = consumeToken(FIRToken::kw_mem);
4874 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4878 if (parseId(
id,
"expected mem name") ||
4879 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4883 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4884 RUWBehavior ruw = RUWBehavior::Undefined;
4886 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4890 auto nextIndent = getIndentation();
4891 if (!nextIndent || *nextIndent <= memIndent)
4894 auto spelling = getTokenSpelling();
4895 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4896 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4899 if (spelling ==
"data-type") {
4901 return emitError(
"'mem' type specified multiple times"), failure();
4903 if (
parseType(type,
"expected type in data-type declaration"))
4907 if (spelling ==
"depth") {
4908 if (parseIntLit(depth,
"expected integer in depth specification"))
4912 if (spelling ==
"read-latency") {
4913 if (parseIntLit(readLatency,
"expected integer latency"))
4917 if (spelling ==
"write-latency") {
4918 if (parseIntLit(writeLatency,
"expected integer latency"))
4922 if (spelling ==
"read-under-write") {
4923 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4924 FIRToken::kw_undefined))
4925 return emitError(
"expected specifier"), failure();
4927 if (parseOptionalRUW(ruw))
4932 MemOp::PortKind portKind;
4933 if (spelling ==
"reader")
4934 portKind = MemOp::PortKind::Read;
4935 else if (spelling ==
"writer")
4936 portKind = MemOp::PortKind::Write;
4937 else if (spelling ==
"readwriter")
4938 portKind = MemOp::PortKind::ReadWrite;
4940 return emitError(
"unexpected field in 'mem' declaration"), failure();
4943 if (parseId(portName,
"expected port name"))
4945 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4947 return emitError(
"unexpected type, must be base type");
4948 ports.push_back({builder.getStringAttr(portName),
4949 MemOp::getTypeForPort(depth, baseType, portKind)});
4951 while (!getIndentation().has_value()) {
4952 if (parseId(portName,
"expected port name"))
4954 ports.push_back({builder.getStringAttr(portName),
4955 MemOp::getTypeForPort(depth, baseType, portKind)});
4966 llvm::array_pod_sort(ports.begin(), ports.end(),
4967 [](
const std::pair<StringAttr, Type> *lhs,
4968 const std::pair<StringAttr, Type> *rhs) ->
int {
4969 return lhs->first.getValue().compare(
4970 rhs->first.getValue());
4973 auto annotations = getConstants().emptyArrayAttr;
4974 SmallVector<Attribute, 4> resultNames;
4975 SmallVector<Type, 4> resultTypes;
4976 SmallVector<Attribute, 4> resultAnnotations;
4977 for (
auto p : ports) {
4978 resultNames.push_back(p.first);
4979 resultTypes.push_back(p.second);
4980 resultAnnotations.push_back(annotations);
4983 locationProcessor.setLoc(startTok.getLoc());
4985 auto result = MemOp::create(
4986 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4987 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
4988 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4989 MemoryInitAttr(), StringAttr());
4992 unbundledValueEntry.reserve(result.getNumResults());
4993 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4994 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4996 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4997 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4998 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5002ParseResult FIRStmtParser::parseNode() {
5003 auto startTok = consumeToken(FIRToken::kw_node);
5007 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5012 if (parseId(
id,
"expected node name") ||
5013 parseToken(FIRToken::equal,
"expected '=' in node") ||
5014 parseExp(initializer,
"expected expression for node") ||
5015 parseOptionalInfo())
5018 locationProcessor.setLoc(startTok.getLoc());
5030 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5031 auto initializerBaseType =
5032 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5033 if (type_isa<AnalogType>(initializerType) ||
5034 !(initializerBaseType && initializerBaseType.isPassive())) {
5035 emitError(startTok.getLoc())
5036 <<
"Node cannot be analog and must be passive or passive under a flip "
5037 << initializer.getType();
5041 auto annotations = getConstants().emptyArrayAttr;
5042 StringAttr sym = {};
5044 auto result = NodeOp::create(builder, initializer,
id,
5045 NameKindEnum::InterestingName, annotations, sym);
5046 return moduleContext.addSymbolEntry(
id, result.getResult(),
5051ParseResult FIRStmtParser::parseWire() {
5052 auto startTok = consumeToken(FIRToken::kw_wire);
5056 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5061 if (parseId(
id,
"expected wire name") ||
5062 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5063 parseType(type,
"expected wire type") || parseOptionalInfo())
5066 locationProcessor.setLoc(startTok.getLoc());
5068 auto annotations = getConstants().emptyArrayAttr;
5069 StringAttr sym = {};
5072 auto namekind = isa<PropertyType, RefType>(type)
5073 ? NameKindEnum::DroppableName
5074 : NameKindEnum::InterestingName;
5076 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
5077 return moduleContext.addSymbolEntry(
id, result.getResult(),
5091ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5092 auto startTok = consumeToken(FIRToken::kw_reg);
5096 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5105 if (parseId(
id,
"expected reg name") ||
5106 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5108 parseToken(FIRToken::comma,
"expected ','") ||
5109 parseExp(clock,
"expected expression for register clock"))
5112 if (!type_isa<FIRRTLBaseType>(type))
5113 return emitError(startTok.getLoc(),
"register must have base type");
5116 Value resetSignal, resetValue;
5117 if (consumeIf(FIRToken::kw_with)) {
5118 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5121 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5129 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5131 auto indent = getIndentation();
5132 if (!indent || *indent <= regIndent)
5133 if (!hasExtraLParen)
5134 return emitError(
"expected indented reset specifier in reg"), failure();
5136 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5137 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5138 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5139 parseExp(resetSignal,
"expected expression for reset signal") ||
5140 parseToken(FIRToken::comma,
"expected ','"))
5148 if (getTokenSpelling() ==
id) {
5150 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5152 resetSignal = Value();
5154 if (parseExp(resetValue,
"expected expression for reset value") ||
5155 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5159 if (hasExtraLParen &&
5160 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5166 if (parseOptionalInfo())
5169 locationProcessor.setLoc(startTok.getLoc());
5171 ArrayAttr annotations = getConstants().emptyArrayAttr;
5173 StringAttr sym = {};
5176 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5177 NameKindEnum::InterestingName, annotations, sym)
5180 result = RegOp::create(builder, type, clock,
id,
5181 NameKindEnum::InterestingName, annotations, sym)
5183 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5191ParseResult FIRStmtParser::parseRegisterWithReset() {
5192 auto startTok = consumeToken(FIRToken::kw_regreset);
5196 Value clock, resetSignal, resetValue;
5198 if (parseId(
id,
"expected reg name") ||
5199 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5201 parseToken(FIRToken::comma,
"expected ','") ||
5202 parseExp(clock,
"expected expression for register clock") ||
5203 parseToken(FIRToken::comma,
"expected ','") ||
5204 parseExp(resetSignal,
"expected expression for register reset") ||
5205 parseToken(FIRToken::comma,
"expected ','") ||
5206 parseExp(resetValue,
"expected expression for register reset value") ||
5207 parseOptionalInfo())
5210 if (!type_isa<FIRRTLBaseType>(type))
5211 return emitError(startTok.getLoc(),
"register must have base type");
5213 locationProcessor.setLoc(startTok.getLoc());
5216 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5217 NameKindEnum::InterestingName,
5218 getConstants().emptyArrayAttr, StringAttr{})
5221 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5226ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5230 auto startTok = consumeToken(FIRToken::kw_contract);
5233 SmallVector<StringRef> ids;
5234 SmallVector<SMLoc> locs;
5235 SmallVector<Value> values;
5236 SmallVector<Type> types;
5237 if (!consumeIf(FIRToken::colon)) {
5238 auto parseContractId = [&] {
5240 locs.push_back(getToken().
getLoc());
5241 if (parseId(
id,
"expected contract result name"))
5246 auto parseContractValue = [&] {
5248 if (parseExp(value,
"expected expression for contract result"))
5250 values.push_back(value);
5251 types.push_back(value.getType());
5254 if (parseListUntil(FIRToken::equal, parseContractId) ||
5255 parseListUntil(FIRToken::colon, parseContractValue))
5258 if (parseOptionalInfo())
5262 if (ids.size() != values.size())
5263 return emitError(startTok.getLoc())
5264 <<
"contract requires same number of results and expressions; got "
5265 << ids.size() <<
" results and " << values.size()
5266 <<
" expressions instead";
5268 locationProcessor.setLoc(startTok.getLoc());
5272 auto contract = ContractOp::create(builder, types, values);
5273 auto &block = contract.getBody().emplaceBlock();
5277 FIRModuleContext::ContextScope scope(moduleContext, &block);
5278 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5279 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5280 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5283 if (getIndentation() > blockIndent)
5284 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5289 for (
auto [
id, loc, value, result] :
5290 llvm::zip(ids, locs, values, contract.getResults())) {
5292 moduleContext.removeSymbolEntry(
id);
5293 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5306struct FIRCircuitParser :
public FIRParser {
5307 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5309 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5312 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5313 mlir::TimingScope &ts);
5318 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5319 SmallVectorImpl<Attribute> &attrs);
5321 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5323 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5324 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5325 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5326 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5327 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5328 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5329 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5330 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5332 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5334 ParseResult parseLayerName(SymbolRefAttr &result);
5335 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5336 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5337 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5338 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5339 ParseResult parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5340 ArrayAttr &knownLayers);
5342 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5343 SmallVectorImpl<SMLoc> &resultPortLocs,
5347 ParseResult skipToModuleEnd(
unsigned indent);
5349 ParseResult parseTypeDecl();
5351 ParseResult parseOptionDecl(CircuitOp circuit);
5353 ParseResult parseLayer(CircuitOp circuit);
5355 ParseResult parseDomains(SmallVectorImpl<Attribute> &domains,
5356 const DenseMap<Attribute, size_t> &nameToIndex);
5358 struct DeferredModuleToParse {
5359 FModuleLike moduleOp;
5360 SmallVector<SMLoc> portLocs;
5365 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5366 DeferredModuleToParse &deferredModule,
5367 InnerSymFixups &fixups);
5369 SmallVector<DeferredModuleToParse, 0> deferredModules;
5371 SmallVector<InnerSymFixups, 0> moduleFixups;
5375 ModuleOp mlirModule;
5380FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5381 SmallVectorImpl<Attribute> &attrs) {
5383 auto annotations = json::parse(annotationsStr);
5384 if (
auto err = annotations.takeError()) {
5385 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5386 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5387 diag.attachNote() << a.message();
5392 json::Path::Root root;
5393 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5396 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5397 std::string jsonErrorMessage =
5398 "See inline comments for problem area in JSON:\n";
5399 llvm::raw_string_ostream s(jsonErrorMessage);
5400 root.printErrorContext(annotations.get(), s);
5401 diag.attachNote() << jsonErrorMessage;
5408ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5409 auto *context = getContext();
5410 SmallVector<StringRef> strings;
5413 if (parseId(name,
"expected layer name"))
5415 strings.push_back(name);
5416 }
while (consumeIf(FIRToken::period));
5418 SmallVector<FlatSymbolRefAttr> nested;
5419 nested.reserve(strings.size() - 1);
5420 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5421 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5423 result = SymbolRefAttr::get(context, strings[0], nested);
5427ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5428 SmallVector<Attribute> enabledLayersBuffer;
5430 auto tokenKind = getToken().getKind();
5432 if (tokenKind == FIRToken::kw_enablelayer) {
5433 if (parseEnableLayerSpec(enabledLayersBuffer))
5441 if (enabledLayersBuffer.size() != 0)
5442 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5445 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5449ParseResult FIRCircuitParser::parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5450 ArrayAttr &knownLayers) {
5451 SmallVector<Attribute> enabledLayersBuffer;
5452 SmallVector<Attribute> knownLayersBuffer;
5454 auto tokenKind = getToken().getKind();
5456 if (tokenKind == FIRToken::kw_enablelayer) {
5457 if (parseEnableLayerSpec(enabledLayersBuffer))
5462 if (tokenKind == FIRToken::kw_knownlayer) {
5463 if (parseKnownLayerSpec(knownLayersBuffer))
5471 if (enabledLayersBuffer.size() != 0)
5472 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5475 if (knownLayersBuffer.size() != 0)
5476 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5479 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5480 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5485FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5487 SymbolRefAttr layer;
5488 if (parseLayerName(layer))
5490 result.push_back(layer);
5491 }
while (consumeIf(FIRToken::comma));
5496FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5497 consumeToken(FIRToken::kw_enablelayer);
5498 return parseLayerList(result);
5502FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5503 consumeToken(FIRToken::kw_knownlayer);
5504 return parseLayerList(result);
5511FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5512 SmallVectorImpl<SMLoc> &resultPortLocs,
5515 DenseMap<Attribute, size_t> nameToIndex;
5518 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5520 getIndentation() > indent) {
5526 auto backtrackState = getLexer().getCursor();
5528 bool isOutput = getToken().is(FIRToken::kw_output);
5533 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5534 !getToken().isKeyword()) {
5535 backtrackState.restore(getLexer());
5542 if (parseId(name,
"expected port name") ||
5543 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5544 parseType(type,
"expected a type in port declaration"))
5546 Attribute domainInfoElement;
5547 if (isa<DomainType>(type)) {
5548 StringAttr domainKind;
5549 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type port") ||
5550 parseId(domainKind,
"expected domain kind"))
5552 domainInfoElement = FlatSymbolRefAttr::get(domainKind);
5554 SmallVector<Attribute, 4> domains;
5555 if (getToken().is(FIRToken::kw_domains))
5556 if (parseDomains(domains, nameToIndex))
5558 domainInfoElement = ArrayAttr::get(getContext(), domains);
5561 if (
info.parseOptionalInfo())
5564 StringAttr innerSym = {};
5565 resultPorts.push_back(
PortInfo{name,
5571 domainInfoElement});
5572 resultPortLocs.push_back(
info.getFIRLoc());
5573 nameToIndex.insert({name, resultPorts.size() - 1});
5578 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5579 PortInfo &port = std::get<0>(portAndLoc);
5580 auto &entry = portIds[port.
name];
5581 if (!entry.isValid()) {
5582 entry = std::get<1>(portAndLoc);
5586 emitError(std::get<1>(portAndLoc),
5587 "redefinition of name '" + port.
getName() +
"'")
5588 .attachNote(translateLocation(entry))
5589 <<
"previous definition here";
5598ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5600 switch (getToken().getKind()) {
5604 case FIRToken::error:
5608 case FIRToken::kw_class:
5609 case FIRToken::kw_domain:
5610 case FIRToken::kw_declgroup:
5611 case FIRToken::kw_extclass:
5612 case FIRToken::kw_extmodule:
5613 case FIRToken::kw_intmodule:
5614 case FIRToken::kw_formal:
5615 case FIRToken::kw_module:
5616 case FIRToken::kw_public:
5617 case FIRToken::kw_layer:
5618 case FIRToken::kw_option:
5619 case FIRToken::kw_simulation:
5620 case FIRToken::kw_type:
5624 if (getIndentation() == indent)
5636ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5637 SmallVector<Attribute, 8> parameters;
5638 SmallPtrSet<StringAttr, 8> seen;
5639 while (consumeIf(FIRToken::kw_parameter)) {
5643 if (parseParameter(name, value, loc))
5645 auto typedValue = dyn_cast<TypedAttr>(value);
5647 return emitError(loc)
5648 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5649 if (!seen.insert(name).second)
5650 return emitError(loc,
5651 "redefinition of parameter '" + name.getValue() +
"'");
5652 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5654 resultParameters = ArrayAttr::get(getContext(), parameters);
5659ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5661 SmallVector<PortInfo, 8> portList;
5662 SmallVector<SMLoc> portLocs;
5668 consumeToken(FIRToken::kw_class);
5669 if (parseId(name,
"expected class name") ||
5670 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5674 if (name == circuit.getName())
5675 return mlir::emitError(
info.getLoc(),
5676 "class cannot be the top of a circuit");
5678 for (
auto &portInfo : portList)
5680 return
mlir::emitError(portInfo.loc,
5681 "ports on classes must be properties");
5684 auto builder = circuit.getBodyBuilder();
5685 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5686 classOp.setPrivate();
5687 deferredModules.emplace_back(
5688 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5691 getConstants().classMap[name.getValue()] = classOp;
5692 return skipToModuleEnd(indent);
5696ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5697 consumeToken(FIRToken::kw_domain);
5701 if (parseId(name,
"domain name") ||
5702 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5703 info.parseOptionalInfo())
5706 SmallVector<Attribute> fields;
5708 auto nextIndent = getIndentation();
5709 if (!nextIndent || *nextIndent <= indent)
5712 StringAttr fieldName;
5714 if (parseId(fieldName,
"field name") ||
5715 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5716 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5720 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5723 auto builder = circuit.getBodyBuilder();
5724 DomainOp::create(builder,
info.getLoc(), name, builder.getArrayAttr(fields));
5730ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5733 SmallVector<PortInfo, 8> portList;
5734 SmallVector<SMLoc> portLocs;
5740 consumeToken(FIRToken::kw_extclass);
5741 if (parseId(name,
"expected extclass name") ||
5742 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5746 if (name == circuit.getName())
5747 return mlir::emitError(
info.getLoc(),
5748 "extclass cannot be the top of a circuit");
5750 for (
auto &portInfo : portList)
5752 return
mlir::emitError(portInfo.loc,
5753 "ports on extclasses must be properties");
5756 auto builder = circuit.getBodyBuilder();
5757 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5760 getConstants().classMap[name.getValue()] = extClassOp;
5761 return skipToModuleEnd(indent);
5768ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5771 ArrayAttr enabledLayers;
5772 ArrayAttr knownLayers;
5773 SmallVector<PortInfo, 8> portList;
5774 SmallVector<SMLoc> portLocs;
5776 consumeToken(FIRToken::kw_extmodule);
5777 if (parseId(name,
"expected extmodule name") ||
5778 parseExtModuleLayerSpec(enabledLayers, knownLayers) ||
5779 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5784 if (consumeIf(FIRToken::kw_defname)) {
5785 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5786 parseId(defName,
"expected defname name"))
5790 ArrayAttr parameters;
5795 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5796 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5797 if (ftype.hasUninferredWidth())
5798 return emitError(loc,
"extmodule port must have known width");
5803 auto builder = circuit.getBodyBuilder();
5804 auto isMainModule = (name == circuit.getName());
5806 (isMainModule && getConstants().options.scalarizePublicModules) ||
5807 getConstants().options.scalarizeExtModules
5808 ? Convention::Scalarized
5809 : Convention::Internal;
5810 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5811 auto annotations = ArrayAttr::get(getContext(), {});
5812 auto extModuleOp = FExtModuleOp::create(
5813 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5814 defName, annotations, parameters, enabledLayers);
5815 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5816 : SymbolTable::Visibility::Private;
5817 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5825ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5829 ArrayAttr enabledLayers;
5830 SmallVector<PortInfo, 8> portList;
5831 SmallVector<SMLoc> portLocs;
5833 consumeToken(FIRToken::kw_intmodule);
5834 if (parseId(name,
"expected intmodule name") ||
5835 parseModuleLayerSpec(enabledLayers) ||
5836 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5838 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5839 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5840 parseId(intName,
"expected intrinsic name"))
5843 ArrayAttr parameters;
5847 ArrayAttr annotations = getConstants().emptyArrayAttr;
5848 auto builder = circuit.getBodyBuilder();
5849 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5850 annotations, parameters, enabledLayers)
5856ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5859 SmallVector<PortInfo, 8> portList;
5860 SmallVector<SMLoc> portLocs;
5861 ArrayAttr enabledLayers;
5862 auto modLoc = getToken().getLoc();
5863 LocWithInfo
info(modLoc,
this);
5864 consumeToken(FIRToken::kw_module);
5865 if (parseId(name,
"expected module name") ||
5866 parseModuleLayerSpec(enabledLayers) ||
5867 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5872 if (name == circuit.getName()) {
5873 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5878 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5879 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5880 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5881 if (ftype.hasUninferredWidth())
5882 return emitError(loc,
"public module port must have known width");
5883 if (ftype.hasUninferredReset())
5884 return emitError(loc,
5885 "public module port must have concrete reset type");
5890 ArrayAttr annotations = getConstants().emptyArrayAttr;
5891 auto convention = Convention::Internal;
5892 if (isPublic && getConstants().options.scalarizePublicModules)
5893 convention = Convention::Scalarized;
5894 if (!isPublic && getConstants().options.scalarizeInternalModules)
5895 convention = Convention::Scalarized;
5896 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5897 auto builder = circuit.getBodyBuilder();
5899 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
5900 annotations, enabledLayers);
5902 auto visibility = isPublic ? SymbolTable::Visibility::Public
5903 : SymbolTable::Visibility::Private;
5904 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5908 deferredModules.emplace_back(DeferredModuleToParse{
5909 moduleOp, portLocs, getLexer().getCursor(), indent});
5911 if (skipToModuleEnd(indent))
5917ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5918 consumeToken(FIRToken::kw_formal);
5919 return parseFormalLike<FormalOp>(circuit, indent);
5923ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5925 consumeToken(FIRToken::kw_simulation);
5926 return parseFormalLike<SimulationOp>(circuit, indent);
5933ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5935 StringRef id, moduleName;
5938 auto builder = circuit.getBodyBuilder();
5941 if (parseId(
id,
"expected test name") ||
5942 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5943 parseId(moduleName,
"expected module name"))
5947 NamedAttrList params;
5948 if (consumeIf(FIRToken::comma)) {
5950 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5951 return emitError(
"expected 'bound' after ','");
5953 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5954 parseIntLit(bound,
"expected integer bound after '='"))
5957 return emitError(
"bound must be a positive integer");
5958 if (
info.parseOptionalInfo())
5960 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5963 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5964 info.parseOptionalInfo())
5966 while (getIndentation() > indent) {
5967 StringAttr paramName;
5968 Attribute paramValue;
5970 if (parseParameter(paramName, paramValue, paramLoc,
5973 if (params.set(paramName, paramValue))
5974 return emitError(paramLoc,
"redefinition of parameter '" +
5975 paramName.getValue() +
"'");
5979 Op::create(builder,
info.getLoc(),
id, moduleName,
5980 params.getDictionary(getContext()));
5984ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5986 switch (getToken().getKind()) {
5987 case FIRToken::kw_class:
5988 return parseClass(circuit, indent);
5989 case FIRToken::kw_declgroup:
5990 if (requireFeature({3, 2, 0},
"optional groups") ||
5991 removedFeature({3, 3, 0},
"optional groups"))
5993 return parseLayer(circuit);
5994 case FIRToken::kw_domain:
5997 return parseDomain(circuit, indent);
5998 case FIRToken::kw_extclass:
5999 return parseExtClass(circuit, indent);
6000 case FIRToken::kw_extmodule:
6001 return parseExtModule(circuit, indent);
6002 case FIRToken::kw_formal:
6003 if (requireFeature({4, 0, 0},
"formal tests"))
6005 return parseFormal(circuit, indent);
6006 case FIRToken::kw_intmodule:
6007 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6008 removedFeature({4, 0, 0},
"intrinsic modules"))
6010 return parseIntModule(circuit, indent);
6011 case FIRToken::kw_layer:
6012 if (requireFeature({3, 3, 0},
"layers"))
6014 return parseLayer(circuit);
6015 case FIRToken::kw_module:
6016 return parseModule(circuit,
false, indent);
6017 case FIRToken::kw_public:
6018 if (requireFeature({3, 3, 0},
"public modules"))
6021 if (getToken().getKind() == FIRToken::kw_module)
6022 return parseModule(circuit,
true, indent);
6023 return emitError(getToken().
getLoc(),
"only modules may be public");
6024 case FIRToken::kw_simulation:
6027 return parseSimulation(circuit, indent);
6028 case FIRToken::kw_type:
6029 return parseTypeDecl();
6030 case FIRToken::kw_option:
6033 return parseOptionDecl(circuit);
6035 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6040ParseResult FIRCircuitParser::parseTypeDecl() {
6044 auto loc = getToken().getLoc();
6046 if (getToken().isKeyword())
6047 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6048 <<
"' for type alias name";
6050 if (parseId(
id,
"expected type name") ||
6051 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6054 auto name = StringAttr::get(type.getContext(),
id);
6057 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6058 type = BaseTypeAliasType::get(name, base);
6061 <<
"type alias for non-base type " << type
6062 <<
" is currently not supported. Type alias is stripped immediately";
6064 if (!getConstants().aliasMap.insert({id, type}).second)
6065 return emitError(loc) <<
"type alias `" << name.getValue()
6066 <<
"` is already defined";
6071ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6074 auto loc = getToken().getLoc();
6077 if (parseId(
id,
"expected an option group name") ||
6078 parseToken(FIRToken::colon,
6079 "expected ':' after option group definition") ||
6080 info.parseOptionalInfo())
6083 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6084 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6085 auto *block =
new Block;
6086 optionOp.getBody().push_back(block);
6087 builder.setInsertionPointToEnd(block);
6089 auto baseIndent = getIndentation();
6091 while (getIndentation() == baseIndent) {
6093 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6094 if (parseId(
id,
"expected an option case ID") ||
6095 caseInfo.parseOptionalInfo())
6098 if (!cases.insert(
id).second)
6099 return emitError(loc)
6100 <<
"duplicate option case definition '" <<
id <<
"'";
6102 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6109ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6110 auto baseIndent = getIndentation();
6113 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6116 auto parseOne = [&](
Block *block) -> ParseResult {
6117 auto indent = getIndentation();
6118 StringRef id, convention;
6121 if (parseId(
id,
"expected layer name") ||
6122 parseToken(FIRToken::comma,
"expected ','") ||
6123 parseGetSpelling(convention))
6126 auto layerConvention = symbolizeLayerConvention(convention);
6127 if (!layerConvention) {
6128 emitError() <<
"unknown convention '" << convention
6129 <<
"' (did you misspell it?)";
6132 if (layerConvention == LayerConvention::Inline &&
6133 requireFeature({4, 1, 0},
"inline layers"))
6137 hw::OutputFileAttr outputDir;
6138 if (consumeIf(FIRToken::comma)) {
6139 if (getToken().getKind() == FIRToken::string) {
6140 auto text = getToken().getStringValue();
6142 return emitError() <<
"output directory must not be blank";
6143 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6144 consumeToken(FIRToken::string);
6148 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6149 info.parseOptionalInfo())
6151 auto builder = OpBuilder::atBlockEnd(block);
6154 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6155 layerOp->getRegion(0).push_back(
new Block());
6157 layerOp->setAttr(
"output_file", outputDir);
6158 layerStack.push_back({indent, layerOp});
6162 if (parseOne(circuit.getBodyBlock()))
6166 while (getIndentation() > baseIndent) {
6167 switch (getToken().getKind()) {
6168 case FIRToken::kw_declgroup:
6169 case FIRToken::kw_layer: {
6172 while (layerStack.back().first >= getIndentation())
6173 layerStack.pop_back();
6174 auto parentLayer = layerStack.back().second;
6175 if (parseOne(&parentLayer.getBody().front()))
6180 return emitError(
"expected 'layer'"), failure();
6188FIRCircuitParser::parseDomains(SmallVectorImpl<Attribute> &domains,
6189 const DenseMap<Attribute, size_t> &nameToIndex) {
6192 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6193 parseToken(FIRToken::l_square,
"expected '['"))
6196 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6198 auto domainLoc = getToken().getLoc();
6199 if (parseId(domain,
"expected domain name"))
6201 auto indexItr = nameToIndex.find(domain);
6202 if (indexItr == nameToIndex.end()) {
6203 emitError(domainLoc)
6204 <<
"unknown domain name '" << domain.getValue() <<
"'";
6207 return domains.push_back(IntegerAttr::get(
6208 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6219FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6220 DeferredModuleToParse &deferredModule,
6221 InnerSymFixups &fixups) {
6222 FModuleLike moduleOp = deferredModule.moduleOp;
6223 auto &body = moduleOp->getRegion(0).front();
6224 auto &portLocs = deferredModule.portLocs;
6228 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6231 deferredModule.lexerCursor.restore(moduleBodyLexer);
6233 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6238 auto portList = moduleOp.getPorts();
6239 auto portArgs = body.getArguments();
6240 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6241 PortInfo &port = std::get<0>(tuple);
6242 llvm::SMLoc loc = std::get<1>(tuple);
6243 BlockArgument portArg = std::get<2>(tuple);
6245 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6249 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6252 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6258 size_t numVerifPrintfs = 0;
6259 std::optional<Location> printfLoc;
6261 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6266 printfLoc = printFOp.getLoc();
6269 if (numVerifPrintfs > 0) {
6271 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6273 <<
" printf-encoded verification operation(s), which are no longer "
6275 diag.attachNote(*printfLoc)
6276 <<
"example printf here, this is now just a printf and nothing more";
6277 diag.attachNote() <<
"For more information, see "
6278 "https://github.com/llvm/circt/issues/6970";
6292ParseResult FIRCircuitParser::parseCircuit(
6293 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6294 mlir::TimingScope &ts) {
6296 auto indent = getIndentation();
6297 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6299 if (!indent.has_value())
6300 return emitError(
"'FIRRTL' must be first token on its line");
6301 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6302 parseVersionLit(
"expected version literal"))
6304 indent = getIndentation();
6306 if (!indent.has_value())
6307 return emitError(
"'circuit' must be first token on its line");
6308 unsigned circuitIndent = *indent;
6312 SMLoc inlineAnnotationsLoc;
6313 StringRef inlineAnnotations;
6316 if (parseToken(FIRToken::kw_circuit,
6317 "expected a top-level 'circuit' definition") ||
6318 parseId(name,
"expected circuit name") ||
6319 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6320 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6321 info.parseOptionalInfo())
6325 OpBuilder b(mlirModule.getBodyRegion());
6326 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6329 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6335 SmallVector<Attribute> annos;
6336 if (!inlineAnnotations.empty())
6337 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6341 for (
auto *annotationsBuf : annotationsBufs)
6342 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6346 parseAnnotationTimer.stop();
6354 auto parseTimer = ts.nest(
"Parse modules");
6355 deferredModules.reserve(16);
6359 switch (getToken().getKind()) {
6367 case FIRToken::error:
6371 emitError(
"unexpected token in circuit");
6374 case FIRToken::kw_class:
6375 case FIRToken::kw_declgroup:
6376 case FIRToken::kw_domain:
6377 case FIRToken::kw_extclass:
6378 case FIRToken::kw_extmodule:
6379 case FIRToken::kw_intmodule:
6380 case FIRToken::kw_layer:
6381 case FIRToken::kw_formal:
6382 case FIRToken::kw_module:
6383 case FIRToken::kw_option:
6384 case FIRToken::kw_public:
6385 case FIRToken::kw_simulation:
6386 case FIRToken::kw_type: {
6387 auto indent = getIndentation();
6388 if (!indent.has_value())
6389 return emitError(
"'module' must be first token on its line"), failure();
6390 unsigned definitionIndent = *indent;
6392 if (definitionIndent <= circuitIndent)
6393 return emitError(
"module should be indented more"), failure();
6395 if (parseToplevelDefinition(circuit, definitionIndent))
6409 (void)getLexer().translateLocation(
info.getFIRLoc());
6415 DenseMap<Attribute, Location> nameToOrigLoc;
6419 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6424 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6427 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6428 .attachNote(it.first->second)
6429 .append(
"see existing symbol definition here");
6435 SymbolTable circuitSymTbl(circuit);
6437 moduleFixups.resize(deferredModules.size());
6442 for (
auto &d : deferredModules)
6443 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6446 auto anyFailed = mlir::failableParallelForEachN(
6447 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6448 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6449 moduleFixups[index]))
6453 if (failed(anyFailed))
6458 for (
auto &fixups : moduleFixups) {
6459 if (failed(fixups.resolve(innerSymbolNamespaces)))
6465 auto parseLayerName = [&](StringRef name) -> Attribute {
6467 auto [head, rest] = name.split(
".");
6468 SmallVector<FlatSymbolRefAttr> nestedRefs;
6469 while (!rest.empty()) {
6471 std::tie(next, rest) = rest.split(
".");
6472 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6474 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6477 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6478 SmallVector<Attribute> attrArray;
6479 auto *context = getContext();
6480 for (
const auto &str : strArray)
6481 attrArray.push_back(getAttr(str));
6482 if (attrArray.empty())
6484 return ArrayAttr::get(context, attrArray);
6487 if (
auto enableLayers =
6488 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6489 circuit.setEnableLayersAttr(enableLayers);
6490 if (
auto disableLayers =
6491 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6492 circuit.setDisableLayersAttr(disableLayers);
6494 auto getStrAttr = [&](StringRef str) -> Attribute {
6495 return StringAttr::get(getContext(), str);
6498 if (
auto selectInstChoice =
6499 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6500 circuit.setSelectInstChoiceAttr(selectInstChoice);
6502 circuit.setDefaultLayerSpecialization(
6503 getConstants().options.defaultLayerSpecialization);
6516 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6517 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6518 unsigned fileID = 1;
6520 annotationsBufs.push_back(
6521 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6523 context->loadDialect<CHIRRTLDialect>();
6524 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6528 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6531 SharedParserConstants state(context, options);
6532 FIRLexer lexer(sourceMgr, context);
6534 .parseCircuit(annotationsBufs, ts))
6539 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6540 if (failed(verify(*module)))
6547 static mlir::TranslateToMLIRRegistration fromFIR(
6548 "import-firrtl",
"import .fir",
6549 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6550 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 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::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