26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Diagnostics.h"
29#include "mlir/IR/ImplicitLocOpBuilder.h"
30#include "mlir/IR/PatternMatch.h"
31#include "mlir/IR/Threading.h"
32#include "mlir/IR/Verifier.h"
33#include "mlir/Support/Timing.h"
34#include "mlir/Tools/mlir-translate/Translation.h"
35#include "llvm/ADT/PointerEmbeddedInt.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallPtrSet.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/StringSet.h"
40#include "llvm/ADT/StringSwitch.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/JSON.h"
43#include "llvm/Support/LogicalResult.h"
44#include "llvm/Support/SourceMgr.h"
45#include "llvm/Support/raw_ostream.h"
50using namespace firrtl;
51using namespace chirrtl;
55using mlir::LocationAttr;
68struct SharedParserConstants {
72 loIdentifier(StringAttr::get(
context,
"lo")),
73 hiIdentifier(StringAttr::get(
context,
"hi")),
74 amountIdentifier(StringAttr::get(
context,
"amount")),
76 hw::InnerRefAttr::get(StringAttr::get(
context,
"module"),
77 StringAttr::get(
context,
"placeholder"))) {}
86 llvm::StringMap<FIRRTLType> aliasMap;
89 llvm::DenseMap<StringRef, ClassLike> classMap;
92 const ArrayAttr emptyArrayAttr;
95 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
98 const hw::InnerRefAttr placeholderInnerRef;
101 SharedParserConstants(
const SharedParserConstants &) =
delete;
102 void operator=(
const SharedParserConstants &) =
delete;
115 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
117 : version(version), constants(constants), lexer(lexer),
118 locatorFilenameCache(constants.loIdentifier ) {
122 SharedParserConstants &getConstants()
const {
return constants; }
123 MLIRContext *getContext()
const {
return constants.context; }
125 FIRLexer &getLexer() {
return lexer; }
128 std::optional<unsigned> getIndentation()
const {
133 const FIRToken &getToken()
const {
return lexer.getToken(); }
134 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
141 InFlightDiagnostic emitError(
const Twine &message = {}) {
142 return emitError(getToken().
getLoc(), message);
144 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
147 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
148 return emitWarning(getToken().
getLoc(), message);
151 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
161 Location translateLocation(llvm::SMLoc loc) {
162 return lexer.translateLocation(loc);
167 ParseResult parseOptionalInfoLocator(LocationAttr &result);
171 ParseResult parseOptionalName(StringAttr &name);
177 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
178 return requireFeature(minimum, feature, getToken().
getLoc());
181 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
182 if (version < minimum)
183 return emitError(loc)
184 << feature <<
" are a FIRRTL " << minimum
185 <<
"+ feature, but the specified FIRRTL version was " << version;
189 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
190 return removedFeature(removedVersion, feature, getToken().
getLoc());
193 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
195 if (version >= removedVersion)
196 return emitError(loc)
197 << feature <<
" were removed in FIRRTL " << removedVersion
198 <<
", but the specified FIRRTL version was " << version;
208 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
217 if (getToken().isNot(kind))
227 FIRToken consumedToken = getToken();
228 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
229 "shouldn't advance past EOF or errors");
231 return consumedToken;
240 FIRToken consumedToken = getToken();
241 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
243 return consumedToken;
248 ParseResult parseGetSpelling(StringRef &spelling) {
249 spelling = getTokenSpelling();
255 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
260 const std::function<ParseResult()> &parseElement);
267 ParseResult parseIntLit(APInt &result,
const Twine &message);
268 ParseResult parseIntLit(int64_t &result,
const Twine &message);
269 ParseResult parseIntLit(int32_t &result,
const Twine &message);
272 ParseResult parseVersionLit(
const Twine &message);
275 template <
typename T>
276 ParseResult parseOptionalWidth(T &result);
279 ParseResult parseId(StringRef &result,
const Twine &message);
280 ParseResult parseId(StringAttr &result,
const Twine &message);
281 ParseResult parseFieldId(StringRef &result,
const Twine &message);
282 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
283 const Twine &message);
284 ParseResult parseEnumType(
FIRRTLType &result);
285 ParseResult parseListType(
FIRRTLType &result);
288 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
290 ParseResult parseRUW(RUWBehavior &result);
291 ParseResult parseOptionalRUW(RUWBehavior &result);
293 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
294 SMLoc &resultLoc,
bool allowAggregates =
false);
295 ParseResult parseParameterValue(Attribute &resultValue,
296 bool allowAggregates =
false);
302 FIRParser(
const FIRParser &) =
delete;
303 void operator=(
const FIRParser &) =
delete;
307 SharedParserConstants &constants;
311 StringAttr locatorFilenameCache;
313 FileLineColLoc fileLineColLocCache;
322InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
323 auto diag = mlir::emitError(translateLocation(loc), message);
327 if (getToken().is(FIRToken::error))
332InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
333 return mlir::emitWarning(translateLocation(loc), message);
343 const Twine &message) {
344 if (consumeIf(expectedToken))
346 return emitError(message);
353 const std::function<ParseResult()> &parseElement) {
354 if (consumeIf(rightToken))
360 while (consumeIf(FIRToken::comma)) {
365 if (parseToken(rightToken,
"expected ','"))
397 if (failed(
parser->parseOptionalInfoLocator(loc)))
401 switch (
parser->constants.options.infoLocatorHandling) {
402 case ILH::IgnoreInfo:
403 assert(0 &&
"Should not return info locations if ignoring");
405 case ILH::PreferInfo:
409 infoLoc = FusedLoc::get(loc.getContext(),
410 {loc, parser->translateLocation(firLoc)});
437ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
438 if (getToken().isNot(FIRToken::fileinfo))
441 auto loc = getToken().getLoc();
443 auto spelling = getTokenSpelling();
444 consumeToken(FIRToken::fileinfo);
448 constants.options.infoLocatorHandling ==
449 FIRParserOptions::InfoLocHandling::IgnoreInfo,
450 locatorFilenameCache, fileLineColLocCache, getContext());
453 if (!locationPair.first) {
454 mlir::emitWarning(translateLocation(loc),
455 "ignoring unknown @ info record format");
461 if (locationPair.first && constants.options.infoLocatorHandling ==
462 FIRParserOptions::InfoLocHandling::IgnoreInfo)
466 result = *locationPair.second;
474ParseResult FIRParser::parseOptionalName(StringAttr &name) {
476 if (getToken().isNot(FIRToken::colon)) {
477 name = StringAttr::get(getContext(),
"");
481 consumeToken(FIRToken::colon);
483 if (parseId(nameRef,
"expected result name"))
486 name = StringAttr::get(getContext(), nameRef);
497ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
499 if (getToken().isNot(FIRToken::inlineannotation))
502 loc = getToken().getLoc();
504 result = getTokenSpelling().drop_front(2).drop_back(1);
505 consumeToken(FIRToken::inlineannotation);
523ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
524 auto spelling = getTokenSpelling();
525 bool isNegative =
false;
526 switch (getToken().getKind()) {
527 case FIRToken::signed_integer:
528 isNegative = spelling[0] ==
'-';
529 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
530 spelling = spelling.drop_front();
532 case FIRToken::integer:
533 if (spelling.getAsInteger(10, result))
534 return emitError(message), failure();
538 if (result.isNegative())
539 result = result.zext(result.getBitWidth() + 1);
548 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
549 result = result.trunc(32);
553 case FIRToken::radix_specified_integer: {
554 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
556 if (spelling[0] ==
'-') {
558 spelling = spelling.drop_front();
560 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
565 spelling = spelling.drop_front(2);
566 if (spelling.getAsInteger(base, result))
567 return emitError(
"invalid character in integer literal"), failure();
568 if (result.isNegative())
569 result = result.zext(result.getBitWidth() + 1);
575 case FIRToken::string: {
578 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
581 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
582 spelling = spelling.drop_back().drop_front();
586 switch (spelling.empty() ?
' ' : spelling.front()) {
597 return emitError(
"expected base specifier (h/o/b) in integer literal"),
600 spelling = spelling.drop_front();
603 bool isNegative =
false;
604 if (!spelling.empty() && spelling.front() ==
'+')
605 spelling = spelling.drop_front();
606 else if (!spelling.empty() && spelling.front() ==
'-') {
608 spelling = spelling.drop_front();
612 if (spelling.empty())
613 return emitError(
"expected digits in integer literal"), failure();
615 if (spelling.getAsInteger(base, result))
616 return emitError(
"invalid character in integer literal"), failure();
621 if (result.isNegative())
622 result = result.zext(result.getBitWidth() + 1);
627 consumeToken(FIRToken::string);
632 return emitError(
"expected integer literal"), failure();
636ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
638 auto loc = getToken().getLoc();
639 if (parseIntLit(value, message))
642 result = (int64_t)value.getLimitedValue(INT64_MAX);
644 return emitError(loc,
"value is too big to handle"), failure();
648ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
650 auto loc = getToken().getLoc();
651 if (parseIntLit(value, message))
654 result = (int32_t)value.getLimitedValue(INT32_MAX);
656 return emitError(loc,
"value is too big to handle"), failure();
662ParseResult FIRParser::parseVersionLit(
const Twine &message) {
663 auto spelling = getTokenSpelling();
664 if (getToken().getKind() != FIRToken::version)
665 return emitError(message), failure();
667 auto [a, d] = spelling.split(
".");
668 auto [b, c] = d.split(
".");
669 APInt aInt, bInt, cInt;
670 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
671 c.getAsInteger(10, cInt))
672 return emitError(
"failed to parse version string"), failure();
673 version.major = aInt.getLimitedValue(UINT32_MAX);
674 version.minor = bInt.getLimitedValue(UINT32_MAX);
675 version.patch = cInt.getLimitedValue(UINT32_MAX);
676 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
677 return emitError(
"integers out of range"), failure();
681 consumeToken(FIRToken::version);
689ParseResult FIRParser::parseOptionalWidth(T &result) {
690 if (!consumeIf(FIRToken::less))
691 return result = -1, success();
694 auto widthLoc = getToken().getLoc();
695 if (parseIntLit(result,
"expected width") ||
696 parseToken(FIRToken::greater,
"expected >"))
700 return emitError(widthLoc,
"invalid width specifier"), failure();
709ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
710 switch (getToken().getKind()) {
712 case FIRToken::identifier:
713 case FIRToken::literal_identifier:
715#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
716#include "FIRTokenKinds.def"
721 if (getToken().getKind() == FIRToken::literal_identifier)
722 result = getTokenSpelling().drop_front().drop_back();
724 result = getTokenSpelling();
734ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
736 if (parseId(name, message))
739 result = StringAttr::get(getContext(), name);
748ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
750 result = getTokenSpelling();
751 if (consumeIf(FIRToken::integer))
757 if (parseId(result, message))
769ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
770 const Twine &message) {
772 StringRef tmp = getTokenSpelling();
774 if (consumeIf(FIRToken::integer)) {
775 result.push_back(tmp);
779 if (consumeIf(FIRToken::floatingpoint)) {
783 auto [a, b] = tmp.split(
".");
789 if (consumeIf(FIRToken::version)) {
791 auto [a, d] = tmp.split(
".");
792 auto [b, c] = d.split(
".");
800 if (parseId(tmp, message))
802 result.push_back(tmp);
808ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
809 if (parseToken(FIRToken::l_brace_bar,
810 "expected leading '{|' in enumeration type"))
812 SmallVector<StringAttr> names;
813 SmallVector<APInt> values;
814 SmallVector<FIRRTLBaseType> types;
815 SmallVector<SMLoc> locs;
816 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
817 auto fieldLoc = getToken().getLoc();
818 locs.push_back(fieldLoc);
822 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
824 auto name = StringAttr::get(getContext(), nameStr);
825 names.push_back(name);
831 if (consumeIf(FIRToken::equal)) {
832 if (parseIntLit(value,
"expected integer value for enumeration tag"))
834 if (value.isNegative())
835 return emitError(fieldLoc,
"enum tag value must be non-negative");
836 }
else if (values.empty()) {
842 auto &prev = values.back();
843 if (prev.isMaxValue())
844 value = prev.zext(prev.getBitWidth() + 1);
849 values.push_back(std::move(value));
853 if (consumeIf(FIRToken::colon)) {
855 if (
parseType(parsedType,
"expected enumeration type"))
857 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
859 return emitError(fieldLoc,
"field must be a base type");
862 type = UIntType::get(getContext(), 0);
864 types.push_back(type);
866 auto r = type.getRecursiveTypeProperties();
868 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
869 if (r.containsAnalog)
870 return emitError(fieldLoc)
871 <<
"enum field " << name <<
" contains analog";
872 if (r.hasUninferredWidth)
873 return emitError(fieldLoc)
874 <<
"enum field " << name <<
" has uninferred width";
875 if (r.hasUninferredReset)
876 return emitError(fieldLoc)
877 <<
"enum field " << name <<
" has uninferred reset";
883 SmallPtrSet<StringAttr, 4> nameSet;
884 for (
auto [name, loc] :
llvm::zip(names, locs))
885 if (!nameSet.insert(name).second)
886 return emitError(loc,
887 "duplicate variant name in enum: " + name.getValue());
890 unsigned bitwidth = 0;
891 for (
auto &value : values)
892 bitwidth = std::max(bitwidth, value.getActiveBits());
894 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
898 SmallPtrSet<IntegerAttr, 4> valueSet;
899 SmallVector<FEnumType::EnumElement, 4> elements;
900 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
901 auto tagValue = value.zextOrTrunc(bitwidth);
902 auto attr = IntegerAttr::get(tagType, tagValue);
904 if (!valueSet.insert(attr).second)
905 return emitError(loc,
"duplicate variant value in enum: ") << attr;
906 elements.push_back({name, attr, type});
909 llvm::sort(elements);
910 result = FEnumType::get(getContext(), elements);
914ParseResult FIRParser::parsePropertyType(
PropertyType &result,
915 const Twine &message) {
916 auto loc = getToken().getLoc();
921 auto prop = type_dyn_cast<PropertyType>(type);
923 return emitError(loc,
"expected property type");
929ParseResult FIRParser::parseListType(
FIRRTLType &result) {
930 consumeToken(FIRToken::kw_List);
933 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
934 parsePropertyType(
elementType,
"expected List element type") ||
935 parseToken(FIRToken::greater,
"expected '>' in List type"))
961ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
962 switch (getToken().getKind()) {
964 return emitError(message), failure();
966 case FIRToken::kw_Clock:
967 consumeToken(FIRToken::kw_Clock);
968 result = ClockType::get(getContext());
971 case FIRToken::kw_Inst: {
975 consumeToken(FIRToken::kw_Inst);
976 if (parseToken(FIRToken::less,
"expected < in Inst type"))
979 auto loc = getToken().getLoc();
981 if (parseId(
id,
"expected class name in Inst type"))
985 const auto &classMap = getConstants().classMap;
986 auto lookup = classMap.find(
id);
987 if (lookup == classMap.end())
988 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
990 auto classOp = lookup->second;
992 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
995 result = classOp.getInstanceType();
999 case FIRToken::kw_AnyRef: {
1003 consumeToken(FIRToken::kw_AnyRef);
1004 result = AnyRefType::get(getContext());
1008 case FIRToken::kw_Reset:
1009 consumeToken(FIRToken::kw_Reset);
1010 result = ResetType::get(getContext());
1013 case FIRToken::kw_AsyncReset:
1014 consumeToken(FIRToken::kw_AsyncReset);
1015 result = AsyncResetType::get(getContext());
1018 case FIRToken::kw_UInt:
1019 case FIRToken::kw_SInt:
1020 case FIRToken::kw_Analog: {
1021 auto kind = getToken().getKind();
1026 if (parseOptionalWidth(width))
1029 if (kind == FIRToken::kw_SInt)
1030 result = SIntType::get(getContext(), width);
1031 else if (kind == FIRToken::kw_UInt)
1032 result = UIntType::get(getContext(), width);
1034 assert(kind == FIRToken::kw_Analog);
1035 result = AnalogType::get(getContext(), width);
1040 case FIRToken::kw_Domain: {
1044 result = DomainType::get(getContext());
1048 case FIRToken::kw_Probe:
1049 case FIRToken::kw_RWProbe: {
1050 auto kind = getToken().getKind();
1051 auto loc = getToken().getLoc();
1056 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1057 parseType(type,
"expected probe data type"))
1060 SmallVector<StringRef> layers;
1061 if (consumeIf(FIRToken::comma)) {
1062 if (requireFeature({4, 0, 0},
"colored probes"))
1067 loc = getToken().getLoc();
1068 if (parseId(layer,
"expected layer name"))
1070 layers.push_back(layer);
1071 }
while (consumeIf(FIRToken::period));
1074 if (!consumeIf(FIRToken::greater))
1075 return emitError(loc,
"expected '>' to end reference type");
1077 bool forceable = kind == FIRToken::kw_RWProbe;
1079 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1081 return emitError(loc,
"invalid probe inner type, must be base-type");
1084 return emitError(loc,
"probe inner type must be passive");
1086 if (forceable &&
innerType.containsConst())
1087 return emitError(loc,
"rwprobe cannot contain const");
1089 SymbolRefAttr layer;
1090 if (!layers.empty()) {
1092 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1093 return FlatSymbolRefAttr::get(getContext(), a);
1095 layer = SymbolRefAttr::get(getContext(), layers.front(),
1096 llvm::to_vector(nestedLayers));
1099 result = RefType::get(innerType, forceable, layer);
1103 case FIRToken::l_brace: {
1104 consumeToken(FIRToken::l_brace);
1106 SmallVector<OpenBundleType::BundleElement, 4> elements;
1107 SmallPtrSet<StringAttr, 4> nameSet;
1108 bool bundleCompatible =
true;
1109 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1110 bool isFlipped = consumeIf(FIRToken::kw_flip);
1112 auto loc = getToken().getLoc();
1113 StringRef fieldNameStr;
1114 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1115 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1117 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1120 if (!nameSet.insert(fieldName).second)
1121 return emitError(loc,
"duplicate field name in bundle: " +
1122 fieldName.getValue());
1125 if (
parseType(type,
"expected bundle field type"))
1128 elements.push_back({fieldName, isFlipped, type});
1129 bundleCompatible &= isa<BundleType::ElementType>(type);
1136 if (bundleCompatible) {
1137 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1138 return BundleType::BundleElement{
1139 element.name, element.isFlip,
1140 cast<BundleType::ElementType>(element.type)};
1142 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1144 result = OpenBundleType::get(getContext(), elements);
1148 case FIRToken::l_brace_bar: {
1149 if (parseEnumType(result))
1154 case FIRToken::identifier: {
1156 auto loc = getToken().getLoc();
1157 if (parseId(
id,
"expected a type alias name"))
1159 auto it = constants.aliasMap.find(
id);
1160 if (it == constants.aliasMap.end()) {
1161 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1164 result = it->second;
1168 case FIRToken::kw_const: {
1169 consumeToken(FIRToken::kw_const);
1170 auto nextToken = getToken();
1171 auto loc = nextToken.getLoc();
1174 if (nextToken.is(FIRToken::kw_const))
1175 return emitError(loc,
"'const' can only be specified once on a type");
1180 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1182 return emitError(loc,
"only hardware types can be 'const'");
1184 result = baseType.getConstType(
true);
1188 case FIRToken::kw_String:
1189 if (requireFeature({3, 1, 0},
"Strings"))
1191 consumeToken(FIRToken::kw_String);
1192 result = StringType::get(getContext());
1194 case FIRToken::kw_Integer:
1195 if (requireFeature({3, 1, 0},
"Integers"))
1197 consumeToken(FIRToken::kw_Integer);
1198 result = FIntegerType::get(getContext());
1200 case FIRToken::kw_Bool:
1203 consumeToken(FIRToken::kw_Bool);
1204 result = BoolType::get(getContext());
1206 case FIRToken::kw_Double:
1209 consumeToken(FIRToken::kw_Double);
1210 result = DoubleType::get(getContext());
1212 case FIRToken::kw_Path:
1215 consumeToken(FIRToken::kw_Path);
1216 result = PathType::get(getContext());
1218 case FIRToken::kw_List:
1219 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1225 while (consumeIf(FIRToken::l_square)) {
1226 auto sizeLoc = getToken().getLoc();
1228 if (parseIntLit(size,
"expected width") ||
1229 parseToken(FIRToken::r_square,
"expected ]"))
1233 return emitError(sizeLoc,
"invalid size specifier"), failure();
1235 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1237 result = FVectorType::get(baseType, size);
1239 result = OpenVectorType::get(result, size);
1246ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1247 switch (getToken().getKind()) {
1249 case FIRToken::kw_old:
1250 result = RUWBehavior::Old;
1251 consumeToken(FIRToken::kw_old);
1253 case FIRToken::kw_new:
1254 result = RUWBehavior::New;
1255 consumeToken(FIRToken::kw_new);
1257 case FIRToken::kw_undefined:
1258 result = RUWBehavior::Undefined;
1259 consumeToken(FIRToken::kw_undefined);
1269ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1270 switch (getToken().getKind()) {
1274 case FIRToken::kw_old:
1275 result = RUWBehavior::Old;
1276 consumeToken(FIRToken::kw_old);
1278 case FIRToken::kw_new:
1279 result = RUWBehavior::New;
1280 consumeToken(FIRToken::kw_new);
1282 case FIRToken::kw_undefined:
1283 result = RUWBehavior::Undefined;
1284 consumeToken(FIRToken::kw_undefined);
1292ParseResult FIRParser::parseParameter(StringAttr &resultName,
1293 Attribute &resultValue, SMLoc &resultLoc,
1294 bool allowAggregates) {
1295 auto loc = getToken().getLoc();
1299 if (parseId(name,
"expected parameter name") ||
1300 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1305 if (parseParameterValue(value, allowAggregates))
1308 resultName = StringAttr::get(getContext(), name);
1309 resultValue = value;
1320ParseResult FIRParser::parseParameterValue(Attribute &value,
1321 bool allowAggregates) {
1322 mlir::Builder builder(getContext());
1323 switch (getToken().getKind()) {
1326 case FIRToken::integer:
1327 case FIRToken::signed_integer: {
1329 if (parseIntLit(result,
"invalid integer parameter"))
1335 if (result.getBitWidth() < 32)
1336 result = result.sext(32);
1338 value = builder.getIntegerAttr(
1339 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1345 case FIRToken::string: {
1347 value = builder.getStringAttr(getToken().getStringValue());
1348 consumeToken(FIRToken::string);
1353 case FIRToken::verbatim_string: {
1355 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1356 value = hw::ParamVerbatimAttr::get(text);
1357 consumeToken(FIRToken::verbatim_string);
1362 case FIRToken::floatingpoint: {
1364 if (!llvm::to_float(getTokenSpelling(), v))
1365 return emitError(
"invalid float parameter syntax"), failure();
1367 value = builder.getF64FloatAttr(v);
1368 consumeToken(FIRToken::floatingpoint);
1373 case FIRToken::l_square: {
1374 if (!allowAggregates)
1375 return emitError(
"expected non-aggregate parameter value");
1378 SmallVector<Attribute> elements;
1379 auto parseElement = [&] {
1380 return parseParameterValue(elements.emplace_back(),
1383 if (parseListUntil(FIRToken::r_square, parseElement))
1386 value = builder.getArrayAttr(elements);
1391 case FIRToken::l_brace: {
1392 if (!allowAggregates)
1393 return emitError(
"expected non-aggregate parameter value");
1396 NamedAttrList fields;
1397 auto parseField = [&]() -> ParseResult {
1398 StringAttr fieldName;
1399 Attribute fieldValue;
1401 if (parseParameter(fieldName, fieldValue, fieldLoc,
1404 if (fields.set(fieldName, fieldValue))
1405 return emitError(fieldLoc)
1406 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1409 if (parseListUntil(FIRToken::r_brace, parseField))
1412 value = fields.getDictionary(getContext());
1417 return emitError(
"expected parameter value");
1432 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1440struct UnbundledValueRestorer {
1442 size_t startingSize;
1444 startingSize = list.size();
1446 ~UnbundledValueRestorer() { list.resize(startingSize); }
1455struct FIRModuleContext :
public FIRParser {
1456 explicit FIRModuleContext(Block *topLevelBlock,
1457 SharedParserConstants &constants,
FIRLexer &lexer,
1459 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1462 template <
typename OpTy = ConstantOp,
typename... Args>
1463 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1464 Type type, Args &&...args) {
1465 auto &result = constantCache[{attr, type}];
1471 OpBuilder::InsertPoint savedIP;
1474 if (builder.getInsertionBlock() != topLevelBlock) {
1475 savedIP = builder.saveInsertionPoint();
1476 auto *block = builder.getInsertionBlock();
1478 auto *op = block->getParentOp();
1479 if (!op || !op->getBlock()) {
1481 builder.setInsertionPointToEnd(topLevelBlock);
1484 if (op->getBlock() == topLevelBlock) {
1485 builder.setInsertionPoint(op);
1488 block = op->getBlock();
1492 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1494 if (savedIP.isSet())
1495 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1506 Value &getCachedSubaccess(Value value,
unsigned index) {
1507 auto &result = subaccessCache[{value, index}];
1510 auto it = scopeMap.find(value.getParentBlock());
1511 if (it != scopeMap.end())
1512 it->second->scopedSubaccesses.push_back({result, index});
1522 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1523 bool insertNameIntoGlobalScope =
false);
1524 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1525 bool insertNameIntoGlobalScope =
false) {
1527 insertNameIntoGlobalScope);
1531 void removeSymbolEntry(StringRef name);
1535 SMLoc loc,
bool fatal =
true);
1540 StringRef field, SMLoc loc);
1548 assert(index < unbundledValues.size());
1549 return unbundledValues[index];
1559 struct ContextScope {
1560 friend struct FIRModuleContext;
1561 ContextScope(FIRModuleContext &moduleContext, Block *block)
1562 : moduleContext(moduleContext), block(block),
1563 previousScope(moduleContext.currentScope) {
1564 moduleContext.currentScope =
this;
1565 moduleContext.scopeMap[block] =
this;
1570 for (
auto *entryPtr : scopedDecls)
1571 entryPtr->second.first = SMLoc();
1574 for (
auto subaccess : scopedSubaccesses)
1575 moduleContext.subaccessCache.erase(subaccess);
1577 moduleContext.scopeMap.erase(block);
1579 moduleContext.currentScope = previousScope;
1583 void operator=(
const ContextScope &) =
delete;
1584 ContextScope(
const ContextScope &) =
delete;
1586 FIRModuleContext &moduleContext;
1588 ContextScope *previousScope;
1589 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1590 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1595 Block *topLevelBlock;
1601 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1613 DenseMap<Block *, ContextScope *> scopeMap;
1618 ContextScope *currentScope =
nullptr;
1624void FIRModuleContext::removeSymbolEntry(StringRef name) {
1625 symbolTable.erase(name);
1634ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1636 bool insertNameIntoGlobalScope) {
1639 auto [entryIt, inserted] =
1644 if (entryIt->second.first.isValid()) {
1646 emitError(loc,
"redefinition of name '" + name +
"' ")
1647 .attachNote(translateLocation(entryIt->second.first))
1648 <<
"previous definition here.";
1651 emitError(loc,
"redefinition of name '" + name +
"' ")
1652 <<
"- FIRRTL has flat namespace and requires all "
1653 <<
"declarations in a module to have unique names.";
1660 entryIt->second = {loc, entry};
1661 if (currentScope && !insertNameIntoGlobalScope)
1662 currentScope->scopedDecls.push_back(&*entryIt);
1669 StringRef name, SMLoc loc) {
1670 auto &entry = symbolTable[name];
1671 if (!entry.first.isValid())
1672 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1673 result = entry.second;
1674 assert(result &&
"name in symbol table without definition");
1678ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1680 SMLoc loc,
bool fatal) {
1681 if (!isa<Value>(entry)) {
1683 emitError(loc,
"bundle value should only be used from subfield");
1686 result = cast<Value>(entry);
1690ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1692 StringRef fieldName,
1694 if (!isa<UnbundledID>(entry)) {
1695 emitError(loc,
"value should not be used from subfield");
1699 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1701 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1702 assert(unbundledId < unbundledValues.size());
1704 for (
auto elt : ubEntry) {
1705 if (elt.first == fieldAttr) {
1706 result = elt.second;
1711 emitError(loc,
"use of invalid field name '")
1712 << fieldName <<
"' on bundle value";
1738struct LazyLocationListener :
public OpBuilder::Listener {
1739 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1740 assert(builder.getListener() ==
nullptr);
1741 builder.setListener(
this);
1744 ~LazyLocationListener() {
1745 assert(subOps.empty() &&
"didn't process parsed operations");
1746 assert(builder.getListener() ==
this);
1747 builder.setListener(
nullptr);
1750 void startStatement() {
1751 assert(!isActive &&
"Already processing a statement");
1757 void endStatement(FIRParser &parser) {
1758 assert(isActive &&
"Not parsing a statement");
1762 for (
auto opAndSMLoc : subOps) {
1766 switch (parser.getConstants().options.infoLocatorHandling) {
1767 case ILH::IgnoreInfo:
1769 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1771 case ILH::PreferInfo:
1772 opAndSMLoc.first->setLoc(infoLoc);
1774 case ILH::FusedInfo:
1775 opAndSMLoc.first->setLoc(FusedLoc::get(
1776 infoLoc.getContext(),
1777 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1784 for (
auto opAndSMLoc : subOps)
1785 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1790 infoLoc = LocationAttr();
1791 currentSMLoc = SMLoc();
1796 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1799 void setInfoLoc(LocationAttr loc) {
1800 assert(!infoLoc &&
"Info location multiply specified");
1806 void notifyOperationInserted(Operation *op,
1807 mlir::IRRewriter::InsertPoint)
override {
1808 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1809 assert(isActive &&
"Not parsing a statement");
1810 subOps.push_back({op, currentSMLoc});
1815 bool isActive =
false;
1823 LocationAttr infoLoc;
1830 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1832 void operator=(
const LazyLocationListener &) =
delete;
1833 LazyLocationListener(
const LazyLocationListener &) =
delete;
1841struct InnerSymFixups {
1844 fixups.push_back({user, target});
1853 hw::InnerRefUserOpInterface innerRefUser;
1856 SmallVector<Fixup, 0> fixups;
1862 for (
auto &f : fixups) {
1865 return isnc.get(module);
1867 assert(ref &&
"unable to resolve inner symbol target");
1871 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1872 .Case<RWProbeOp>([ref](RWProbeOp op) {
1873 op.setTargetAttr(ref);
1876 .Default([](
auto *op) {
1877 return op->emitError(
"unknown inner-ref user requiring fixup");
1888struct FIRStmtParser :
public FIRParser {
1889 explicit FIRStmtParser(Block &blockToInsertInto,
1890 FIRModuleContext &moduleContext,
1891 InnerSymFixups &innerSymFixups,
1892 const SymbolTable &circuitSymTbl,
FIRVersion version,
1893 SymbolRefAttr layerSym = {})
1894 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1896 builder(UnknownLoc::
get(getContext()), getContext()),
1897 locationProcessor(this->builder), moduleContext(moduleContext),
1898 innerSymFixups(innerSymFixups), layerSym(layerSym),
1899 circuitSymTbl(circuitSymTbl) {
1900 builder.setInsertionPointToEnd(&blockToInsertInto);
1903 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1904 ParseResult parseSimpleStmtBlock(
unsigned indent);
1907 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1910 void emitInvalidate(Value val,
Flow flow);
1916 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1919 ParseResult parseOptionalInfo() {
1921 if (failed(parseOptionalInfoLocator(loc)))
1923 locationProcessor.setInfoLoc(loc);
1928 ParseResult parseExpImpl(Value &result,
const Twine &message,
1929 bool isLeadingStmt);
1930 ParseResult parseExp(Value &result,
const Twine &message) {
1931 return parseExpImpl(result, message,
false);
1933 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1934 return parseExpImpl(result, message,
true);
1936 ParseResult parseEnumExp(Value &result);
1937 ParseResult parsePathExp(Value &result);
1938 ParseResult parseDomainExp(Value &result);
1939 ParseResult parseRefExp(Value &result,
const Twine &message);
1940 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1941 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1942 const Twine &message);
1945 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1946 ParseResult parseIntrinsicStmt() {
1948 return parseIntrinsic(unused,
true);
1950 ParseResult parseIntrinsicExp(Value &result) {
1951 return parseIntrinsic(result,
false);
1953 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1955 template <
typename subop>
1956 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1957 ParseResult parseOptionalExpPostscript(Value &result,
1958 bool allowDynamic =
true);
1959 ParseResult parsePostFixFieldId(Value &result);
1960 ParseResult parsePostFixIntSubscript(Value &result);
1961 ParseResult parsePostFixDynamicSubscript(Value &result);
1962 ParseResult parseIntegerLiteralExp(Value &result);
1963 ParseResult parseListExp(Value &result);
1964 ParseResult parseListConcatExp(Value &result);
1965 ParseResult parseCatExp(Value &result);
1966 ParseResult parseUnsafeDomainCast(Value &result);
1967 ParseResult parseUnknownProperty(Value &result);
1969 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1970 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1972 auto loc = getToken().getLoc();
1973 locationProcessor.setLoc(loc);
1976 auto vals = std::array<Value, M>();
1977 auto ints = std::array<int64_t, N>();
1981 for (
size_t i = 0; i < M; ++i) {
1983 if (parseToken(FIRToken::comma,
"expected ','"))
1985 if (parseExp(vals[i],
"expected expression in primitive operand"))
1991 for (
size_t i = 0; i < N; ++i) {
1993 if (parseToken(FIRToken::comma,
"expected ','"))
1995 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2000 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2004 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2008 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2009 translateLocation(loc));
2014 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2015 result = op.getResult();
2019 template <
typename T,
unsigned M,
unsigned N>
2020 ParseResult parsePrimExp(Value &result) {
2021 auto ms = std::make_index_sequence<M>();
2022 auto ns = std::make_index_sequence<N>();
2023 return parsePrim<T, M, N>(ms, ns, result);
2026 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2029 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2030 SymbolRefAttr layerSym);
2031 ParseResult parseAttach();
2032 ParseResult parseMemPort(MemDirAttr direction);
2038 ArrayRef<Value> specOperands,
2039 StringAttr &formatStringResult,
2040 SmallVectorImpl<Value> &operands);
2041 ParseResult parsePrintf();
2042 ParseResult parseFPrintf();
2043 ParseResult parseFFlush();
2044 ParseResult parseSkip();
2045 ParseResult parseStop();
2046 ParseResult parseAssert();
2047 ParseResult parseAssume();
2048 ParseResult parseCover();
2049 ParseResult parseWhen(
unsigned whenIndent);
2050 ParseResult parseMatch(
unsigned matchIndent);
2051 ParseResult parseDomainDefine();
2052 ParseResult parseRefDefine();
2053 ParseResult parseRefForce();
2054 ParseResult parseRefForceInitial();
2055 ParseResult parseRefRelease();
2056 ParseResult parseRefReleaseInitial();
2057 ParseResult parseRefRead(Value &result);
2058 ParseResult parseProbe(Value &result);
2059 ParseResult parsePropAssign();
2060 ParseResult parseRWProbe(Value &result);
2061 ParseResult parseLeadingExpStmt(Value lhs);
2062 ParseResult parseConnect();
2063 ParseResult parseInvalidate();
2064 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2067 ParseResult parseInstance();
2068 ParseResult parseInstanceChoice();
2069 ParseResult parseObject();
2070 ParseResult parseCombMem();
2071 ParseResult parseSeqMem();
2072 ParseResult parseMem(
unsigned memIndent);
2073 ParseResult parseNode();
2074 ParseResult parseWire();
2075 ParseResult parseRegister(
unsigned regIndent);
2076 ParseResult parseRegisterWithReset();
2077 ParseResult parseContract(
unsigned blockIndent);
2080 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2083 ImplicitLocOpBuilder builder;
2084 LazyLocationListener locationProcessor;
2087 FIRModuleContext &moduleContext;
2090 InnerSymFixups &innerSymFixups;
2094 SymbolRefAttr layerSym;
2096 const SymbolTable &circuitSymTbl;
2103void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2104 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2111 auto props = tpe.getRecursiveTypeProperties();
2112 if (props.isPassive && !props.containsAnalog) {
2113 if (flow == Flow::Source)
2115 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2126 TypeSwitch<FIRRTLType>(tpe)
2127 .Case<BundleType>([&](
auto tpe) {
2128 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2129 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2131 OpBuilder::InsertionGuard guard(builder);
2132 builder.setInsertionPointAfterValue(val);
2133 subfield = SubfieldOp::create(builder, val, i);
2135 emitInvalidate(subfield,
2136 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2139 .Case<FVectorType>([&](
auto tpe) {
2140 auto tpex = tpe.getElementType();
2141 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2142 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2144 OpBuilder::InsertionGuard guard(builder);
2145 builder.setInsertionPointAfterValue(val);
2146 subindex = SubindexOp::create(builder, tpex, val, i);
2148 emitInvalidate(subindex, flow);
2176ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2177 bool isLeadingStmt) {
2178 auto token = getToken();
2179 auto kind = token.getKind();
2181 case FIRToken::lp_integer_add:
2182 case FIRToken::lp_integer_mul:
2183 case FIRToken::lp_integer_shr:
2184 case FIRToken::lp_integer_shl:
2185 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2194#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2196 case FIRToken::lp_##SPELLING: \
2197 if (requireFeature(VERSION, FEATURE)) \
2199 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2202#include "FIRTokenKinds.def"
2204 case FIRToken::l_brace_bar:
2206 return emitError(
"unexpected enumeration as start of statement");
2207 if (parseEnumExp(result))
2210 case FIRToken::lp_read:
2212 return emitError(
"unexpected read() as start of statement");
2213 if (parseRefRead(result))
2216 case FIRToken::lp_probe:
2218 return emitError(
"unexpected probe() as start of statement");
2219 if (parseProbe(result))
2222 case FIRToken::lp_rwprobe:
2224 return emitError(
"unexpected rwprobe() as start of statement");
2225 if (parseRWProbe(result))
2229 case FIRToken::kw_UInt:
2230 case FIRToken::kw_SInt:
2231 if (parseIntegerLiteralExp(result))
2234 case FIRToken::kw_String: {
2235 if (requireFeature({3, 1, 0},
"Strings"))
2237 locationProcessor.setLoc(getToken().
getLoc());
2238 consumeToken(FIRToken::kw_String);
2240 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2241 parseGetSpelling(spelling) ||
2242 parseToken(FIRToken::string,
2243 "expected string literal in String expression") ||
2244 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2247 result = moduleContext.getCachedConstant<StringConstantOp>(
2248 builder, attr, builder.getType<StringType>(), attr);
2251 case FIRToken::kw_Integer: {
2252 if (requireFeature({3, 1, 0},
"Integers"))
2254 locationProcessor.setLoc(getToken().
getLoc());
2255 consumeToken(FIRToken::kw_Integer);
2257 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2258 parseIntLit(value,
"expected integer literal in Integer expression") ||
2259 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2261 APSInt apint(value,
false);
2262 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2263 builder, IntegerAttr::get(getContext(), apint),
2264 builder.getType<FIntegerType>(), apint);
2267 case FIRToken::kw_Bool: {
2270 locationProcessor.setLoc(getToken().
getLoc());
2271 consumeToken(FIRToken::kw_Bool);
2272 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2275 if (consumeIf(FIRToken::kw_true))
2277 else if (consumeIf(FIRToken::kw_false))
2280 return emitError(
"expected true or false in Bool expression");
2281 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2283 auto attr = builder.getBoolAttr(value);
2284 result = moduleContext.getCachedConstant<BoolConstantOp>(
2285 builder, attr, builder.getType<BoolType>(), value);
2288 case FIRToken::kw_Double: {
2291 locationProcessor.setLoc(getToken().
getLoc());
2292 consumeToken(FIRToken::kw_Double);
2293 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2295 auto spelling = getTokenSpelling();
2296 if (parseToken(FIRToken::floatingpoint,
2297 "expected floating point in Double expression") ||
2298 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2303 if (!llvm::to_float(spelling, d))
2304 return emitError(
"invalid double");
2305 auto attr = builder.getF64FloatAttr(d);
2306 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2307 builder, attr, builder.getType<DoubleType>(), attr);
2310 case FIRToken::kw_List: {
2311 if (requireFeature({4, 0, 0},
"Lists"))
2314 return emitError(
"unexpected List<>() as start of statement");
2315 if (parseListExp(result))
2320 case FIRToken::lp_list_concat: {
2322 return emitError(
"unexpected list_create() as start of statement");
2323 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2328 case FIRToken::lp_path:
2330 return emitError(
"unexpected path() as start of statement");
2335 case FIRToken::lp_intrinsic:
2336 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2337 parseIntrinsicExp(result))
2341 case FIRToken::lp_cat:
2342 if (parseCatExp(result))
2346 case FIRToken::lp_unsafe_domain_cast:
2348 parseUnsafeDomainCast(result))
2351 case FIRToken::kw_Unknown:
2352 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2353 parseUnknownProperty(result))
2359 case FIRToken::identifier:
2360 case FIRToken::literal_identifier:
2363 auto loc = getToken().getLoc();
2365 if (parseId(name, message) ||
2366 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2370 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2373 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2378 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2379 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2380 parseOptionalInfo())
2383 locationProcessor.setLoc(loc);
2385 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2387 moduleContext.getUnbundledEntry(unbundledId);
2388 for (
auto elt : ubEntry)
2389 emitInvalidate(elt.second);
2397 StringRef fieldName;
2398 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2399 parseFieldId(fieldName,
"expected field name") ||
2400 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2408 case FIRToken::lp_shr:
2411 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2412 result = PadPrimOp::create(builder, result, 1);
2418 return parseOptionalExpPostscript(result);
2428ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2429 bool allowDynamic) {
2434 if (consumeIf(FIRToken::period)) {
2435 if (parsePostFixFieldId(result))
2442 if (consumeIf(FIRToken::l_square)) {
2443 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2444 if (parsePostFixIntSubscript(result))
2449 return emitError(
"subaccess not allowed here");
2450 if (parsePostFixDynamicSubscript(result))
2460template <
typename subop>
2462FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2464 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2470 auto baseType = cast<FIRRTLType>(base.getType());
2471 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2474 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2480 locationProcessor.setLoc(loc);
2481 OpBuilder::InsertionGuard guard(builder);
2482 builder.setInsertionPointAfterValue(base);
2483 auto op = subop::create(builder, resultType, base, indexNo);
2486 return value = op.getResult();
2493ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2494 auto loc = getToken().getLoc();
2495 SmallVector<StringRef, 3> fields;
2496 if (parseFieldIdSeq(fields,
"expected field name"))
2498 for (
auto fieldName : fields) {
2499 std::optional<unsigned> indexV;
2500 auto type = result.getType();
2501 if (
auto refTy = type_dyn_cast<RefType>(type))
2502 type = refTy.getType();
2503 if (
auto bundle = type_dyn_cast<BundleType>(type))
2504 indexV = bundle.getElementIndex(fieldName);
2505 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2506 indexV = bundle.getElementIndex(fieldName);
2507 else if (
auto klass = type_dyn_cast<ClassType>(type))
2508 indexV = klass.getElementIndex(fieldName);
2510 return emitError(loc,
"subfield requires bundle or object operand ");
2512 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2513 << result.getType();
2514 auto indexNo = *indexV;
2516 FailureOr<Value> subResult;
2517 if (type_isa<RefType>(result.getType()))
2518 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2519 else if (type_isa<ClassType>(type))
2520 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2521 else if (type_isa<BundleType>(type))
2522 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2524 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2526 if (failed(subResult))
2528 result = *subResult;
2537ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2538 auto loc = getToken().getLoc();
2540 if (parseIntLit(indexNo,
"expected index") ||
2541 parseToken(FIRToken::r_square,
"expected ']'"))
2545 return emitError(loc,
"invalid index specifier"), failure();
2547 FailureOr<Value> subResult;
2548 if (type_isa<RefType>(result.getType()))
2549 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2550 else if (type_isa<FVectorType>(result.getType()))
2551 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2553 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2555 if (failed(subResult))
2557 result = *subResult;
2565ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2566 auto loc = getToken().getLoc();
2568 if (parseExp(index,
"expected subscript index expression") ||
2569 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2573 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2575 return emitError(
"expected base type for index expression");
2576 indexType = indexType.getPassiveType();
2577 locationProcessor.setLoc(loc);
2582 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2585 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2586 translateLocation(loc));
2591 auto op = SubaccessOp::create(builder, resultType, result, index);
2592 result = op.getResult();
2598ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2599 bool isSigned = getToken().is(FIRToken::kw_SInt);
2600 auto loc = getToken().getLoc();
2606 if (parseOptionalWidth(width) ||
2607 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2608 parseIntLit(value,
"expected integer value") ||
2609 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2614 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2616 IntegerType::SignednessSemantics signedness =
2617 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2619 if (!value.isZero())
2620 return emitError(loc,
"zero bit constant must be zero");
2621 value = value.trunc(0);
2622 }
else if (width != -1) {
2624 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2626 return emitError(loc,
"initializer too wide for declared width");
2627 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2631 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2632 auto attr = builder.getIntegerAttr(attrType, value);
2634 locationProcessor.setLoc(loc);
2635 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2640ParseResult FIRStmtParser::parseListExp(Value &result) {
2641 auto loc = getToken().getLoc();
2643 if (parseListType(type))
2645 auto listType = type_cast<ListType>(type);
2648 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2651 SmallVector<Value, 3> operands;
2652 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2654 locationProcessor.setLoc(loc);
2655 if (parseExp(operand,
"expected expression in List expression"))
2659 if (!isa<AnyRefType>(elementType) ||
2660 !isa<ClassType>(operand.getType()))
2661 return emitError(loc,
"unexpected expression of type ")
2662 << operand.getType() <<
" in List expression of type "
2664 operand = ObjectAnyRefCastOp::create(builder, operand);
2667 operands.push_back(operand);
2672 locationProcessor.setLoc(loc);
2673 result = ListCreateOp::create(builder, listType, operands);
2678ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2679 consumeToken(FIRToken::lp_list_concat);
2681 auto loc = getToken().getLoc();
2683 SmallVector<Value, 3> operands;
2684 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2686 locationProcessor.setLoc(loc);
2687 if (parseExp(operand,
"expected expression in List concat expression"))
2690 if (!type_isa<ListType>(operand.getType()))
2691 return emitError(loc,
"unexpected expression of type ")
2692 << operand.getType() <<
" in List concat expression";
2695 type = type_cast<ListType>(operand.getType());
2697 if (operand.getType() != type)
2698 return emitError(loc,
"unexpected expression of type ")
2699 << operand.getType() <<
" in List concat expression of type "
2702 operands.push_back(operand);
2707 if (operands.empty())
2708 return emitError(loc,
"need at least one List to concatenate");
2710 locationProcessor.setLoc(loc);
2711 result = ListConcatOp::create(builder, type, operands);
2716ParseResult FIRStmtParser::parseCatExp(Value &result) {
2717 consumeToken(FIRToken::lp_cat);
2719 auto loc = getToken().getLoc();
2720 SmallVector<Value, 3> operands;
2721 std::optional<bool> isSigned;
2722 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2724 locationProcessor.setLoc(loc);
2725 auto operandLoc = getToken().getLoc();
2726 if (parseExp(operand,
"expected expression in cat expression"))
2728 if (!type_isa<IntType>(operand.getType())) {
2729 auto diag = emitError(loc,
"all operands must be Int type");
2730 diag.attachNote(translateLocation(operandLoc))
2731 <<
"non-integer operand is here";
2735 isSigned = type_isa<SIntType>(operand.getType());
2736 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2737 auto diag = emitError(loc,
"all operands must have same signedness");
2738 diag.attachNote(translateLocation(operandLoc))
2739 <<
"operand with different signedness is here";
2743 operands.push_back(operand);
2748 if (operands.size() != 2) {
2753 locationProcessor.setLoc(loc);
2754 result = CatPrimOp::create(builder, operands);
2758ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2759 consumeToken(FIRToken::lp_unsafe_domain_cast);
2761 auto loc = getToken().getLoc();
2763 if (parseExp(input,
"expected input"))
2766 SmallVector<Value> domains;
2767 if (consumeIf(FIRToken::comma)) {
2768 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2770 if (parseExp(domain,
"expected domain"))
2772 domains.push_back(domain);
2776 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2780 locationProcessor.setLoc(loc);
2781 result = UnsafeDomainCastOp::create(builder, input, domains);
2785ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2786 consumeToken(FIRToken::kw_Unknown);
2788 auto loc = getToken().getLoc();
2790 if (parseToken(FIRToken::colon,
"expected ':' in unknown property") ||
2791 parsePropertyType(type,
"expected property type"))
2794 locationProcessor.setLoc(loc);
2795 result = UnknownValueOp::create(builder, type);
2816std::optional<ParseResult>
2817FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2818 switch (getToken().getKind()) {
2821 return std::nullopt;
2823 case FIRToken::period:
2824 case FIRToken::l_square:
2825 case FIRToken::kw_is:
2826 case FIRToken::less_equal:
2832 auto loc = keyword.
getLoc();
2834 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2835 return ParseResult(failure());
2841 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2844 if (!consumeIf(FIRToken::period))
2845 return ParseResult(failure());
2847 StringRef fieldName;
2848 if (parseFieldId(fieldName,
"expected field name") ||
2849 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2850 return ParseResult(failure());
2854 if (parseOptionalExpPostscript(lhs))
2855 return ParseResult(failure());
2857 return parseLeadingExpStmt(lhs);
2863ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2866 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2869 auto subIndent = getIndentation();
2870 if (!subIndent.has_value())
2871 return emitError(
"expected statement to be on its own line"), failure();
2873 if (*subIndent <= indent)
2877 if (parseSimpleStmt(*subIndent))
2882ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2883 locationProcessor.startStatement();
2884 auto result = parseSimpleStmtImpl(stmtIndent);
2885 locationProcessor.endStatement(*
this);
2907ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2908 auto kind = getToken().getKind();
2911 case FIRToken::kw_invalidate:
2912 case FIRToken::kw_connect:
2913 case FIRToken::kw_regreset:
2917 kind = FIRToken::identifier;
2924 case FIRToken::kw_attach:
2925 return parseAttach();
2926 case FIRToken::kw_infer:
2927 return parseMemPort(MemDirAttr::Infer);
2928 case FIRToken::kw_read:
2929 return parseMemPort(MemDirAttr::Read);
2930 case FIRToken::kw_write:
2931 return parseMemPort(MemDirAttr::Write);
2932 case FIRToken::kw_rdwr:
2933 return parseMemPort(MemDirAttr::ReadWrite);
2934 case FIRToken::kw_connect:
2935 return parseConnect();
2936 case FIRToken::kw_propassign:
2937 if (requireFeature({3, 1, 0},
"properties"))
2939 return parsePropAssign();
2940 case FIRToken::kw_invalidate:
2941 return parseInvalidate();
2942 case FIRToken::lp_printf:
2943 return parsePrintf();
2944 case FIRToken::lp_fprintf:
2945 return parseFPrintf();
2946 case FIRToken::lp_fflush:
2947 return parseFFlush();
2948 case FIRToken::kw_skip:
2950 case FIRToken::lp_stop:
2952 case FIRToken::lp_assert:
2953 return parseAssert();
2954 case FIRToken::lp_assume:
2955 return parseAssume();
2956 case FIRToken::lp_cover:
2957 return parseCover();
2958 case FIRToken::kw_when:
2959 return parseWhen(stmtIndent);
2960 case FIRToken::kw_match:
2961 return parseMatch(stmtIndent);
2962 case FIRToken::kw_domain_define:
2963 return parseDomainDefine();
2964 case FIRToken::kw_define:
2965 return parseRefDefine();
2966 case FIRToken::lp_force:
2967 return parseRefForce();
2968 case FIRToken::lp_force_initial:
2969 return parseRefForceInitial();
2970 case FIRToken::lp_release:
2971 return parseRefRelease();
2972 case FIRToken::lp_release_initial:
2973 return parseRefReleaseInitial();
2974 case FIRToken::kw_group:
2975 if (requireFeature({3, 2, 0},
"optional groups") ||
2976 removedFeature({3, 3, 0},
"optional groups"))
2978 return parseLayerBlockOrGroup(stmtIndent);
2979 case FIRToken::kw_layerblock:
2980 if (requireFeature({3, 3, 0},
"layers"))
2982 return parseLayerBlockOrGroup(stmtIndent);
2983 case FIRToken::lp_intrinsic:
2984 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2986 return parseIntrinsicStmt();
2990 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2997 return parseLeadingExpStmt(lhs);
3001 case FIRToken::kw_inst:
3002 return parseInstance();
3003 case FIRToken::kw_instchoice:
3004 return parseInstanceChoice();
3005 case FIRToken::kw_object:
3006 return parseObject();
3007 case FIRToken::kw_cmem:
3008 return parseCombMem();
3009 case FIRToken::kw_smem:
3010 return parseSeqMem();
3011 case FIRToken::kw_mem:
3012 return parseMem(stmtIndent);
3013 case FIRToken::kw_node:
3015 case FIRToken::kw_wire:
3017 case FIRToken::kw_reg:
3018 return parseRegister(stmtIndent);
3019 case FIRToken::kw_regreset:
3020 return parseRegisterWithReset();
3021 case FIRToken::kw_contract:
3022 return parseContract(stmtIndent);
3026ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3028 SymbolRefAttr layerSym) {
3030 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3031 moduleContext, &blockToInsertInto);
3036 UnbundledValueRestorer x(moduleContext.unbundledValues);
3040 auto subParser = std::make_unique<FIRStmtParser>(
3041 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3045 auto stmtIndent = getIndentation();
3048 if (!stmtIndent.has_value())
3049 return subParser->parseSimpleStmt(indent);
3051 if (*stmtIndent <= indent)
3052 return emitError(
"statement must be indented more than previous statement"),
3056 return subParser->parseSimpleStmtBlock(indent);
3060ParseResult FIRStmtParser::parseAttach() {
3061 auto startTok = consumeToken(FIRToken::kw_attach);
3064 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3067 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3070 SmallVector<Value, 4> operands;
3071 operands.push_back({});
3072 if (parseExp(operands.back(),
"expected operand in attach"))
3075 while (consumeIf(FIRToken::comma)) {
3076 operands.push_back({});
3077 if (parseExp(operands.back(),
"expected operand in attach"))
3080 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3083 if (parseOptionalInfo())
3086 locationProcessor.setLoc(startTok.getLoc());
3087 AttachOp::create(builder, operands);
3094ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3095 auto startTok = consumeToken();
3096 auto startLoc = startTok.getLoc();
3100 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3106 Value memory, indexExp, clock;
3107 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3108 parseId(
id,
"expected result name") ||
3109 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3110 parseId(memName,
"expected memory name") ||
3111 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3112 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3113 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3114 parseExp(indexExp,
"expected index expression") ||
3115 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3116 parseToken(FIRToken::comma,
"expected ','") ||
3117 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3120 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3122 return emitError(startLoc,
3123 "memory port should have behavioral memory type");
3124 auto resultType = memVType.getElementType();
3126 ArrayAttr annotations = getConstants().emptyArrayAttr;
3127 locationProcessor.setLoc(startLoc);
3130 Value memoryPort, memoryData;
3132 OpBuilder::InsertionGuard guard(builder);
3133 builder.setInsertionPointAfterValue(memory);
3134 auto memoryPortOp = MemoryPortOp::create(
3135 builder, resultType, CMemoryPortType::get(getContext()), memory,
3136 direction,
id, annotations);
3137 memoryData = memoryPortOp.getResult(0);
3138 memoryPort = memoryPortOp.getResult(1);
3142 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3144 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3150ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3151 StringRef formatString,
3152 ArrayRef<Value> specOperands,
3153 StringAttr &formatStringResult,
3154 SmallVectorImpl<Value> &operands) {
3157 operands.append(specOperands.begin(), specOperands.end());
3158 formatStringResult =
3164 auto loc = translateLocation(formatStringLoc);
3167 formatStringResult, operands);
3172ParseResult FIRStmtParser::parsePrintf() {
3173 auto startTok = consumeToken(FIRToken::lp_printf);
3175 Value clock, condition;
3176 StringRef formatString;
3177 if (parseExp(clock,
"expected clock expression in printf") ||
3178 parseToken(FIRToken::comma,
"expected ','") ||
3179 parseExp(condition,
"expected condition in printf") ||
3180 parseToken(FIRToken::comma,
"expected ','"))
3183 auto formatStringLoc = getToken().getLoc();
3184 if (parseGetSpelling(formatString) ||
3185 parseToken(FIRToken::string,
"expected format string in printf"))
3188 SmallVector<Value, 4> specOperands;
3189 while (consumeIf(FIRToken::comma)) {
3190 specOperands.push_back({});
3191 if (parseExp(specOperands.back(),
"expected operand in printf"))
3196 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3197 parseOptionalName(name) || parseOptionalInfo())
3200 locationProcessor.setLoc(startTok.getLoc());
3202 StringAttr formatStrUnescaped;
3203 SmallVector<Value> operands;
3205 formatStrUnescaped, operands))
3208 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3214ParseResult FIRStmtParser::parseFPrintf() {
3217 auto startTok = consumeToken(FIRToken::lp_fprintf);
3219 Value clock, condition;
3220 StringRef outputFile, formatString;
3221 if (parseExp(clock,
"expected clock expression in fprintf") ||
3222 parseToken(FIRToken::comma,
"expected ','") ||
3223 parseExp(condition,
"expected condition in fprintf") ||
3224 parseToken(FIRToken::comma,
"expected ','"))
3227 auto outputFileLoc = getToken().getLoc();
3228 if (parseGetSpelling(outputFile) ||
3229 parseToken(FIRToken::string,
"expected output file in fprintf"))
3232 SmallVector<Value, 4> outputFileSpecOperands;
3233 while (consumeIf(FIRToken::comma)) {
3235 if (getToken().getKind() == FIRToken::string)
3237 outputFileSpecOperands.push_back({});
3238 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3242 auto formatStringLoc = getToken().getLoc();
3243 if (parseGetSpelling(formatString) ||
3244 parseToken(FIRToken::string,
"expected format string in printf"))
3247 SmallVector<Value, 4> specOperands;
3248 while (consumeIf(FIRToken::comma)) {
3249 specOperands.push_back({});
3250 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3255 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3256 parseOptionalName(name) || parseOptionalInfo())
3259 locationProcessor.setLoc(startTok.getLoc());
3261 StringAttr outputFileNameStrUnescaped;
3262 SmallVector<Value> outputFileOperands;
3264 outputFileNameStrUnescaped, outputFileOperands))
3267 StringAttr formatStrUnescaped;
3268 SmallVector<Value> operands;
3270 formatStrUnescaped, operands))
3273 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3274 outputFileOperands, formatStrUnescaped, operands, name);
3279ParseResult FIRStmtParser::parseFFlush() {
3283 auto startTok = consumeToken(FIRToken::lp_fflush);
3285 Value clock, condition;
3286 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3287 parseToken(FIRToken::comma,
"expected ','") ||
3288 parseExp(condition,
"expected condition in 'fflush'"))
3291 locationProcessor.setLoc(startTok.getLoc());
3292 StringAttr outputFileNameStrUnescaped;
3293 SmallVector<Value> outputFileOperands;
3295 if (consumeIf(FIRToken::comma)) {
3296 SmallVector<Value, 4> outputFileSpecOperands;
3297 auto outputFileLoc = getToken().getLoc();
3298 StringRef outputFile;
3299 if (parseGetSpelling(outputFile) ||
3300 parseToken(FIRToken::string,
"expected output file in fflush"))
3303 while (consumeIf(FIRToken::comma)) {
3304 outputFileSpecOperands.push_back({});
3305 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3310 outputFileNameStrUnescaped, outputFileOperands))
3314 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3315 parseOptionalInfo())
3318 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3319 outputFileOperands);
3324ParseResult FIRStmtParser::parseSkip() {
3325 auto startTok = consumeToken(FIRToken::kw_skip);
3329 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3332 if (parseOptionalInfo())
3335 locationProcessor.setLoc(startTok.getLoc());
3336 SkipOp::create(builder);
3341ParseResult FIRStmtParser::parseStop() {
3342 auto startTok = consumeToken(FIRToken::lp_stop);
3344 Value clock, condition;
3347 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3348 parseToken(FIRToken::comma,
"expected ','") ||
3349 parseExp(condition,
"expected condition in 'stop'") ||
3350 parseToken(FIRToken::comma,
"expected ','") ||
3351 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3352 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3353 parseOptionalName(name) || parseOptionalInfo())
3356 locationProcessor.setLoc(startTok.getLoc());
3357 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3363ParseResult FIRStmtParser::parseAssert() {
3364 auto startTok = consumeToken(FIRToken::lp_assert);
3366 Value clock, predicate, enable;
3367 StringRef formatString;
3369 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3370 parseToken(FIRToken::comma,
"expected ','") ||
3371 parseExp(predicate,
"expected predicate in 'assert'") ||
3372 parseToken(FIRToken::comma,
"expected ','") ||
3373 parseExp(enable,
"expected enable in 'assert'") ||
3374 parseToken(FIRToken::comma,
"expected ','") ||
3375 parseGetSpelling(formatString) ||
3376 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3379 SmallVector<Value, 4> operands;
3380 while (!consumeIf(FIRToken::r_paren)) {
3381 operands.push_back({});
3382 if (parseToken(FIRToken::comma,
"expected ','") ||
3383 parseExp(operands.back(),
"expected operand in 'assert'"))
3387 if (parseOptionalName(name) || parseOptionalInfo())
3390 locationProcessor.setLoc(startTok.getLoc());
3392 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3393 operands, name.getValue());
3398ParseResult FIRStmtParser::parseAssume() {
3399 auto startTok = consumeToken(FIRToken::lp_assume);
3401 Value clock, predicate, enable;
3402 StringRef formatString;
3404 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3405 parseToken(FIRToken::comma,
"expected ','") ||
3406 parseExp(predicate,
"expected predicate in 'assume'") ||
3407 parseToken(FIRToken::comma,
"expected ','") ||
3408 parseExp(enable,
"expected enable in 'assume'") ||
3409 parseToken(FIRToken::comma,
"expected ','") ||
3410 parseGetSpelling(formatString) ||
3411 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3414 SmallVector<Value, 4> operands;
3415 while (!consumeIf(FIRToken::r_paren)) {
3416 operands.push_back({});
3417 if (parseToken(FIRToken::comma,
"expected ','") ||
3418 parseExp(operands.back(),
"expected operand in 'assume'"))
3422 if (parseOptionalName(name) || parseOptionalInfo())
3425 locationProcessor.setLoc(startTok.getLoc());
3427 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3428 operands, name.getValue());
3433ParseResult FIRStmtParser::parseCover() {
3434 auto startTok = consumeToken(FIRToken::lp_cover);
3436 Value clock, predicate, enable;
3439 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3440 parseToken(FIRToken::comma,
"expected ','") ||
3441 parseExp(predicate,
"expected predicate in 'cover'") ||
3442 parseToken(FIRToken::comma,
"expected ','") ||
3443 parseExp(enable,
"expected enable in 'cover'") ||
3444 parseToken(FIRToken::comma,
"expected ','") ||
3445 parseGetSpelling(message) ||
3446 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3447 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3448 parseOptionalName(name) || parseOptionalInfo())
3451 locationProcessor.setLoc(startTok.getLoc());
3453 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3454 ValueRange{}, name.getValue());
3460ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3461 auto startTok = consumeToken(FIRToken::kw_when);
3465 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3469 if (parseExp(condition,
"expected condition in 'when'") ||
3470 parseToken(FIRToken::colon,
"expected ':' in when") ||
3471 parseOptionalInfo())
3474 locationProcessor.setLoc(startTok.getLoc());
3476 auto whenStmt = WhenOp::create(builder, condition,
false);
3479 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3483 if (getToken().isNot(FIRToken::kw_else))
3488 auto elseIndent = getIndentation();
3489 if (elseIndent && *elseIndent < whenIndent)
3492 consumeToken(FIRToken::kw_else);
3495 whenStmt.createElseRegion();
3501 if (getToken().is(FIRToken::kw_when)) {
3503 auto subParser = std::make_unique<FIRStmtParser>(
3504 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3507 return subParser->parseSimpleStmt(whenIndent);
3511 LocationAttr elseLoc;
3512 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3513 parseOptionalInfoLocator(elseLoc) ||
3514 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3523ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3524 auto startLoc = getToken().getLoc();
3525 locationProcessor.setLoc(startLoc);
3527 if (parseEnumType(type))
3531 auto enumType = type_dyn_cast<FEnumType>(type);
3533 return emitError(startLoc,
3534 "expected enumeration type in enumeration expression");
3537 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3538 parseId(tag,
"expected enumeration tag"))
3542 if (consumeIf(FIRToken::r_paren)) {
3545 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3546 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3547 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3548 input = ConstantOp::create(builder, type, attr);
3551 if (parseToken(FIRToken::comma,
"expected ','") ||
3552 parseExp(input,
"expected expression in enumeration value") ||
3553 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3557 value = FEnumCreateOp::create(builder, enumType, tag, input);
3565ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3566 auto startTok = consumeToken(FIRToken::kw_match);
3568 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3572 if (parseExp(input,
"expected expression in 'match'") ||
3573 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3574 parseOptionalInfo())
3577 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3579 return mlir::emitError(
3581 "expected enumeration type for 'match' statement, but got ")
3584 locationProcessor.setLoc(startTok.getLoc());
3586 SmallVector<Attribute> tags;
3587 SmallVector<std::unique_ptr<Region>> regions;
3589 auto tagLoc = getToken().getLoc();
3592 auto caseIndent = getIndentation();
3593 if (!caseIndent || *caseIndent <= matchIndent)
3597 StringRef tagSpelling;
3598 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3600 auto tagIndex = enumType.getElementIndex(tagSpelling);
3602 return emitError(tagLoc,
"tag ")
3603 << tagSpelling <<
" not a member of enumeration " << enumType;
3604 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3605 tags.push_back(tag);
3608 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3611 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3616 UnbundledValueRestorer x(moduleContext.unbundledValues);
3619 if (consumeIf(FIRToken::l_paren)) {
3620 StringAttr identifier;
3621 if (parseId(identifier,
"expected identifier for 'case' binding"))
3625 auto dataType = enumType.getElementType(*tagIndex);
3626 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3628 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3632 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3636 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3637 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3640 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3644 auto subParser = std::make_unique<FIRStmtParser>(
3645 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3647 if (subParser->parseSimpleStmtBlock(*caseIndent))
3651 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3658ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3659 auto loc = getToken().getLoc();
3662 if (parseId(
id,
"expected domain expression") ||
3663 moduleContext.lookupSymbolEntry(entry,
id, loc))
3666 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3668 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3669 parseFieldId(field,
"expected field name") ||
3670 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3674 if (parseOptionalExpPostscript(result,
false))
3677 auto type = result.getType();
3678 if (!type_isa<DomainType>(type))
3679 return emitError(loc) <<
"expected domain-type expression, got " << type;
3686ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3687 auto token = getToken().getKind();
3688 if (token == FIRToken::lp_probe)
3689 return parseProbe(result);
3690 if (token == FIRToken::lp_rwprobe)
3691 return parseRWProbe(result);
3696 return parseStaticRefExp(result, message);
3703ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3704 const Twine &message) {
3705 auto parseIdOrInstance = [&]() -> ParseResult {
3707 auto loc = getToken().getLoc();
3709 if (parseId(
id, message) ||
3710 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3714 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3717 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3720 StringRef fieldName;
3722 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3723 parseFieldId(fieldName,
"expected field name") ||
3724 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3726 return failure(parseIdOrInstance() ||
3727 parseOptionalExpPostscript(result,
false));
3738ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3740 const Twine &message) {
3741 auto loc = getToken().getLoc();
3745 if (parseId(
id, message) ||
3746 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3758 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3760 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3762 StringRef fieldName;
3763 auto loc = getToken().getLoc();
3764 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3765 parseFieldId(fieldName,
"expected field name"))
3770 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3771 for (
auto &elt : ubEntry) {
3772 if (elt.first == fieldAttr) {
3775 auto &instResult = elt.second;
3778 auto *defining = instResult.getDefiningOp();
3780 if (isa<WireOp>(defining)) {
3781 result = instResult;
3786 auto type = instResult.getType();
3790 bool forceable =
static_cast<bool>(
3793 return emitError(loc,
"unable to force instance result of type ")
3797 auto annotations = getConstants().emptyArrayAttr;
3798 StringAttr sym = {};
3799 SmallString<64> name;
3800 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3801 locationProcessor.setLoc(loc);
3802 OpBuilder::InsertionGuard guard(builder);
3803 builder.setInsertionPoint(defining);
3805 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3807 auto bounceVal = bounce.getData();
3810 instResult.replaceAllUsesWith(bounceVal);
3813 builder.setInsertionPointAfter(defining);
3814 if (
foldFlow(instResult) == Flow::Source)
3821 result = instResult = bounce.getDataRaw();
3827 emitError(loc,
"use of invalid field name '")
3828 << fieldName <<
"' on bundle value";
3833 result = cast<Value>(symtabEntry);
3837 assert(isa<BlockArgument>(result) ||
3838 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3844 type = result.getType();
3846 if (consumeIf(FIRToken::period)) {
3847 SmallVector<StringRef, 3> fields;
3848 if (parseFieldIdSeq(fields,
"expected field name"))
3850 for (
auto fieldName : fields) {
3851 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3852 if (
auto index = bundle.getElementIndex(fieldName)) {
3853 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3854 type = bundle.getElementTypePreservingConst(*index);
3857 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3858 if (
auto index = bundle.getElementIndex(fieldName)) {
3859 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3860 type = bundle.getElementTypePreservingConst(*index);
3864 return emitError(loc,
"subfield requires bundle operand")
3865 <<
"got " << type <<
"\n";
3867 return emitError(loc,
3868 "unknown field '" + fieldName +
"' in bundle type ")
3873 if (consumeIf(FIRToken::l_square)) {
3874 auto loc = getToken().
getLoc();
3876 if (parseIntLit(index,
"expected index") ||
3877 parseToken(FIRToken::r_square,
"expected ']'"))
3881 return emitError(loc,
"invalid index specifier");
3883 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3884 if ((
unsigned)index < vector.getNumElements()) {
3885 refResult = refResult.
getSubField(vector.getFieldID(index));
3886 type = vector.getElementTypePreservingConst();
3889 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3890 if ((
unsigned)index < vector.getNumElements()) {
3891 refResult = refResult.
getSubField(vector.getFieldID(index));
3892 type = vector.getElementTypePreservingConst();
3896 return emitError(loc,
"subindex requires vector operand");
3898 return emitError(loc,
"out of range index '")
3899 << index <<
"' for vector type " << type;
3907ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3908 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3909 StringRef intrinsic;
3910 ArrayAttr parameters;
3913 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3914 parseOptionalParams(parameters))
3917 if (consumeIf(FIRToken::colon)) {
3918 if (
parseType(type,
"expected intrinsic return type"))
3920 }
else if (!isStatement)
3921 return emitError(
"expected ':' in intrinsic expression");
3923 SmallVector<Value> operands;
3924 auto loc = startTok.getLoc();
3925 if (consumeIf(FIRToken::comma)) {
3926 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3928 if (parseExp(operand,
"expected operand in intrinsic"))
3930 operands.push_back(operand);
3931 locationProcessor.setLoc(loc);
3936 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3941 if (parseOptionalInfo())
3944 locationProcessor.setLoc(loc);
3946 auto op = GenericIntrinsicOp::create(
3947 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
3949 result = op.getResult();
3954ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3955 if (!consumeIf(FIRToken::less))
3958 SmallVector<Attribute, 8> parameters;
3959 SmallPtrSet<StringAttr, 8> seen;
3960 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3964 if (parseParameter(name, value, loc))
3966 auto typedValue = dyn_cast<TypedAttr>(value);
3968 return emitError(loc)
3969 <<
"invalid value for parameter '" << name.getValue() <<
"'";
3970 if (!seen.insert(name).second)
3971 return emitError(loc,
"redefinition of parameter '" +
3972 name.getValue() +
"'");
3973 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3978 resultParameters = ArrayAttr::get(getContext(), parameters);
3984ParseResult FIRStmtParser::parsePathExp(Value &result) {
3985 auto startTok = consumeToken(FIRToken::lp_path);
3986 locationProcessor.setLoc(startTok.getLoc());
3988 if (parseGetSpelling(target) ||
3989 parseToken(FIRToken::string,
3990 "expected target string in path expression") ||
3991 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
3993 result = UnresolvedPathOp::create(
3999ParseResult FIRStmtParser::parseDomainDefine() {
4000 auto startTok = consumeToken(FIRToken::kw_domain_define);
4001 auto startLoc = startTok.getLoc();
4002 locationProcessor.setLoc(startLoc);
4006 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4007 parseDomainExp(src) || parseOptionalInfo())
4015ParseResult FIRStmtParser::parseRefDefine() {
4016 auto startTok = consumeToken(FIRToken::kw_define);
4019 if (parseStaticRefExp(target,
4020 "expected static reference expression in 'define'") ||
4021 parseToken(FIRToken::equal,
4022 "expected '=' after define reference expression") ||
4023 parseRefExp(src,
"expected reference expression in 'define'") ||
4024 parseOptionalInfo())
4028 if (!type_isa<RefType>(target.getType()))
4029 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4030 "'define' target (LHS), got ")
4031 << target.getType();
4032 if (!type_isa<RefType>(src.getType()))
4033 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4034 "'define' source (RHS), got ")
4039 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4040 return emitError(startTok.getLoc(),
4041 "cannot define into a sub-element of a reference");
4043 locationProcessor.setLoc(startTok.getLoc());
4046 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4047 << target.getType() <<
" with incompatible reference of type "
4057ParseResult FIRStmtParser::parseRefRead(Value &result) {
4058 auto startTok = consumeToken(FIRToken::lp_read);
4061 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4062 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4065 locationProcessor.setLoc(startTok.getLoc());
4068 if (!type_isa<RefType>(ref.getType()))
4069 return emitError(startTok.getLoc(),
4070 "expected reference-type expression in 'read', got ")
4073 result = RefResolveOp::create(builder, ref);
4079ParseResult FIRStmtParser::parseProbe(Value &result) {
4080 auto startTok = consumeToken(FIRToken::lp_probe);
4083 if (parseStaticRefExp(staticRef,
4084 "expected static reference expression in 'probe'") ||
4085 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4088 locationProcessor.setLoc(startTok.getLoc());
4091 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4092 return emitError(startTok.getLoc(),
4093 "expected base-type expression in 'probe', got ")
4094 << staticRef.getType();
4098 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4099 MemoryDebugPortOp, MemoryPortAccessOp>(
4100 staticRef.getDefiningOp()))
4101 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4103 result = RefSendOp::create(builder, staticRef);
4109ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4110 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4113 Type parsedTargetType;
4114 if (parseRWProbeStaticRefExp(
4115 staticRef, parsedTargetType,
4116 "expected static reference expression in 'rwprobe'") ||
4117 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4120 locationProcessor.setLoc(startTok.getLoc());
4126 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4128 return emitError(startTok.getLoc(),
4129 "expected base-type expression in 'rwprobe', got ")
4130 << parsedTargetType;
4133 auto *definingOp = root.getDefiningOp();
4135 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4136 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4137 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4141 return emitError(startTok.getLoc(),
"cannot force target of type ")
4145 auto op = RWProbeOp::create(builder, forceableType,
4146 getConstants().placeholderInnerRef);
4153ParseResult FIRStmtParser::parseRefForce() {
4154 auto startTok = consumeToken(FIRToken::lp_force);
4156 Value clock, pred, dest, src;
4157 if (parseExp(clock,
"expected clock expression in force") ||
4158 parseToken(FIRToken::comma,
"expected ','") ||
4159 parseExp(pred,
"expected predicate expression in force") ||
4160 parseToken(FIRToken::comma,
"expected ','") ||
4161 parseRefExp(dest,
"expected destination reference expression in force") ||
4162 parseToken(FIRToken::comma,
"expected ','") ||
4163 parseExp(src,
"expected source expression in force") ||
4164 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4165 parseOptionalInfo())
4169 auto ref = type_dyn_cast<RefType>(dest.getType());
4170 if (!ref || !ref.getForceable())
4173 "expected rwprobe-type expression for force destination, got ")
4175 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4177 return emitError(startTok.getLoc(),
4178 "expected base-type for force source, got ")
4180 if (!srcBaseType.isPassive())
4181 return emitError(startTok.getLoc(),
4182 "expected passive value for force source, got ")
4185 locationProcessor.setLoc(startTok.getLoc());
4188 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4189 if (noConstSrcType != ref.getType()) {
4191 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4193 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4195 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4196 << src.getType() <<
" cannot target destination "
4200 RefForceOp::create(builder, clock, pred, dest, src);
4206ParseResult FIRStmtParser::parseRefForceInitial() {
4207 auto startTok = consumeToken(FIRToken::lp_force_initial);
4211 dest,
"expected destination reference expression in force_initial") ||
4212 parseToken(FIRToken::comma,
"expected ','") ||
4213 parseExp(src,
"expected source expression in force_initial") ||
4214 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4215 parseOptionalInfo())
4219 auto ref = type_dyn_cast<RefType>(dest.getType());
4220 if (!ref || !ref.getForceable())
4221 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4222 "force_initial destination, got ")
4224 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4226 return emitError(startTok.getLoc(),
4227 "expected base-type expression for force_initial "
4230 if (!srcBaseType.isPassive())
4231 return emitError(startTok.getLoc(),
4232 "expected passive value for force_initial source, got ")
4235 locationProcessor.setLoc(startTok.getLoc());
4238 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4239 if (noConstSrcType != ref.getType()) {
4241 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4243 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4245 return emitError(startTok.getLoc(),
4246 "incompatible force_initial source of type ")
4247 << src.getType() <<
" cannot target destination "
4251 auto value = APInt::getAllOnes(1);
4252 auto type = UIntType::get(builder.getContext(), 1);
4253 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4254 value.getBitWidth(),
4255 IntegerType::Unsigned),
4257 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4258 RefForceInitialOp::create(builder, pred, dest, src);
4264ParseResult FIRStmtParser::parseRefRelease() {
4265 auto startTok = consumeToken(FIRToken::lp_release);
4267 Value clock, pred, dest;
4268 if (parseExp(clock,
"expected clock expression in release") ||
4269 parseToken(FIRToken::comma,
"expected ','") ||
4270 parseExp(pred,
"expected predicate expression in release") ||
4271 parseToken(FIRToken::comma,
"expected ','") ||
4273 "expected destination reference expression in release") ||
4274 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4275 parseOptionalInfo())
4279 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4280 !ref || !ref.getForceable())
4283 "expected rwprobe-type expression for release destination, got ")
4286 locationProcessor.setLoc(startTok.getLoc());
4288 RefReleaseOp::create(builder, clock, pred, dest);
4294ParseResult FIRStmtParser::parseRefReleaseInitial() {
4295 auto startTok = consumeToken(FIRToken::lp_release_initial);
4300 "expected destination reference expression in release_initial") ||
4301 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4302 parseOptionalInfo())
4306 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4307 !ref || !ref.getForceable())
4308 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4309 "release_initial destination, got ")
4312 locationProcessor.setLoc(startTok.getLoc());
4314 auto value = APInt::getAllOnes(1);
4315 auto type = UIntType::get(builder.getContext(), 1);
4316 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4317 value.getBitWidth(),
4318 IntegerType::Unsigned),
4320 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4321 RefReleaseInitialOp::create(builder, pred, dest);
4327ParseResult FIRStmtParser::parseConnect() {
4328 auto startTok = consumeToken(FIRToken::kw_connect);
4329 auto loc = startTok.getLoc();
4332 if (parseExp(lhs,
"expected connect expression") ||
4333 parseToken(FIRToken::comma,
"expected ','") ||
4334 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4337 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4338 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4339 if (!lhsType || !rhsType)
4340 return emitError(loc,
"cannot connect reference or property types");
4342 if (lhsType.containsReference() || rhsType.containsReference())
4343 return emitError(loc,
"cannot connect types containing references");
4346 return emitError(loc,
"cannot connect non-equivalent type ")
4347 << rhsType <<
" to " << lhsType;
4349 locationProcessor.setLoc(loc);
4355ParseResult FIRStmtParser::parsePropAssign() {
4356 auto startTok = consumeToken(FIRToken::kw_propassign);
4357 auto loc = startTok.getLoc();
4360 if (parseExp(lhs,
"expected propassign expression") ||
4361 parseToken(FIRToken::comma,
"expected ','") ||
4362 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4365 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4366 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4367 if (!lhsType || !rhsType)
4368 return emitError(loc,
"can only propassign property types");
4369 locationProcessor.setLoc(loc);
4370 if (lhsType != rhsType) {
4372 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4373 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4375 return emitError(loc,
"cannot propassign non-equivalent type ")
4376 << rhsType <<
" to " << lhsType;
4378 PropAssignOp::create(builder, lhs, rhs);
4383ParseResult FIRStmtParser::parseInvalidate() {
4384 auto startTok = consumeToken(FIRToken::kw_invalidate);
4389 auto loc = getToken().getLoc();
4391 if (parseId(
id,
"expected static reference expression") ||
4392 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4397 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4398 if (parseOptionalExpPostscript(lhs,
false) ||
4399 parseOptionalInfo())
4402 locationProcessor.setLoc(startTok.getLoc());
4403 emitInvalidate(lhs);
4410 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4412 if (getToken().isNot(FIRToken::period)) {
4413 locationProcessor.setLoc(loc);
4415 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4417 for (
auto elt : ubEntry)
4418 emitInvalidate(elt.second);
4424 StringRef fieldName;
4425 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4426 parseFieldId(fieldName,
"expected field name") ||
4427 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4431 if (parseOptionalExpPostscript(lhs,
false) ||
4432 parseOptionalInfo())
4435 locationProcessor.setLoc(startTok.getLoc());
4436 emitInvalidate(lhs);
4440ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4442 auto startTok = consumeToken();
4443 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4444 "consumed an unexpected token");
4445 auto loc = startTok.getLoc();
4448 if (parseId(
id,
"expected layer identifer") ||
4449 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4450 parseOptionalInfo())
4453 locationProcessor.setLoc(loc);
4455 StringRef rootLayer;
4456 SmallVector<FlatSymbolRefAttr> nestedLayers;
4460 rootLayer = layerSym.getRootReference();
4461 auto nestedRefs = layerSym.getNestedReferences();
4462 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4463 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4466 auto layerBlockOp = LayerBlockOp::create(
4468 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4469 layerBlockOp->getRegion(0).push_back(
new Block());
4471 if (getIndentation() > indent)
4472 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4473 layerBlockOp.getLayerName()))
4481ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4482 auto loc = getToken().getLoc();
4485 if (consumeIf(FIRToken::kw_is)) {
4486 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4487 parseOptionalInfo())
4490 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4493 locationProcessor.setLoc(loc);
4494 emitInvalidate(lhs);
4498 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4501 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4505 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4508 locationProcessor.setLoc(loc);
4510 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4511 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4512 if (!lhsType || !rhsType)
4513 return emitError(loc,
"cannot connect reference or property types");
4515 if (lhsType.containsReference() || rhsType.containsReference())
4516 return emitError(loc,
"cannot connect types containing references");
4519 return emitError(loc,
"cannot connect non-equivalent type ")
4520 << rhsType <<
" to " << lhsType;
4529ParseResult FIRStmtParser::parseInstance() {
4530 auto startTok = consumeToken(FIRToken::kw_inst);
4534 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4538 StringRef moduleName;
4539 if (parseId(
id,
"expected instance name") ||
4540 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4541 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4544 locationProcessor.setLoc(startTok.getLoc());
4547 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4548 if (!referencedModule)
4551 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4553 auto annotations = getConstants().emptyArrayAttr;
4554 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4556 hw::InnerSymAttr sym = {};
4557 auto result = InstanceOp::create(
4558 builder, referencedModule,
id, NameKindEnum::InterestingName,
4559 annotations.getValue(), portAnnotations,
false,
false, sym);
4565 unbundledValueEntry.reserve(modulePorts.size());
4566 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4567 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4571 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4572 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4573 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4578ParseResult FIRStmtParser::parseInstanceChoice() {
4579 auto startTok = consumeToken(FIRToken::kw_instchoice);
4580 SMLoc loc = startTok.getLoc();
4583 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4590 StringRef defaultModuleName;
4591 StringRef optionGroupName;
4592 if (parseId(
id,
"expected instance name") ||
4593 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4594 parseId(defaultModuleName,
"expected module name") ||
4595 parseToken(FIRToken::comma,
"expected ','") ||
4596 parseId(optionGroupName,
"expected option group name") ||
4597 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4598 parseOptionalInfo())
4601 locationProcessor.setLoc(startTok.getLoc());
4605 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4609 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4612 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4614 return emitError(loc,
4615 "use of undefined option group '" + optionGroupName +
"'");
4617 auto baseIndent = getIndentation();
4618 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4619 while (getIndentation() == baseIndent) {
4621 StringRef caseModuleName;
4622 if (parseId(caseId,
"expected a case identifier") ||
4623 parseToken(FIRToken::equal_greater,
4624 "expected '=> in instance choice definition") ||
4625 parseId(caseModuleName,
"expected module name"))
4628 auto caseModule = getReferencedModule(loc, caseModuleName);
4632 for (
const auto &[defaultPort, casePort] :
4633 llvm::zip(modulePorts, caseModule.getPorts())) {
4634 if (defaultPort.name != casePort.name)
4635 return emitError(loc,
"instance case module port '")
4636 << casePort.name.getValue()
4637 <<
"' does not match the default module port '"
4638 << defaultPort.name.getValue() <<
"'";
4639 if (defaultPort.type != casePort.type)
4640 return emitError(loc,
"instance case port '")
4641 << casePort.name.getValue()
4642 <<
"' type does not match the default module port";
4646 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4648 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4649 caseModules.emplace_back(optionCase, caseModule);
4652 auto annotations = getConstants().emptyArrayAttr;
4653 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4657 auto result = InstanceChoiceOp::create(
4658 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4659 annotations.getValue(), portAnnotations, sym);
4663 unbundledValueEntry.reserve(modulePorts.size());
4664 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4665 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4667 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4668 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4669 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4672FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4673 StringRef moduleName) {
4674 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4675 if (!referencedModule) {
4677 "use of undefined module name '" + moduleName +
"' in instance");
4680 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4681 emitError(loc,
"cannot create instance of class '" + moduleName +
4682 "', did you mean object?");
4685 return referencedModule;
4689ParseResult FIRStmtParser::parseObject() {
4690 auto startTok = consumeToken(FIRToken::kw_object);
4694 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4701 StringRef className;
4702 if (parseId(
id,
"expected object name") ||
4703 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4704 parseId(className,
"expected class name") || parseOptionalInfo())
4707 locationProcessor.setLoc(startTok.getLoc());
4710 const auto &classMap = getConstants().classMap;
4711 auto lookup = classMap.find(className);
4712 if (lookup == classMap.end())
4713 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4714 className +
"' in object");
4715 auto referencedClass = lookup->getSecond();
4716 auto result = ObjectOp::create(builder, referencedClass,
id);
4717 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4721ParseResult FIRStmtParser::parseCombMem() {
4723 auto startTok = consumeToken(FIRToken::kw_cmem);
4727 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4732 if (parseId(
id,
"expected cmem name") ||
4733 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4734 parseType(type,
"expected cmem type") || parseOptionalInfo())
4737 locationProcessor.setLoc(startTok.getLoc());
4740 auto vectorType = type_dyn_cast<FVectorType>(type);
4742 return emitError(
"cmem requires vector type");
4744 auto annotations = getConstants().emptyArrayAttr;
4745 StringAttr sym = {};
4746 auto result = CombMemOp::create(
4747 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4748 NameKindEnum::InterestingName, annotations, sym);
4749 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4753ParseResult FIRStmtParser::parseSeqMem() {
4755 auto startTok = consumeToken(FIRToken::kw_smem);
4759 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4764 RUWBehavior ruw = RUWBehavior::Undefined;
4766 if (parseId(
id,
"expected smem name") ||
4767 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4771 if (consumeIf(FIRToken::comma)) {
4776 if (parseOptionalInfo()) {
4780 locationProcessor.setLoc(startTok.getLoc());
4783 auto vectorType = type_dyn_cast<FVectorType>(type);
4785 return emitError(
"smem requires vector type");
4787 auto annotations = getConstants().emptyArrayAttr;
4788 StringAttr sym = {};
4789 auto result = SeqMemOp::create(
4790 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4791 id, NameKindEnum::InterestingName, annotations, sym);
4792 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4804ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4805 auto startTok = consumeToken(FIRToken::kw_mem);
4809 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4813 if (parseId(
id,
"expected mem name") ||
4814 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4818 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4819 RUWBehavior ruw = RUWBehavior::Undefined;
4821 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4825 auto nextIndent = getIndentation();
4826 if (!nextIndent || *nextIndent <= memIndent)
4829 auto spelling = getTokenSpelling();
4830 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4831 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4834 if (spelling ==
"data-type") {
4836 return emitError(
"'mem' type specified multiple times"), failure();
4838 if (
parseType(type,
"expected type in data-type declaration"))
4842 if (spelling ==
"depth") {
4843 if (parseIntLit(depth,
"expected integer in depth specification"))
4847 if (spelling ==
"read-latency") {
4848 if (parseIntLit(readLatency,
"expected integer latency"))
4852 if (spelling ==
"write-latency") {
4853 if (parseIntLit(writeLatency,
"expected integer latency"))
4857 if (spelling ==
"read-under-write") {
4858 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4859 FIRToken::kw_undefined))
4860 return emitError(
"expected specifier"), failure();
4862 if (parseOptionalRUW(ruw))
4867 MemOp::PortKind portKind;
4868 if (spelling ==
"reader")
4869 portKind = MemOp::PortKind::Read;
4870 else if (spelling ==
"writer")
4871 portKind = MemOp::PortKind::Write;
4872 else if (spelling ==
"readwriter")
4873 portKind = MemOp::PortKind::ReadWrite;
4875 return emitError(
"unexpected field in 'mem' declaration"), failure();
4878 if (parseId(portName,
"expected port name"))
4880 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4882 return emitError(
"unexpected type, must be base type");
4883 ports.push_back({builder.getStringAttr(portName),
4884 MemOp::getTypeForPort(depth, baseType, portKind)});
4886 while (!getIndentation().has_value()) {
4887 if (parseId(portName,
"expected port name"))
4889 ports.push_back({builder.getStringAttr(portName),
4890 MemOp::getTypeForPort(depth, baseType, portKind)});
4901 llvm::array_pod_sort(ports.begin(), ports.end(),
4902 [](
const std::pair<StringAttr, Type> *lhs,
4903 const std::pair<StringAttr, Type> *rhs) ->
int {
4904 return lhs->first.getValue().compare(
4905 rhs->first.getValue());
4908 auto annotations = getConstants().emptyArrayAttr;
4909 SmallVector<Attribute, 4> resultNames;
4910 SmallVector<Type, 4> resultTypes;
4911 SmallVector<Attribute, 4> resultAnnotations;
4912 for (
auto p : ports) {
4913 resultNames.push_back(p.first);
4914 resultTypes.push_back(p.second);
4915 resultAnnotations.push_back(annotations);
4918 locationProcessor.setLoc(startTok.getLoc());
4920 auto result = MemOp::create(
4921 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4922 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
4923 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4924 MemoryInitAttr(), StringAttr());
4927 unbundledValueEntry.reserve(result.getNumResults());
4928 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4929 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4931 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4932 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4933 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4937ParseResult FIRStmtParser::parseNode() {
4938 auto startTok = consumeToken(FIRToken::kw_node);
4942 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4947 if (parseId(
id,
"expected node name") ||
4948 parseToken(FIRToken::equal,
"expected '=' in node") ||
4949 parseExp(initializer,
"expected expression for node") ||
4950 parseOptionalInfo())
4953 locationProcessor.setLoc(startTok.getLoc());
4965 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4966 auto initializerBaseType =
4967 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4968 if (type_isa<AnalogType>(initializerType) ||
4969 !(initializerBaseType && initializerBaseType.isPassive())) {
4970 emitError(startTok.getLoc())
4971 <<
"Node cannot be analog and must be passive or passive under a flip "
4972 << initializer.getType();
4976 auto annotations = getConstants().emptyArrayAttr;
4977 StringAttr sym = {};
4979 auto result = NodeOp::create(builder, initializer,
id,
4980 NameKindEnum::InterestingName, annotations, sym);
4981 return moduleContext.addSymbolEntry(
id, result.getResult(),
4986ParseResult FIRStmtParser::parseWire() {
4987 auto startTok = consumeToken(FIRToken::kw_wire);
4991 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4996 if (parseId(
id,
"expected wire name") ||
4997 parseToken(FIRToken::colon,
"expected ':' in wire") ||
4998 parseType(type,
"expected wire type") || parseOptionalInfo())
5001 locationProcessor.setLoc(startTok.getLoc());
5003 auto annotations = getConstants().emptyArrayAttr;
5004 StringAttr sym = {};
5007 auto namekind = isa<PropertyType, RefType>(type)
5008 ? NameKindEnum::DroppableName
5009 : NameKindEnum::InterestingName;
5011 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
5012 return moduleContext.addSymbolEntry(
id, result.getResult(),
5026ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5027 auto startTok = consumeToken(FIRToken::kw_reg);
5031 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5040 if (parseId(
id,
"expected reg name") ||
5041 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5043 parseToken(FIRToken::comma,
"expected ','") ||
5044 parseExp(clock,
"expected expression for register clock"))
5047 if (!type_isa<FIRRTLBaseType>(type))
5048 return emitError(startTok.getLoc(),
"register must have base type");
5051 Value resetSignal, resetValue;
5052 if (consumeIf(FIRToken::kw_with)) {
5053 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5056 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5064 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5066 auto indent = getIndentation();
5067 if (!indent || *indent <= regIndent)
5068 if (!hasExtraLParen)
5069 return emitError(
"expected indented reset specifier in reg"), failure();
5071 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5072 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5073 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5074 parseExp(resetSignal,
"expected expression for reset signal") ||
5075 parseToken(FIRToken::comma,
"expected ','"))
5083 if (getTokenSpelling() ==
id) {
5085 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5087 resetSignal = Value();
5089 if (parseExp(resetValue,
"expected expression for reset value") ||
5090 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5094 if (hasExtraLParen &&
5095 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5101 if (parseOptionalInfo())
5104 locationProcessor.setLoc(startTok.getLoc());
5106 ArrayAttr annotations = getConstants().emptyArrayAttr;
5108 StringAttr sym = {};
5111 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5112 NameKindEnum::InterestingName, annotations, sym)
5115 result = RegOp::create(builder, type, clock,
id,
5116 NameKindEnum::InterestingName, annotations, sym)
5118 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5126ParseResult FIRStmtParser::parseRegisterWithReset() {
5127 auto startTok = consumeToken(FIRToken::kw_regreset);
5131 Value clock, resetSignal, resetValue;
5133 if (parseId(
id,
"expected reg name") ||
5134 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5136 parseToken(FIRToken::comma,
"expected ','") ||
5137 parseExp(clock,
"expected expression for register clock") ||
5138 parseToken(FIRToken::comma,
"expected ','") ||
5139 parseExp(resetSignal,
"expected expression for register reset") ||
5140 parseToken(FIRToken::comma,
"expected ','") ||
5141 parseExp(resetValue,
"expected expression for register reset value") ||
5142 parseOptionalInfo())
5145 if (!type_isa<FIRRTLBaseType>(type))
5146 return emitError(startTok.getLoc(),
"register must have base type");
5148 locationProcessor.setLoc(startTok.getLoc());
5151 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5152 NameKindEnum::InterestingName,
5153 getConstants().emptyArrayAttr, StringAttr{})
5156 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5161ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5165 auto startTok = consumeToken(FIRToken::kw_contract);
5168 SmallVector<StringRef> ids;
5169 SmallVector<SMLoc> locs;
5170 SmallVector<Value> values;
5171 SmallVector<Type> types;
5172 if (!consumeIf(FIRToken::colon)) {
5173 auto parseContractId = [&] {
5175 locs.push_back(getToken().
getLoc());
5176 if (parseId(
id,
"expected contract result name"))
5181 auto parseContractValue = [&] {
5183 if (parseExp(value,
"expected expression for contract result"))
5185 values.push_back(value);
5186 types.push_back(value.getType());
5189 if (parseListUntil(FIRToken::equal, parseContractId) ||
5190 parseListUntil(FIRToken::colon, parseContractValue))
5193 if (parseOptionalInfo())
5197 if (ids.size() != values.size())
5198 return emitError(startTok.getLoc())
5199 <<
"contract requires same number of results and expressions; got "
5200 << ids.size() <<
" results and " << values.size()
5201 <<
" expressions instead";
5203 locationProcessor.setLoc(startTok.getLoc());
5207 auto contract = ContractOp::create(builder, types, values);
5208 auto &block = contract.getBody().emplaceBlock();
5212 FIRModuleContext::ContextScope scope(moduleContext, &block);
5213 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5214 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5215 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5218 if (getIndentation() > blockIndent)
5219 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5224 for (
auto [
id, loc, value, result] :
5225 llvm::zip(ids, locs, values, contract.getResults())) {
5227 moduleContext.removeSymbolEntry(
id);
5228 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5241struct FIRCircuitParser :
public FIRParser {
5242 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5244 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5247 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5248 mlir::TimingScope &ts);
5253 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5254 SmallVectorImpl<Attribute> &attrs);
5256 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5258 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5259 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5260 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5261 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5262 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5263 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5264 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5265 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5267 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5269 ParseResult parseLayerName(SymbolRefAttr &result);
5270 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5271 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5272 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5273 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5274 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5275 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5276 ArrayAttr &knownLayers,
5277 ArrayAttr &externalRequirements);
5279 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5280 SmallVectorImpl<SMLoc> &resultPortLocs,
5284 ParseResult skipToModuleEnd(
unsigned indent);
5286 ParseResult parseTypeDecl();
5288 ParseResult parseOptionDecl(CircuitOp circuit);
5290 ParseResult parseLayer(CircuitOp circuit);
5292 ParseResult resolveDomains(
5293 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5294 const DenseMap<Attribute, size_t> &nameToIndex,
5295 SmallVectorImpl<Attribute> &domainsByIndex);
5298 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5299 const DenseMap<Attribute, size_t> &nameToIndex);
5301 struct DeferredModuleToParse {
5302 FModuleLike moduleOp;
5303 SmallVector<SMLoc> portLocs;
5308 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5309 DeferredModuleToParse &deferredModule,
5310 InnerSymFixups &fixups);
5312 SmallVector<DeferredModuleToParse, 0> deferredModules;
5314 SmallVector<InnerSymFixups, 0> moduleFixups;
5318 ModuleOp mlirModule;
5323FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5324 SmallVectorImpl<Attribute> &attrs) {
5326 auto annotations = json::parse(annotationsStr);
5327 if (
auto err = annotations.takeError()) {
5328 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5329 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5330 diag.attachNote() << a.message();
5335 json::Path::Root root;
5336 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5339 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5340 std::string jsonErrorMessage =
5341 "See inline comments for problem area in JSON:\n";
5342 llvm::raw_string_ostream s(jsonErrorMessage);
5343 root.printErrorContext(annotations.get(), s);
5344 diag.attachNote() << jsonErrorMessage;
5351ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5353 SmallVector<StringRef> strings;
5356 if (parseId(name,
"expected layer name"))
5358 strings.push_back(name);
5359 }
while (consumeIf(FIRToken::period));
5361 SmallVector<FlatSymbolRefAttr> nested;
5362 nested.reserve(strings.size() - 1);
5363 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5364 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5366 result = SymbolRefAttr::get(
context, strings[0], nested);
5370ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5371 SmallVector<Attribute> enabledLayersBuffer;
5373 auto tokenKind = getToken().getKind();
5375 if (tokenKind == FIRToken::kw_enablelayer) {
5376 if (parseEnableLayerSpec(enabledLayersBuffer))
5384 if (enabledLayersBuffer.size() != 0)
5385 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5388 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5392ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5393 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5394 ArrayAttr &externalRequirements) {
5395 SmallVector<Attribute> enabledLayersBuffer;
5396 SmallVector<Attribute> knownLayersBuffer;
5397 SmallVector<Attribute> requirementsBuffer;
5399 auto tokenKind = getToken().getKind();
5401 if (tokenKind == FIRToken::kw_enablelayer) {
5402 if (parseEnableLayerSpec(enabledLayersBuffer))
5407 if (tokenKind == FIRToken::kw_knownlayer) {
5408 if (parseKnownLayerSpec(knownLayersBuffer))
5413 if (tokenKind == FIRToken::kw_requires) {
5414 if (parseRequiresSpec(requirementsBuffer))
5422 if (enabledLayersBuffer.size() != 0)
5423 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5426 if (knownLayersBuffer.size() != 0)
5427 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5430 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5431 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5432 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5437FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5439 SymbolRefAttr layer;
5440 if (parseLayerName(layer))
5442 result.push_back(layer);
5443 }
while (consumeIf(FIRToken::comma));
5448FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5449 consumeToken(FIRToken::kw_enablelayer);
5450 return parseLayerList(result);
5454FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5455 consumeToken(FIRToken::kw_knownlayer);
5456 return parseLayerList(result);
5460FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5461 consumeToken(FIRToken::kw_requires);
5463 StringRef requireStr;
5464 if (parseGetSpelling(requireStr) ||
5465 parseToken(FIRToken::string,
"expected string after 'requires'"))
5469 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5470 }
while (consumeIf(FIRToken::comma));
5478FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5479 SmallVectorImpl<SMLoc> &resultPortLocs,
5485 DenseMap<Attribute, size_t> nameToIndex;
5486 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5489 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5491 getIndentation() > indent) {
5497 auto backtrackState = getLexer().getCursor();
5499 bool isOutput = getToken().is(FIRToken::kw_output);
5504 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5505 !getToken().isKeyword()) {
5506 backtrackState.restore(getLexer());
5513 if (parseId(name,
"expected port name") ||
5514 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5515 parseType(type,
"expected a type in port declaration"))
5517 Attribute domainInfoElement = {};
5518 size_t portIdx = resultPorts.size();
5519 if (isa<DomainType>(type)) {
5520 StringAttr domainKind;
5521 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type port") ||
5522 parseId(domainKind,
"expected domain kind"))
5524 domainInfoElement = FlatSymbolRefAttr::get(domainKind);
5526 if (getToken().is(FIRToken::kw_domains))
5527 if (parseDomains(domainNames[portIdx], nameToIndex))
5531 if (
info.parseOptionalInfo())
5534 StringAttr innerSym = {};
5535 resultPorts.push_back(
PortInfo{name,
5541 domainInfoElement});
5542 resultPortLocs.push_back(
info.getFIRLoc());
5543 nameToIndex.insert({name, portIdx});
5547 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5548 auto &port = resultPorts[portIdx];
5549 Attribute &attr = port.domains;
5553 SmallVector<Attribute> domainInfo;
5554 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5556 attr = ArrayAttr::get(getContext(), domainInfo);
5561 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5562 PortInfo &port = std::get<0>(portAndLoc);
5563 auto &entry = portIds[port.
name];
5564 if (!entry.isValid()) {
5565 entry = std::get<1>(portAndLoc);
5569 emitError(std::get<1>(portAndLoc),
5570 "redefinition of name '" + port.
getName() +
"'")
5571 .attachNote(translateLocation(entry))
5572 <<
"previous definition here";
5581ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5583 switch (getToken().getKind()) {
5587 case FIRToken::error:
5591 case FIRToken::kw_class:
5592 case FIRToken::kw_domain:
5593 case FIRToken::kw_declgroup:
5594 case FIRToken::kw_extclass:
5595 case FIRToken::kw_extmodule:
5596 case FIRToken::kw_intmodule:
5597 case FIRToken::kw_formal:
5598 case FIRToken::kw_module:
5599 case FIRToken::kw_public:
5600 case FIRToken::kw_layer:
5601 case FIRToken::kw_option:
5602 case FIRToken::kw_simulation:
5603 case FIRToken::kw_type:
5607 if (getIndentation() == indent)
5619ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5620 SmallVector<Attribute, 8> parameters;
5621 SmallPtrSet<StringAttr, 8> seen;
5622 while (consumeIf(FIRToken::kw_parameter)) {
5626 if (parseParameter(name, value, loc))
5628 auto typedValue = dyn_cast<TypedAttr>(value);
5630 return emitError(loc)
5631 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5632 if (!seen.insert(name).second)
5633 return emitError(loc,
5634 "redefinition of parameter '" + name.getValue() +
"'");
5635 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5637 resultParameters = ArrayAttr::get(getContext(), parameters);
5642ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5644 SmallVector<PortInfo, 8> portList;
5645 SmallVector<SMLoc> portLocs;
5651 consumeToken(FIRToken::kw_class);
5652 if (parseId(name,
"expected class name") ||
5653 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5657 if (name == circuit.getName())
5658 return mlir::emitError(
info.getLoc(),
5659 "class cannot be the top of a circuit");
5661 for (
auto &portInfo : portList)
5663 return
mlir::emitError(portInfo.loc,
5664 "ports on classes must be properties");
5667 auto builder = circuit.getBodyBuilder();
5668 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5669 classOp.setPrivate();
5670 deferredModules.emplace_back(
5671 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5674 getConstants().classMap[name.getValue()] = classOp;
5675 return skipToModuleEnd(indent);
5679ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5680 consumeToken(FIRToken::kw_domain);
5684 if (parseId(name,
"domain name") ||
5685 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5686 info.parseOptionalInfo())
5689 SmallVector<Attribute> fields;
5691 auto nextIndent = getIndentation();
5692 if (!nextIndent || *nextIndent <= indent)
5695 StringAttr fieldName;
5697 if (parseId(fieldName,
"field name") ||
5698 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5699 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5703 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5706 auto builder = circuit.getBodyBuilder();
5707 DomainOp::create(builder,
info.getLoc(), name, builder.getArrayAttr(fields));
5713ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5716 SmallVector<PortInfo, 8> portList;
5717 SmallVector<SMLoc> portLocs;
5723 consumeToken(FIRToken::kw_extclass);
5724 if (parseId(name,
"expected extclass name") ||
5725 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5729 if (name == circuit.getName())
5730 return mlir::emitError(
info.getLoc(),
5731 "extclass cannot be the top of a circuit");
5733 for (
auto &portInfo : portList)
5735 return
mlir::emitError(portInfo.loc,
5736 "ports on extclasses must be properties");
5739 auto builder = circuit.getBodyBuilder();
5740 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5743 getConstants().classMap[name.getValue()] = extClassOp;
5744 return skipToModuleEnd(indent);
5752ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5755 ArrayAttr enabledLayers;
5756 ArrayAttr knownLayers;
5757 ArrayAttr externalRequirements;
5758 SmallVector<PortInfo, 8> portList;
5759 SmallVector<SMLoc> portLocs;
5761 consumeToken(FIRToken::kw_extmodule);
5762 if (parseId(name,
"expected extmodule name") ||
5763 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
5764 externalRequirements) ||
5765 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5770 if (consumeIf(FIRToken::kw_defname)) {
5771 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5772 parseId(defName,
"expected defname name"))
5776 ArrayAttr parameters;
5781 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5782 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5783 if (ftype.hasUninferredWidth())
5784 return emitError(loc,
"extmodule port must have known width");
5789 auto builder = circuit.getBodyBuilder();
5790 auto isMainModule = (name == circuit.getName());
5792 (isMainModule && getConstants().options.scalarizePublicModules) ||
5793 getConstants().options.scalarizeExtModules
5794 ? Convention::Scalarized
5795 : Convention::Internal;
5796 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5797 auto annotations = ArrayAttr::get(getContext(), {});
5798 auto extModuleOp = FExtModuleOp::create(
5799 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5800 defName, annotations, parameters, enabledLayers, externalRequirements);
5801 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5802 : SymbolTable::Visibility::Private;
5803 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5811ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5815 ArrayAttr enabledLayers;
5816 SmallVector<PortInfo, 8> portList;
5817 SmallVector<SMLoc> portLocs;
5819 consumeToken(FIRToken::kw_intmodule);
5820 if (parseId(name,
"expected intmodule name") ||
5821 parseModuleLayerSpec(enabledLayers) ||
5822 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5824 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5825 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5826 parseId(intName,
"expected intrinsic name"))
5829 ArrayAttr parameters;
5833 ArrayAttr annotations = getConstants().emptyArrayAttr;
5834 auto builder = circuit.getBodyBuilder();
5835 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5836 annotations, parameters, enabledLayers)
5842ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5845 SmallVector<PortInfo, 8> portList;
5846 SmallVector<SMLoc> portLocs;
5847 ArrayAttr enabledLayers;
5848 auto modLoc = getToken().getLoc();
5849 LocWithInfo
info(modLoc,
this);
5850 consumeToken(FIRToken::kw_module);
5851 if (parseId(name,
"expected module name") ||
5852 parseModuleLayerSpec(enabledLayers) ||
5853 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5858 if (name == circuit.getName()) {
5859 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5864 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5865 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5866 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5867 if (ftype.hasUninferredWidth())
5868 return emitError(loc,
"public module port must have known width");
5869 if (ftype.hasUninferredReset())
5870 return emitError(loc,
5871 "public module port must have concrete reset type");
5876 ArrayAttr annotations = getConstants().emptyArrayAttr;
5877 auto convention = Convention::Internal;
5878 if (isPublic && getConstants().options.scalarizePublicModules)
5879 convention = Convention::Scalarized;
5880 if (!isPublic && getConstants().options.scalarizeInternalModules)
5881 convention = Convention::Scalarized;
5882 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5883 auto builder = circuit.getBodyBuilder();
5885 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
5886 annotations, enabledLayers);
5888 auto visibility = isPublic ? SymbolTable::Visibility::Public
5889 : SymbolTable::Visibility::Private;
5890 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5894 deferredModules.emplace_back(DeferredModuleToParse{
5895 moduleOp, portLocs, getLexer().getCursor(), indent});
5897 if (skipToModuleEnd(indent))
5903ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5904 consumeToken(FIRToken::kw_formal);
5905 return parseFormalLike<FormalOp>(circuit, indent);
5909ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5911 consumeToken(FIRToken::kw_simulation);
5912 return parseFormalLike<SimulationOp>(circuit, indent);
5919ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5921 StringRef id, moduleName;
5924 auto builder = circuit.getBodyBuilder();
5927 if (parseId(
id,
"expected test name") ||
5928 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5929 parseId(moduleName,
"expected module name"))
5933 NamedAttrList params;
5934 if (consumeIf(FIRToken::comma)) {
5936 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5937 return emitError(
"expected 'bound' after ','");
5939 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5940 parseIntLit(bound,
"expected integer bound after '='"))
5943 return emitError(
"bound must be a positive integer");
5944 if (
info.parseOptionalInfo())
5946 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5949 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5950 info.parseOptionalInfo())
5952 while (getIndentation() > indent) {
5953 StringAttr paramName;
5954 Attribute paramValue;
5956 if (parseParameter(paramName, paramValue, paramLoc,
5959 if (params.set(paramName, paramValue))
5960 return emitError(paramLoc,
"redefinition of parameter '" +
5961 paramName.getValue() +
"'");
5965 Op::create(builder,
info.getLoc(),
id, moduleName,
5966 params.getDictionary(getContext()));
5970ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5972 switch (getToken().getKind()) {
5973 case FIRToken::kw_class:
5974 return parseClass(circuit, indent);
5975 case FIRToken::kw_declgroup:
5976 if (requireFeature({3, 2, 0},
"optional groups") ||
5977 removedFeature({3, 3, 0},
"optional groups"))
5979 return parseLayer(circuit);
5980 case FIRToken::kw_domain:
5983 return parseDomain(circuit, indent);
5984 case FIRToken::kw_extclass:
5985 return parseExtClass(circuit, indent);
5986 case FIRToken::kw_extmodule:
5987 return parseExtModule(circuit, indent);
5988 case FIRToken::kw_formal:
5989 if (requireFeature({4, 0, 0},
"formal tests"))
5991 return parseFormal(circuit, indent);
5992 case FIRToken::kw_intmodule:
5993 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
5994 removedFeature({4, 0, 0},
"intrinsic modules"))
5996 return parseIntModule(circuit, indent);
5997 case FIRToken::kw_layer:
5998 if (requireFeature({3, 3, 0},
"layers"))
6000 return parseLayer(circuit);
6001 case FIRToken::kw_module:
6002 return parseModule(circuit,
false, indent);
6003 case FIRToken::kw_public:
6004 if (requireFeature({3, 3, 0},
"public modules"))
6007 if (getToken().getKind() == FIRToken::kw_module)
6008 return parseModule(circuit,
true, indent);
6009 return emitError(getToken().
getLoc(),
"only modules may be public");
6010 case FIRToken::kw_simulation:
6013 return parseSimulation(circuit, indent);
6014 case FIRToken::kw_type:
6015 return parseTypeDecl();
6016 case FIRToken::kw_option:
6019 return parseOptionDecl(circuit);
6021 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6026ParseResult FIRCircuitParser::parseTypeDecl() {
6030 auto loc = getToken().getLoc();
6032 if (getToken().isKeyword())
6033 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6034 <<
"' for type alias name";
6036 if (parseId(
id,
"expected type name") ||
6037 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6040 auto name = StringAttr::get(type.getContext(),
id);
6043 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6044 type = BaseTypeAliasType::get(name, base);
6047 <<
"type alias for non-base type " << type
6048 <<
" is currently not supported. Type alias is stripped immediately";
6050 if (!getConstants().aliasMap.insert({id, type}).second)
6051 return emitError(loc) <<
"type alias `" << name.getValue()
6052 <<
"` is already defined";
6057ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6060 auto loc = getToken().getLoc();
6063 if (parseId(
id,
"expected an option group name") ||
6064 parseToken(FIRToken::colon,
6065 "expected ':' after option group definition") ||
6066 info.parseOptionalInfo())
6069 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6070 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6071 auto *block =
new Block;
6072 optionOp.getBody().push_back(block);
6073 builder.setInsertionPointToEnd(block);
6075 auto baseIndent = getIndentation();
6077 while (getIndentation() == baseIndent) {
6079 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6080 if (parseId(
id,
"expected an option case ID") ||
6081 caseInfo.parseOptionalInfo())
6084 if (!cases.insert(
id).second)
6085 return emitError(loc)
6086 <<
"duplicate option case definition '" <<
id <<
"'";
6088 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6095ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6096 auto baseIndent = getIndentation();
6099 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6102 auto parseOne = [&](
Block *block) -> ParseResult {
6103 auto indent = getIndentation();
6104 StringRef id, convention;
6107 if (parseId(
id,
"expected layer name") ||
6108 parseToken(FIRToken::comma,
"expected ','") ||
6109 parseGetSpelling(convention))
6112 auto layerConvention = symbolizeLayerConvention(convention);
6113 if (!layerConvention) {
6114 emitError() <<
"unknown convention '" << convention
6115 <<
"' (did you misspell it?)";
6118 if (layerConvention == LayerConvention::Inline &&
6119 requireFeature({4, 1, 0},
"inline layers"))
6123 hw::OutputFileAttr outputDir;
6124 if (consumeIf(FIRToken::comma)) {
6125 if (getToken().getKind() == FIRToken::string) {
6126 auto text = getToken().getStringValue();
6128 return emitError() <<
"output directory must not be blank";
6129 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6130 consumeToken(FIRToken::string);
6134 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6135 info.parseOptionalInfo())
6137 auto builder = OpBuilder::atBlockEnd(block);
6140 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6141 layerOp->getRegion(0).push_back(
new Block());
6143 layerOp->setAttr(
"output_file", outputDir);
6144 layerStack.push_back({indent, layerOp});
6148 if (parseOne(circuit.getBodyBlock()))
6152 while (getIndentation() > baseIndent) {
6153 switch (getToken().getKind()) {
6154 case FIRToken::kw_declgroup:
6155 case FIRToken::kw_layer: {
6158 while (layerStack.back().first >= getIndentation())
6159 layerStack.pop_back();
6160 auto parentLayer = layerStack.back().second;
6161 if (parseOne(&parentLayer.getBody().front()))
6166 return emitError(
"expected 'layer'"), failure();
6173ParseResult FIRCircuitParser::resolveDomains(
6174 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6175 const DenseMap<Attribute, size_t> &nameToIndex,
6176 SmallVectorImpl<Attribute> &domainsByIndex) {
6178 for (
auto [attr, loc] : domainsByName) {
6179 auto domain = cast<StringAttr>(attr);
6180 auto indexItr = nameToIndex.find(domain);
6181 if (indexItr == nameToIndex.end()) {
6182 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6185 domainsByIndex.push_back(IntegerAttr::get(
6186 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6193ParseResult FIRCircuitParser::parseDomains(
6194 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6195 const DenseMap<Attribute, size_t> &nameToIndex) {
6198 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6199 parseToken(FIRToken::l_square,
"expected '['"))
6202 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6204 auto domainLoc = getToken().getLoc();
6205 if (parseId(domain,
"expected domain name"))
6207 domains.push_back({domain, domainLoc});
6217FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6218 DeferredModuleToParse &deferredModule,
6219 InnerSymFixups &fixups) {
6220 FModuleLike moduleOp = deferredModule.moduleOp;
6221 auto &body = moduleOp->getRegion(0).front();
6222 auto &portLocs = deferredModule.portLocs;
6226 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6229 deferredModule.lexerCursor.restore(moduleBodyLexer);
6231 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6236 auto portList = moduleOp.getPorts();
6237 auto portArgs = body.getArguments();
6238 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6239 PortInfo &port = std::get<0>(tuple);
6240 llvm::SMLoc loc = std::get<1>(tuple);
6241 BlockArgument portArg = std::get<2>(tuple);
6243 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6247 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6250 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6256 size_t numVerifPrintfs = 0;
6257 std::optional<Location> printfLoc;
6259 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6264 printfLoc = printFOp.getLoc();
6267 if (numVerifPrintfs > 0) {
6269 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6271 <<
" printf-encoded verification operation(s), which are no longer "
6273 diag.attachNote(*printfLoc)
6274 <<
"example printf here, this is now just a printf and nothing more";
6275 diag.attachNote() <<
"For more information, see "
6276 "https://github.com/llvm/circt/issues/6970";
6290ParseResult FIRCircuitParser::parseCircuit(
6291 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6292 mlir::TimingScope &ts) {
6294 auto indent = getIndentation();
6295 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6297 if (!indent.has_value())
6298 return emitError(
"'FIRRTL' must be first token on its line");
6299 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6300 parseVersionLit(
"expected version literal"))
6302 indent = getIndentation();
6304 if (!indent.has_value())
6305 return emitError(
"'circuit' must be first token on its line");
6306 unsigned circuitIndent = *indent;
6310 SMLoc inlineAnnotationsLoc;
6311 StringRef inlineAnnotations;
6314 if (parseToken(FIRToken::kw_circuit,
6315 "expected a top-level 'circuit' definition") ||
6316 parseId(name,
"expected circuit name") ||
6317 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6318 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6319 info.parseOptionalInfo())
6323 OpBuilder b(mlirModule.getBodyRegion());
6324 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6327 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6333 SmallVector<Attribute> annos;
6334 if (!inlineAnnotations.empty())
6335 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6339 for (
auto *annotationsBuf : annotationsBufs)
6340 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6344 parseAnnotationTimer.stop();
6352 auto parseTimer = ts.nest(
"Parse modules");
6353 deferredModules.reserve(16);
6357 switch (getToken().getKind()) {
6365 case FIRToken::error:
6369 emitError(
"unexpected token in circuit");
6372 case FIRToken::kw_class:
6373 case FIRToken::kw_declgroup:
6374 case FIRToken::kw_domain:
6375 case FIRToken::kw_extclass:
6376 case FIRToken::kw_extmodule:
6377 case FIRToken::kw_intmodule:
6378 case FIRToken::kw_layer:
6379 case FIRToken::kw_formal:
6380 case FIRToken::kw_module:
6381 case FIRToken::kw_option:
6382 case FIRToken::kw_public:
6383 case FIRToken::kw_simulation:
6384 case FIRToken::kw_type: {
6385 auto indent = getIndentation();
6386 if (!indent.has_value())
6387 return emitError(
"'module' must be first token on its line"), failure();
6388 unsigned definitionIndent = *indent;
6390 if (definitionIndent <= circuitIndent)
6391 return emitError(
"module should be indented more"), failure();
6393 if (parseToplevelDefinition(circuit, definitionIndent))
6407 (void)getLexer().translateLocation(
info.getFIRLoc());
6413 DenseMap<Attribute, Location> nameToOrigLoc;
6417 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6422 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6425 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6426 .attachNote(it.first->second)
6427 .append(
"see existing symbol definition here");
6433 SymbolTable circuitSymTbl(circuit);
6435 moduleFixups.resize(deferredModules.size());
6440 for (
auto &d : deferredModules)
6441 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6444 auto anyFailed = mlir::failableParallelForEachN(
6445 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6446 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6447 moduleFixups[index]))
6451 if (failed(anyFailed))
6456 for (
auto &fixups : moduleFixups) {
6457 if (failed(fixups.resolve(innerSymbolNamespaces)))
6463 auto parseLayerName = [&](StringRef name) -> Attribute {
6465 auto [head, rest] = name.split(
".");
6466 SmallVector<FlatSymbolRefAttr> nestedRefs;
6467 while (!rest.empty()) {
6469 std::tie(next, rest) = rest.split(
".");
6470 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6472 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6475 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6476 SmallVector<Attribute> attrArray;
6478 for (
const auto &str : strArray)
6479 attrArray.push_back(getAttr(str));
6480 if (attrArray.empty())
6482 return ArrayAttr::get(
context, attrArray);
6485 if (
auto enableLayers =
6486 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6487 circuit.setEnableLayersAttr(enableLayers);
6488 if (
auto disableLayers =
6489 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6490 circuit.setDisableLayersAttr(disableLayers);
6492 auto getStrAttr = [&](StringRef str) -> Attribute {
6493 return StringAttr::get(getContext(), str);
6496 if (
auto selectInstChoice =
6497 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6498 circuit.setSelectInstChoiceAttr(selectInstChoice);
6500 circuit.setDefaultLayerSpecialization(
6501 getConstants().options.defaultLayerSpecialization);
6514 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6515 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6516 unsigned fileID = 1;
6518 annotationsBufs.push_back(
6519 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6521 context->loadDialect<CHIRRTLDialect>();
6522 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6526 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6529 SharedParserConstants state(
context, options);
6532 .parseCircuit(annotationsBufs, ts))
6537 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6538 if (failed(verify(*module)))
6545 static mlir::TranslateToMLIRRegistration fromFIR(
6546 "import-firrtl",
"import .fir",
6547 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6548 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
bool isRecognizedPrintfEncodedVerif(PrintFOp printOp)
Classifier for legacy verif intent captured in printf + when's.
constexpr FIRVersion nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
The FIRRTL specification version.
This holds the name and type that describes the module's ports.
StringRef getName() const