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 llvm::DenseMap<StringRef, DomainOp> domainMap;
95 const ArrayAttr emptyArrayAttr;
98 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
101 const hw::InnerRefAttr placeholderInnerRef;
104 SharedParserConstants(
const SharedParserConstants &) =
delete;
105 void operator=(
const SharedParserConstants &) =
delete;
118 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
120 : version(version), constants(constants), lexer(lexer),
121 locatorFilenameCache(constants.loIdentifier ) {
125 SharedParserConstants &getConstants()
const {
return constants; }
126 MLIRContext *getContext()
const {
return constants.context; }
128 FIRLexer &getLexer() {
return lexer; }
131 std::optional<unsigned> getIndentation()
const {
136 const FIRToken &getToken()
const {
return lexer.getToken(); }
137 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
144 InFlightDiagnostic emitError(
const Twine &message = {}) {
145 return emitError(getToken().
getLoc(), message);
147 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
150 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
151 return emitWarning(getToken().
getLoc(), message);
154 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
164 Location translateLocation(llvm::SMLoc loc) {
165 return lexer.translateLocation(loc);
170 ParseResult parseOptionalInfoLocator(LocationAttr &result);
174 ParseResult parseOptionalName(StringAttr &name);
180 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
181 return requireFeature(minimum, feature, getToken().
getLoc());
184 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
185 if (version < minimum)
186 return emitError(loc)
187 << feature <<
" are a FIRRTL " << minimum
188 <<
"+ feature, but the specified FIRRTL version was " << version;
192 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
193 return removedFeature(removedVersion, feature, getToken().
getLoc());
196 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
198 if (version >= removedVersion)
199 return emitError(loc)
200 << feature <<
" were removed in FIRRTL " << removedVersion
201 <<
", but the specified FIRRTL version was " << version;
211 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
220 if (getToken().isNot(kind))
230 FIRToken consumedToken = getToken();
231 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
232 "shouldn't advance past EOF or errors");
234 return consumedToken;
243 FIRToken consumedToken = getToken();
244 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
246 return consumedToken;
251 ParseResult parseGetSpelling(StringRef &spelling) {
252 spelling = getTokenSpelling();
258 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
263 const std::function<ParseResult()> &parseElement);
270 ParseResult parseIntLit(APInt &result,
const Twine &message);
271 ParseResult parseIntLit(int64_t &result,
const Twine &message);
272 ParseResult parseIntLit(int32_t &result,
const Twine &message);
275 ParseResult parseVersionLit(
const Twine &message);
278 ParseResult parseWidth(int32_t &result);
281 ParseResult parseId(StringRef &result,
const Twine &message);
282 ParseResult parseId(StringAttr &result,
const Twine &message);
283 ParseResult parseFieldId(StringRef &result,
const Twine &message);
284 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
285 const Twine &message);
286 ParseResult parseEnumType(
FIRRTLType &result);
287 ParseResult parseListType(
FIRRTLType &result);
290 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
292 ParseResult parseRUW(RUWBehavior &result);
293 ParseResult parseOptionalRUW(RUWBehavior &result);
295 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
296 SMLoc &resultLoc,
bool allowAggregates =
false);
297 ParseResult parseParameterValue(Attribute &resultValue,
298 bool allowAggregates =
false);
304 FIRParser(
const FIRParser &) =
delete;
305 void operator=(
const FIRParser &) =
delete;
309 SharedParserConstants &constants;
313 StringAttr locatorFilenameCache;
315 FileLineColLoc fileLineColLocCache;
324InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
325 auto diag = mlir::emitError(translateLocation(loc), message);
329 if (getToken().is(FIRToken::error))
334InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
335 return mlir::emitWarning(translateLocation(loc), message);
345 const Twine &message) {
346 if (consumeIf(expectedToken))
348 return emitError(message);
355 const std::function<ParseResult()> &parseElement) {
356 if (consumeIf(rightToken))
362 while (consumeIf(FIRToken::comma)) {
367 if (parseToken(rightToken,
"expected ','"))
399 if (failed(
parser->parseOptionalInfoLocator(loc)))
403 switch (
parser->constants.options.infoLocatorHandling) {
404 case ILH::IgnoreInfo:
405 assert(0 &&
"Should not return info locations if ignoring");
407 case ILH::PreferInfo:
411 infoLoc = FusedLoc::get(loc.getContext(),
412 {loc, parser->translateLocation(firLoc)});
439ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
440 if (getToken().isNot(FIRToken::fileinfo))
443 auto loc = getToken().getLoc();
445 auto spelling = getTokenSpelling();
446 consumeToken(FIRToken::fileinfo);
450 constants.options.infoLocatorHandling ==
451 FIRParserOptions::InfoLocHandling::IgnoreInfo,
452 locatorFilenameCache, fileLineColLocCache, getContext());
455 if (!locationPair.first) {
456 mlir::emitWarning(translateLocation(loc),
457 "ignoring unknown @ info record format");
463 if (locationPair.first && constants.options.infoLocatorHandling ==
464 FIRParserOptions::InfoLocHandling::IgnoreInfo)
468 result = *locationPair.second;
476ParseResult FIRParser::parseOptionalName(StringAttr &name) {
478 if (getToken().isNot(FIRToken::colon)) {
479 name = StringAttr::get(getContext(),
"");
483 consumeToken(FIRToken::colon);
485 if (parseId(nameRef,
"expected result name"))
488 name = StringAttr::get(getContext(), nameRef);
499ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
501 if (getToken().isNot(FIRToken::inlineannotation))
504 loc = getToken().getLoc();
506 result = getTokenSpelling().drop_front(2).drop_back(1);
507 consumeToken(FIRToken::inlineannotation);
525ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
526 auto spelling = getTokenSpelling();
527 bool isNegative =
false;
528 switch (getToken().getKind()) {
529 case FIRToken::signed_integer:
530 isNegative = spelling[0] ==
'-';
531 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
532 spelling = spelling.drop_front();
534 case FIRToken::integer:
535 if (spelling.getAsInteger(10, result))
536 return emitError(message), failure();
540 if (result.isNegative())
541 result = result.zext(result.getBitWidth() + 1);
550 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
551 result = result.trunc(32);
555 case FIRToken::radix_specified_integer: {
556 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
558 if (spelling[0] ==
'-') {
560 spelling = spelling.drop_front();
562 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
567 spelling = spelling.drop_front(2);
568 if (spelling.getAsInteger(base, result))
569 return emitError(
"invalid character in integer literal"), failure();
570 if (result.isNegative())
571 result = result.zext(result.getBitWidth() + 1);
577 case FIRToken::string: {
580 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
583 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
584 spelling = spelling.drop_back().drop_front();
588 switch (spelling.empty() ?
' ' : spelling.front()) {
599 return emitError(
"expected base specifier (h/o/b) in integer literal"),
602 spelling = spelling.drop_front();
605 bool isNegative =
false;
606 if (!spelling.empty() && spelling.front() ==
'+')
607 spelling = spelling.drop_front();
608 else if (!spelling.empty() && spelling.front() ==
'-') {
610 spelling = spelling.drop_front();
614 if (spelling.empty())
615 return emitError(
"expected digits in integer literal"), failure();
617 if (spelling.getAsInteger(base, result))
618 return emitError(
"invalid character in integer literal"), failure();
623 if (result.isNegative())
624 result = result.zext(result.getBitWidth() + 1);
629 consumeToken(FIRToken::string);
634 return emitError(
"expected integer literal"), failure();
638ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
640 auto loc = getToken().getLoc();
641 if (parseIntLit(value, message))
644 result = (int64_t)value.getLimitedValue(INT64_MAX);
646 return emitError(loc,
"value is too big to handle"), failure();
650ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
652 auto loc = getToken().getLoc();
653 if (parseIntLit(value, message))
656 result = (int32_t)value.getLimitedValue(INT32_MAX);
658 return emitError(loc,
"value is too big to handle"), failure();
664ParseResult FIRParser::parseVersionLit(
const Twine &message) {
665 auto spelling = getTokenSpelling();
666 if (getToken().getKind() != FIRToken::version)
667 return emitError(message), failure();
669 auto [
a,
d] = spelling.split(
".");
670 auto [
b, c] =
d.split(
".");
671 APInt aInt, bInt, cInt;
672 if (
a.getAsInteger(10, aInt) ||
b.getAsInteger(10, bInt) ||
673 c.getAsInteger(10, cInt))
674 return emitError(
"failed to parse version string"), failure();
675 version.major = aInt.getLimitedValue(UINT32_MAX);
676 version.minor = bInt.getLimitedValue(UINT32_MAX);
677 version.patch = cInt.getLimitedValue(UINT32_MAX);
678 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
679 return emitError(
"integers out of range"), failure();
683 consumeToken(FIRToken::version);
689ParseResult FIRParser::parseWidth(int32_t &result) {
690 auto widthLoc = getToken().getLoc();
691 if (parseIntLit(result,
"expected width") ||
692 parseToken(FIRToken::greater,
"expected '>'"))
695 return emitError(widthLoc,
"invalid width specifier"), failure();
703ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
704 switch (getToken().getKind()) {
706 case FIRToken::identifier:
707 case FIRToken::literal_identifier:
709#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
710#include "FIRTokenKinds.def"
715 if (getToken().getKind() == FIRToken::literal_identifier)
716 result = getTokenSpelling().drop_front().drop_back();
718 result = getTokenSpelling();
728ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
730 if (parseId(name, message))
733 result = StringAttr::get(getContext(), name);
742ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
744 result = getTokenSpelling();
745 if (consumeIf(FIRToken::integer))
751 if (parseId(result, message))
763ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
764 const Twine &message) {
766 StringRef tmp = getTokenSpelling();
768 if (consumeIf(FIRToken::integer)) {
769 result.push_back(tmp);
773 if (consumeIf(FIRToken::floatingpoint)) {
777 auto [
a,
b] = tmp.split(
".");
783 if (consumeIf(FIRToken::version)) {
785 auto [
a,
d] = tmp.split(
".");
786 auto [
b, c] =
d.split(
".");
794 if (parseId(tmp, message))
796 result.push_back(tmp);
802ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
803 if (parseToken(FIRToken::l_brace_bar,
804 "expected leading '{|' in enumeration type"))
806 SmallVector<StringAttr> names;
807 SmallVector<APInt> values;
808 SmallVector<FIRRTLBaseType> types;
809 SmallVector<SMLoc> locs;
810 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
811 auto fieldLoc = getToken().getLoc();
812 locs.push_back(fieldLoc);
816 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
818 auto name = StringAttr::get(getContext(), nameStr);
819 names.push_back(name);
825 if (consumeIf(FIRToken::equal)) {
826 if (parseIntLit(value,
"expected integer value for enumeration tag"))
828 if (value.isNegative())
829 return emitError(fieldLoc,
"enum tag value must be non-negative");
830 }
else if (values.empty()) {
836 auto &prev = values.back();
837 if (prev.isMaxValue())
838 value = prev.zext(prev.getBitWidth() + 1);
843 values.push_back(std::move(value));
847 if (consumeIf(FIRToken::colon)) {
849 if (
parseType(parsedType,
"expected enumeration type"))
851 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
853 return emitError(fieldLoc,
"field must be a base type");
856 type = UIntType::get(getContext(), 0);
858 types.push_back(type);
860 auto r = type.getRecursiveTypeProperties();
862 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
863 if (r.containsAnalog)
864 return emitError(fieldLoc)
865 <<
"enum field " << name <<
" contains analog";
866 if (r.hasUninferredWidth)
867 return emitError(fieldLoc)
868 <<
"enum field " << name <<
" has uninferred width";
869 if (r.hasUninferredReset)
870 return emitError(fieldLoc)
871 <<
"enum field " << name <<
" has uninferred reset";
877 SmallPtrSet<StringAttr, 4> nameSet;
878 for (
auto [name, loc] :
llvm::zip(names, locs))
879 if (!nameSet.insert(name).second)
880 return emitError(loc,
881 "duplicate variant name in enum: " + name.getValue());
884 unsigned bitwidth = 0;
885 for (
auto &value : values)
886 bitwidth = std::max(bitwidth, value.getActiveBits());
888 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
892 SmallPtrSet<IntegerAttr, 4> valueSet;
893 SmallVector<FEnumType::EnumElement, 4> elements;
894 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
895 auto tagValue = value.zextOrTrunc(bitwidth);
896 auto attr = IntegerAttr::get(tagType, tagValue);
898 if (!valueSet.insert(attr).second)
899 return emitError(loc,
"duplicate variant value in enum: ") << attr;
900 elements.push_back({name, attr, type});
903 llvm::sort(elements);
904 result = FEnumType::get(getContext(), elements);
908ParseResult FIRParser::parsePropertyType(
PropertyType &result,
909 const Twine &message) {
910 auto loc = getToken().getLoc();
915 auto prop = type_dyn_cast<PropertyType>(type);
917 return emitError(loc,
"expected property type");
923ParseResult FIRParser::parseListType(
FIRRTLType &result) {
924 consumeToken(FIRToken::kw_List);
927 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
928 parsePropertyType(
elementType,
"expected List element type") ||
929 parseToken(FIRToken::greater,
"expected '>' in List type"))
955ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
956 switch (getToken().getKind()) {
958 return emitError(message), failure();
960 case FIRToken::kw_Clock:
961 consumeToken(FIRToken::kw_Clock);
962 result = ClockType::get(getContext());
965 case FIRToken::kw_Inst: {
969 consumeToken(FIRToken::kw_Inst);
970 if (parseToken(FIRToken::less,
"expected < in Inst type"))
973 auto loc = getToken().getLoc();
975 if (parseId(
id,
"expected class name in Inst type"))
979 const auto &classMap = getConstants().classMap;
980 auto lookup = classMap.find(
id);
981 if (lookup == classMap.end())
982 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
984 auto classOp = lookup->second;
986 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
989 result = classOp.getInstanceType();
993 case FIRToken::kw_AnyRef: {
997 consumeToken(FIRToken::kw_AnyRef);
998 result = AnyRefType::get(getContext());
1002 case FIRToken::kw_Reset:
1003 consumeToken(FIRToken::kw_Reset);
1004 result = ResetType::get(getContext());
1007 case FIRToken::kw_AsyncReset:
1008 consumeToken(FIRToken::kw_AsyncReset);
1009 result = AsyncResetType::get(getContext());
1012 case FIRToken::kw_UInt:
1013 consumeToken(FIRToken::kw_UInt);
1015 result = UIntType::get(getContext(), -1);
1018 case FIRToken::kw_SInt:
1019 consumeToken(FIRToken::kw_SInt);
1021 result = SIntType::get(getContext(), -1);
1024 case FIRToken::kw_Analog:
1025 consumeToken(FIRToken::kw_Analog);
1027 result = AnalogType::get(getContext(), -1);
1030 case FIRToken::langle_UInt:
1031 case FIRToken::langle_SInt:
1032 case FIRToken::langle_Analog: {
1035 auto kind = getToken().getKind();
1039 if (parseWidth(width))
1042 if (kind == FIRToken::langle_SInt)
1043 result = SIntType::get(getContext(), width);
1044 else if (kind == FIRToken::langle_UInt)
1045 result = UIntType::get(getContext(), width);
1047 assert(kind == FIRToken::langle_Analog);
1048 result = AnalogType::get(getContext(), width);
1053 case FIRToken::kw_Domain: {
1059 auto loc = getToken().getLoc();
1060 StringRef domainKindStr;
1061 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type") ||
1062 parseId(domainKindStr,
"expected domain kind"))
1066 const auto &domainMap = getConstants().domainMap;
1067 auto lookup = domainMap.find(domainKindStr);
1068 if (lookup == domainMap.end())
1069 return emitError(loc) <<
"unknown domain '" << domainKindStr <<
"'";
1071 result = DomainType::getFromDomainOp(lookup->second);
1075 case FIRToken::kw_Probe:
1076 case FIRToken::kw_RWProbe: {
1077 auto kind = getToken().getKind();
1078 auto loc = getToken().getLoc();
1083 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1084 parseType(type,
"expected probe data type"))
1087 SmallVector<StringRef> layers;
1088 if (consumeIf(FIRToken::comma)) {
1089 if (requireFeature({4, 0, 0},
"colored probes"))
1094 loc = getToken().getLoc();
1095 if (parseId(layer,
"expected layer name"))
1097 layers.push_back(layer);
1098 }
while (consumeIf(FIRToken::period));
1101 if (!consumeIf(FIRToken::greater))
1102 return emitError(loc,
"expected '>' to end reference type");
1104 bool forceable = kind == FIRToken::kw_RWProbe;
1106 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1108 return emitError(loc,
"invalid probe inner type, must be base-type");
1111 return emitError(loc,
"probe inner type must be passive");
1113 if (forceable &&
innerType.containsConst())
1114 return emitError(loc,
"rwprobe cannot contain const");
1116 SymbolRefAttr layer;
1117 if (!layers.empty()) {
1119 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1120 return FlatSymbolRefAttr::get(getContext(), a);
1122 layer = SymbolRefAttr::get(getContext(), layers.front(),
1123 llvm::to_vector(nestedLayers));
1126 result = RefType::get(innerType, forceable, layer);
1130 case FIRToken::l_brace: {
1131 consumeToken(FIRToken::l_brace);
1133 SmallVector<OpenBundleType::BundleElement, 4> elements;
1134 SmallPtrSet<StringAttr, 4> nameSet;
1135 bool bundleCompatible =
true;
1136 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1137 bool isFlipped = consumeIf(FIRToken::kw_flip);
1139 auto loc = getToken().getLoc();
1140 StringRef fieldNameStr;
1141 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1142 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1144 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1147 if (!nameSet.insert(fieldName).second)
1148 return emitError(loc,
"duplicate field name in bundle: " +
1149 fieldName.getValue());
1152 if (
parseType(type,
"expected bundle field type"))
1155 elements.push_back({fieldName, isFlipped, type});
1156 bundleCompatible &= isa<BundleType::ElementType>(type);
1163 if (bundleCompatible) {
1164 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1165 return BundleType::BundleElement{
1166 element.name, element.isFlip,
1167 cast<BundleType::ElementType>(element.type)};
1169 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1171 result = OpenBundleType::get(getContext(), elements);
1175 case FIRToken::l_brace_bar: {
1176 if (parseEnumType(result))
1181 case FIRToken::identifier: {
1183 auto loc = getToken().getLoc();
1184 if (parseId(
id,
"expected a type alias name"))
1186 auto it = constants.aliasMap.find(
id);
1187 if (it == constants.aliasMap.end()) {
1188 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1191 result = it->second;
1195 case FIRToken::kw_const: {
1196 consumeToken(FIRToken::kw_const);
1197 auto nextToken = getToken();
1198 auto loc = nextToken.getLoc();
1201 if (nextToken.is(FIRToken::kw_const))
1202 return emitError(loc,
"'const' can only be specified once on a type");
1207 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1209 return emitError(loc,
"only hardware types can be 'const'");
1211 result = baseType.getConstType(
true);
1215 case FIRToken::kw_String:
1216 if (requireFeature({3, 1, 0},
"Strings"))
1218 consumeToken(FIRToken::kw_String);
1219 result = StringType::get(getContext());
1221 case FIRToken::kw_Integer:
1222 if (requireFeature({3, 1, 0},
"Integers"))
1224 consumeToken(FIRToken::kw_Integer);
1225 result = FIntegerType::get(getContext());
1227 case FIRToken::kw_Bool:
1230 consumeToken(FIRToken::kw_Bool);
1231 result = BoolType::get(getContext());
1233 case FIRToken::kw_Double:
1236 consumeToken(FIRToken::kw_Double);
1237 result = DoubleType::get(getContext());
1239 case FIRToken::kw_Path:
1242 consumeToken(FIRToken::kw_Path);
1243 result = PathType::get(getContext());
1245 case FIRToken::kw_List:
1246 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1250 case FIRToken::langle_List: {
1253 if (requireFeature({4, 0, 0},
"Lists"))
1258 if (parsePropertyType(
elementType,
"expected List element type") ||
1259 parseToken(FIRToken::greater,
"expected '>' in List type"))
1262 result = ListType::get(getContext(),
elementType);
1268 while (consumeIf(FIRToken::l_square)) {
1269 auto sizeLoc = getToken().getLoc();
1271 if (parseIntLit(size,
"expected width") ||
1272 parseToken(FIRToken::r_square,
"expected ]"))
1276 return emitError(sizeLoc,
"invalid size specifier"), failure();
1278 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1280 result = FVectorType::get(baseType, size);
1282 result = OpenVectorType::get(result, size);
1289ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1290 switch (getToken().getKind()) {
1292 case FIRToken::kw_old:
1293 result = RUWBehavior::Old;
1294 consumeToken(FIRToken::kw_old);
1296 case FIRToken::kw_new:
1297 result = RUWBehavior::New;
1298 consumeToken(FIRToken::kw_new);
1300 case FIRToken::kw_undefined:
1301 result = RUWBehavior::Undefined;
1302 consumeToken(FIRToken::kw_undefined);
1312ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1313 switch (getToken().getKind()) {
1317 case FIRToken::kw_old:
1318 result = RUWBehavior::Old;
1319 consumeToken(FIRToken::kw_old);
1321 case FIRToken::kw_new:
1322 result = RUWBehavior::New;
1323 consumeToken(FIRToken::kw_new);
1325 case FIRToken::kw_undefined:
1326 result = RUWBehavior::Undefined;
1327 consumeToken(FIRToken::kw_undefined);
1335ParseResult FIRParser::parseParameter(StringAttr &resultName,
1336 Attribute &resultValue, SMLoc &resultLoc,
1337 bool allowAggregates) {
1338 auto loc = getToken().getLoc();
1342 if (parseId(name,
"expected parameter name") ||
1343 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1348 if (parseParameterValue(value, allowAggregates))
1351 resultName = StringAttr::get(getContext(), name);
1352 resultValue = value;
1363ParseResult FIRParser::parseParameterValue(Attribute &value,
1364 bool allowAggregates) {
1365 mlir::Builder builder(getContext());
1366 switch (getToken().getKind()) {
1369 case FIRToken::integer:
1370 case FIRToken::signed_integer: {
1372 if (parseIntLit(result,
"invalid integer parameter"))
1378 if (result.getBitWidth() < 32)
1379 result = result.sext(32);
1381 value = builder.getIntegerAttr(
1382 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1388 case FIRToken::string: {
1390 value = builder.getStringAttr(getToken().getStringValue());
1391 consumeToken(FIRToken::string);
1396 case FIRToken::verbatim_string: {
1398 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1399 value = hw::ParamVerbatimAttr::get(text);
1400 consumeToken(FIRToken::verbatim_string);
1405 case FIRToken::floatingpoint: {
1407 if (!llvm::to_float(getTokenSpelling(), v))
1408 return emitError(
"invalid float parameter syntax"), failure();
1410 value = builder.getF64FloatAttr(v);
1411 consumeToken(FIRToken::floatingpoint);
1416 case FIRToken::l_square: {
1417 if (!allowAggregates)
1418 return emitError(
"expected non-aggregate parameter value");
1421 SmallVector<Attribute> elements;
1422 auto parseElement = [&] {
1423 return parseParameterValue(elements.emplace_back(),
1426 if (parseListUntil(FIRToken::r_square, parseElement))
1429 value = builder.getArrayAttr(elements);
1434 case FIRToken::l_brace: {
1435 if (!allowAggregates)
1436 return emitError(
"expected non-aggregate parameter value");
1439 NamedAttrList fields;
1440 auto parseField = [&]() -> ParseResult {
1441 StringAttr fieldName;
1442 Attribute fieldValue;
1444 if (parseParameter(fieldName, fieldValue, fieldLoc,
1447 if (fields.set(fieldName, fieldValue))
1448 return emitError(fieldLoc)
1449 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1452 if (parseListUntil(FIRToken::r_brace, parseField))
1455 value = fields.getDictionary(getContext());
1460 return emitError(
"expected parameter value");
1475 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1483struct UnbundledValueRestorer {
1485 size_t startingSize;
1487 startingSize = list.size();
1489 ~UnbundledValueRestorer() { list.resize(startingSize); }
1498struct FIRModuleContext :
public FIRParser {
1499 explicit FIRModuleContext(Block *topLevelBlock,
1500 SharedParserConstants &constants,
FIRLexer &lexer,
1502 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1505 template <
typename OpTy = ConstantOp,
typename... Args>
1506 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1507 Type type, Args &&...args) {
1508 auto &result = constantCache[{attr, type}];
1514 OpBuilder::InsertPoint savedIP;
1517 if (builder.getInsertionBlock() != topLevelBlock) {
1518 savedIP = builder.saveInsertionPoint();
1519 auto *block = builder.getInsertionBlock();
1521 auto *op = block->getParentOp();
1522 if (!op || !op->getBlock()) {
1524 builder.setInsertionPointToEnd(topLevelBlock);
1527 if (op->getBlock() == topLevelBlock) {
1528 builder.setInsertionPoint(op);
1531 block = op->getBlock();
1535 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1537 if (savedIP.isSet())
1538 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1549 Value &getCachedSubaccess(Value value,
unsigned index) {
1550 auto &result = subaccessCache[{value, index}];
1553 auto it = scopeMap.find(value.getParentBlock());
1554 if (it != scopeMap.end())
1555 it->second->scopedSubaccesses.push_back({result, index});
1565 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1566 bool insertNameIntoGlobalScope =
false);
1567 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1568 bool insertNameIntoGlobalScope =
false) {
1570 insertNameIntoGlobalScope);
1574 void removeSymbolEntry(StringRef name);
1578 SMLoc loc,
bool fatal =
true);
1583 StringRef field, SMLoc loc);
1591 assert(index < unbundledValues.size());
1592 return unbundledValues[index];
1602 struct ContextScope {
1603 friend struct FIRModuleContext;
1604 ContextScope(FIRModuleContext &moduleContext, Block *block)
1605 : moduleContext(moduleContext), block(block),
1606 previousScope(moduleContext.currentScope) {
1607 moduleContext.currentScope =
this;
1608 moduleContext.scopeMap[block] =
this;
1613 for (
auto *entryPtr : scopedDecls)
1614 entryPtr->second.first = SMLoc();
1617 for (
auto subaccess : scopedSubaccesses)
1618 moduleContext.subaccessCache.erase(subaccess);
1620 moduleContext.scopeMap.erase(block);
1622 moduleContext.currentScope = previousScope;
1626 void operator=(
const ContextScope &) =
delete;
1627 ContextScope(
const ContextScope &) =
delete;
1629 FIRModuleContext &moduleContext;
1631 ContextScope *previousScope;
1632 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1633 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1638 Block *topLevelBlock;
1644 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1656 DenseMap<Block *, ContextScope *> scopeMap;
1661 ContextScope *currentScope =
nullptr;
1667void FIRModuleContext::removeSymbolEntry(StringRef name) {
1668 symbolTable.erase(name);
1677ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1679 bool insertNameIntoGlobalScope) {
1682 auto [entryIt, inserted] =
1687 if (entryIt->second.first.isValid()) {
1689 emitError(loc,
"redefinition of name '" + name +
"' ")
1690 .attachNote(translateLocation(entryIt->second.first))
1691 <<
"previous definition here.";
1694 emitError(loc,
"redefinition of name '" + name +
"' ")
1695 <<
"- FIRRTL has flat namespace and requires all "
1696 <<
"declarations in a module to have unique names.";
1703 entryIt->second = {loc, entry};
1704 if (currentScope && !insertNameIntoGlobalScope)
1705 currentScope->scopedDecls.push_back(&*entryIt);
1712 StringRef name, SMLoc loc) {
1713 auto &entry = symbolTable[name];
1714 if (!entry.first.isValid())
1715 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1716 result = entry.second;
1717 assert(result &&
"name in symbol table without definition");
1721ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1723 SMLoc loc,
bool fatal) {
1724 if (!isa<Value>(entry)) {
1726 emitError(loc,
"bundle value should only be used from subfield");
1729 result = cast<Value>(entry);
1733ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1735 StringRef fieldName,
1737 if (!isa<UnbundledID>(entry)) {
1738 emitError(loc,
"value should not be used from subfield");
1742 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1744 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1745 assert(unbundledId < unbundledValues.size());
1747 for (
auto elt : ubEntry) {
1748 if (elt.first == fieldAttr) {
1749 result = elt.second;
1754 emitError(loc,
"use of invalid field name '")
1755 << fieldName <<
"' on bundle value";
1781struct LazyLocationListener :
public OpBuilder::Listener {
1782 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1783 assert(builder.getListener() ==
nullptr);
1784 builder.setListener(
this);
1787 ~LazyLocationListener() {
1788 assert(subOps.empty() &&
"didn't process parsed operations");
1789 assert(builder.getListener() ==
this);
1790 builder.setListener(
nullptr);
1793 void startStatement() {
1794 assert(!isActive &&
"Already processing a statement");
1800 void endStatement(FIRParser &parser) {
1801 assert(isActive &&
"Not parsing a statement");
1805 for (
auto opAndSMLoc : subOps) {
1809 switch (parser.getConstants().options.infoLocatorHandling) {
1810 case ILH::IgnoreInfo:
1812 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1814 case ILH::PreferInfo:
1815 opAndSMLoc.first->setLoc(infoLoc);
1817 case ILH::FusedInfo:
1818 opAndSMLoc.first->setLoc(FusedLoc::get(
1819 infoLoc.getContext(),
1820 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1827 for (
auto opAndSMLoc : subOps)
1828 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1833 infoLoc = LocationAttr();
1834 currentSMLoc = SMLoc();
1839 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1842 void setInfoLoc(LocationAttr loc) {
1843 assert(!infoLoc &&
"Info location multiply specified");
1849 void notifyOperationInserted(Operation *op,
1850 mlir::IRRewriter::InsertPoint)
override {
1851 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1852 assert(isActive &&
"Not parsing a statement");
1853 subOps.push_back({op, currentSMLoc});
1858 bool isActive =
false;
1866 LocationAttr infoLoc;
1873 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1875 void operator=(
const LazyLocationListener &) =
delete;
1876 LazyLocationListener(
const LazyLocationListener &) =
delete;
1884struct InnerSymFixups {
1887 fixups.push_back({user, target});
1896 hw::InnerRefUserOpInterface innerRefUser;
1899 SmallVector<Fixup, 0> fixups;
1905 for (
auto &f : fixups) {
1908 return isnc.get(module);
1910 assert(ref &&
"unable to resolve inner symbol target");
1914 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1915 .Case<RWProbeOp>([ref](RWProbeOp op) {
1916 op.setTargetAttr(ref);
1919 .Default([](
auto *op) {
1920 return op->emitError(
"unknown inner-ref user requiring fixup");
1931struct FIRStmtParser :
public FIRParser {
1932 explicit FIRStmtParser(Block &blockToInsertInto,
1933 FIRModuleContext &moduleContext,
1934 InnerSymFixups &innerSymFixups,
1935 const SymbolTable &circuitSymTbl,
FIRVersion version,
1936 SymbolRefAttr layerSym = {})
1937 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1939 builder(UnknownLoc::
get(getContext()), getContext()),
1940 locationProcessor(this->builder), moduleContext(moduleContext),
1941 innerSymFixups(innerSymFixups), layerSym(layerSym),
1942 circuitSymTbl(circuitSymTbl) {
1943 builder.setInsertionPointToEnd(&blockToInsertInto);
1946 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1947 ParseResult parseSimpleStmtBlock(
unsigned indent);
1950 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1953 void emitInvalidate(Value val,
Flow flow);
1959 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1962 ParseResult parseOptionalInfo() {
1964 if (failed(parseOptionalInfoLocator(loc)))
1966 locationProcessor.setInfoLoc(loc);
1971 ParseResult parseExpImpl(Value &result,
const Twine &message,
1972 bool isLeadingStmt);
1973 ParseResult parseExp(Value &result,
const Twine &message) {
1974 return parseExpImpl(result, message,
false);
1976 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1977 return parseExpImpl(result, message,
true);
1979 ParseResult parseEnumExp(Value &result);
1980 ParseResult parsePathExp(Value &result);
1981 ParseResult parseDomainExp(Value &result);
1982 ParseResult parseRefExp(Value &result,
const Twine &message);
1983 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1984 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1985 const Twine &message);
1988 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1989 ParseResult parseIntrinsicStmt() {
1991 return parseIntrinsic(unused,
true);
1993 ParseResult parseIntrinsicExp(Value &result) {
1994 return parseIntrinsic(result,
false);
1996 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1998 template <
typename subop>
1999 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
2000 ParseResult parseOptionalExpPostscript(Value &result,
2001 bool allowDynamic =
true);
2002 ParseResult parsePostFixFieldId(Value &result);
2003 ParseResult parsePostFixIntSubscript(Value &result);
2004 ParseResult parsePostFixDynamicSubscript(Value &result);
2006 parseIntegerLiteralExp(Value &result,
bool isSigned,
2007 std::optional<int32_t> allocatedWidth = {});
2008 ParseResult parseListExp(Value &result);
2009 ParseResult parseListConcatExp(Value &result);
2010 ParseResult parseCatExp(Value &result);
2011 ParseResult parseStringConcatExp(Value &result);
2012 ParseResult parseUnsafeDomainCast(Value &result);
2013 ParseResult parseUnknownProperty(Value &result);
2015 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
2016 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2018 auto loc = getToken().getLoc();
2019 locationProcessor.setLoc(loc);
2022 auto vals = std::array<Value, M>();
2023 auto ints = std::array<int64_t, N>();
2027 for (
size_t i = 0; i < M; ++i) {
2029 if (parseToken(FIRToken::comma,
"expected ','"))
2031 if (parseExp(vals[i],
"expected expression in primitive operand"))
2037 for (
size_t i = 0; i < N; ++i) {
2039 if (parseToken(FIRToken::comma,
"expected ','"))
2041 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2046 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2050 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2054 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2055 translateLocation(loc));
2060 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2061 result = op.getResult();
2065 template <
typename T,
unsigned M,
unsigned N>
2066 ParseResult parsePrimExp(Value &result) {
2067 auto ms = std::make_index_sequence<M>();
2068 auto ns = std::make_index_sequence<N>();
2069 return parsePrim<T, M, N>(ms, ns, result);
2072 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2075 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2076 SymbolRefAttr layerSym);
2077 ParseResult parseAttach();
2078 ParseResult parseMemPort(MemDirAttr direction);
2084 ArrayRef<Value> specOperands,
2085 StringAttr &formatStringResult,
2086 SmallVectorImpl<Value> &operands);
2087 ParseResult parsePrintf();
2088 ParseResult parseFPrintf();
2089 ParseResult parseFFlush();
2090 ParseResult parseSkip();
2091 ParseResult parseStop();
2092 ParseResult parseAssert();
2093 ParseResult parseAssume();
2094 ParseResult parseCover();
2095 ParseResult parseWhen(
unsigned whenIndent);
2096 ParseResult parseMatch(
unsigned matchIndent);
2097 ParseResult parseDomainInstantiation();
2098 ParseResult parseDomainDefine();
2099 ParseResult parseRefDefine();
2100 ParseResult parseRefForce();
2101 ParseResult parseRefForceInitial();
2102 ParseResult parseRefRelease();
2103 ParseResult parseRefReleaseInitial();
2104 ParseResult parseRefRead(Value &result);
2105 ParseResult parseProbe(Value &result);
2106 ParseResult parsePropAssign();
2107 ParseResult parseRWProbe(Value &result);
2108 ParseResult parseLeadingExpStmt(Value lhs);
2109 ParseResult parseConnect();
2110 ParseResult parseInvalidate();
2111 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2114 ParseResult parseInstance();
2115 ParseResult parseInstanceChoice();
2116 ParseResult parseObject();
2117 ParseResult parseCombMem();
2118 ParseResult parseSeqMem();
2119 ParseResult parseMem(
unsigned memIndent);
2120 ParseResult parseNode();
2121 ParseResult parseWire();
2122 ParseResult parseRegister(
unsigned regIndent);
2123 ParseResult parseRegisterWithReset();
2124 ParseResult parseContract(
unsigned blockIndent);
2127 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2130 ImplicitLocOpBuilder builder;
2131 LazyLocationListener locationProcessor;
2134 FIRModuleContext &moduleContext;
2137 InnerSymFixups &innerSymFixups;
2141 SymbolRefAttr layerSym;
2143 const SymbolTable &circuitSymTbl;
2150void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2151 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2158 auto props = tpe.getRecursiveTypeProperties();
2159 if (props.isPassive && !props.containsAnalog) {
2160 if (flow == Flow::Source)
2162 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2173 TypeSwitch<FIRRTLType>(tpe)
2174 .Case<BundleType>([&](
auto tpe) {
2175 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2176 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2178 OpBuilder::InsertionGuard guard(builder);
2179 builder.setInsertionPointAfterValue(val);
2180 subfield = SubfieldOp::create(builder, val, i);
2182 emitInvalidate(subfield,
2183 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2186 .Case<FVectorType>([&](
auto tpe) {
2187 auto tpex = tpe.getElementType();
2188 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2189 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2191 OpBuilder::InsertionGuard guard(builder);
2192 builder.setInsertionPointAfterValue(val);
2193 subindex = SubindexOp::create(builder, tpex, val, i);
2195 emitInvalidate(subindex, flow);
2223ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2224 bool isLeadingStmt) {
2225 auto token = getToken();
2226 auto kind = token.getKind();
2228 case FIRToken::lp_integer_add:
2229 case FIRToken::lp_integer_mul:
2230 case FIRToken::lp_integer_shr:
2231 case FIRToken::lp_integer_shl:
2232 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2241#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2243 case FIRToken::lp_##SPELLING: \
2244 if (requireFeature(VERSION, FEATURE)) \
2246 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2249#include "FIRTokenKinds.def"
2251 case FIRToken::l_brace_bar:
2253 return emitError(
"unexpected enumeration as start of statement");
2254 if (parseEnumExp(result))
2257 case FIRToken::lp_read:
2259 return emitError(
"unexpected read() as start of statement");
2260 if (parseRefRead(result))
2263 case FIRToken::lp_probe:
2265 return emitError(
"unexpected probe() as start of statement");
2266 if (parseProbe(result))
2269 case FIRToken::lp_rwprobe:
2271 return emitError(
"unexpected rwprobe() as start of statement");
2272 if (parseRWProbe(result))
2276 case FIRToken::langle_UInt:
2277 case FIRToken::langle_SInt: {
2280 bool isSigned = getToken().is(FIRToken::langle_SInt);
2283 if (parseWidth(width))
2287 if (parseIntegerLiteralExp(result, isSigned, width))
2292 case FIRToken::lp_UInt:
2293 if (parseIntegerLiteralExp(result,
false))
2296 case FIRToken::lp_SInt:
2297 if (parseIntegerLiteralExp(result,
true))
2300 case FIRToken::lp_String: {
2301 if (requireFeature({3, 1, 0},
"Strings"))
2303 locationProcessor.setLoc(getToken().
getLoc());
2304 consumeToken(FIRToken::lp_String);
2306 if (parseGetSpelling(spelling) ||
2307 parseToken(FIRToken::string,
2308 "expected string literal in String expression") ||
2309 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2312 result = moduleContext.getCachedConstant<StringConstantOp>(
2313 builder, attr, builder.getType<StringType>(), attr);
2316 case FIRToken::lp_Integer: {
2317 if (requireFeature({3, 1, 0},
"Integers"))
2319 locationProcessor.setLoc(getToken().
getLoc());
2320 consumeToken(FIRToken::lp_Integer);
2322 if (parseIntLit(value,
"expected integer literal in Integer expression") ||
2323 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2325 APSInt apint(value,
false);
2326 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2327 builder, IntegerAttr::get(getContext(), apint),
2328 builder.getType<FIntegerType>(), apint);
2331 case FIRToken::lp_Bool: {
2334 locationProcessor.setLoc(getToken().
getLoc());
2335 consumeToken(FIRToken::lp_Bool);
2337 if (consumeIf(FIRToken::kw_true))
2339 else if (consumeIf(FIRToken::kw_false))
2342 return emitError(
"expected true or false in Bool expression");
2343 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2345 auto attr = builder.getBoolAttr(value);
2346 result = moduleContext.getCachedConstant<BoolConstantOp>(
2347 builder, attr, builder.getType<BoolType>(), value);
2350 case FIRToken::lp_Double: {
2353 locationProcessor.setLoc(getToken().
getLoc());
2354 consumeToken(FIRToken::lp_Double);
2355 auto spelling = getTokenSpelling();
2356 if (parseToken(FIRToken::floatingpoint,
2357 "expected floating point in Double expression") ||
2358 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2363 if (!llvm::to_float(spelling, d))
2364 return emitError(
"invalid double");
2365 auto attr = builder.getF64FloatAttr(d);
2366 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2367 builder, attr, builder.getType<DoubleType>(), attr);
2370 case FIRToken::lp_List:
2371 case FIRToken::langle_List: {
2372 if (requireFeature({4, 0, 0},
"Lists"))
2375 return emitError(
"unexpected List<>() as start of statement");
2376 if (parseListExp(result))
2381 case FIRToken::lp_list_concat: {
2383 return emitError(
"unexpected list_create() as start of statement");
2384 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2389 case FIRToken::lp_path:
2391 return emitError(
"unexpected path() as start of statement");
2396 case FIRToken::lp_intrinsic:
2397 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2398 parseIntrinsicExp(result))
2402 case FIRToken::lp_cat:
2403 if (parseCatExp(result))
2407 case FIRToken::lp_string_concat:
2408 if (parseStringConcatExp(result))
2412 case FIRToken::lp_unsafe_domain_cast:
2414 parseUnsafeDomainCast(result))
2417 case FIRToken::lp_Unknown:
2418 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2419 parseUnknownProperty(result))
2425 case FIRToken::identifier:
2426 case FIRToken::literal_identifier:
2427 case FIRToken::kw_UInt:
2428 case FIRToken::kw_SInt:
2429 case FIRToken::kw_String:
2430 case FIRToken::kw_Integer:
2431 case FIRToken::kw_Bool:
2432 case FIRToken::kw_Double:
2433 case FIRToken::kw_List:
2436 auto loc = getToken().getLoc();
2438 if (parseId(name, message) ||
2439 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2443 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2446 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2451 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2452 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2453 parseOptionalInfo())
2456 locationProcessor.setLoc(loc);
2458 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2460 moduleContext.getUnbundledEntry(unbundledId);
2461 for (
auto elt : ubEntry)
2462 emitInvalidate(elt.second);
2470 StringRef fieldName;
2471 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2472 parseFieldId(fieldName,
"expected field name") ||
2473 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2481 case FIRToken::lp_shr:
2484 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2485 result = PadPrimOp::create(builder, result, 1);
2491 return parseOptionalExpPostscript(result);
2501ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2502 bool allowDynamic) {
2507 if (consumeIf(FIRToken::period)) {
2508 if (parsePostFixFieldId(result))
2515 if (consumeIf(FIRToken::l_square)) {
2516 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2517 if (parsePostFixIntSubscript(result))
2522 return emitError(
"subaccess not allowed here");
2523 if (parsePostFixDynamicSubscript(result))
2533template <
typename subop>
2535FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2537 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2543 auto baseType = cast<FIRRTLType>(base.getType());
2544 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2547 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2553 locationProcessor.setLoc(loc);
2554 OpBuilder::InsertionGuard guard(builder);
2555 builder.setInsertionPointAfterValue(base);
2556 auto op = subop::create(builder, resultType, base, indexNo);
2559 return value = op.getResult();
2566ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2567 auto loc = getToken().getLoc();
2568 SmallVector<StringRef, 3> fields;
2569 if (parseFieldIdSeq(fields,
"expected field name"))
2571 for (
auto fieldName : fields) {
2572 std::optional<unsigned> indexV;
2573 auto type = result.getType();
2574 if (
auto refTy = type_dyn_cast<RefType>(type))
2575 type = refTy.getType();
2576 if (
auto bundle = type_dyn_cast<BundleType>(type))
2577 indexV = bundle.getElementIndex(fieldName);
2578 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2579 indexV = bundle.getElementIndex(fieldName);
2580 else if (
auto klass = type_dyn_cast<ClassType>(type))
2581 indexV = klass.getElementIndex(fieldName);
2582 else if (
auto domain = type_dyn_cast<DomainType>(type))
2583 indexV = domain.getFieldIndex(fieldName);
2585 return emitError(loc,
2586 "subfield requires bundle, object, or domain operand ");
2588 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2589 << result.getType();
2590 auto indexNo = *indexV;
2592 FailureOr<Value> subResult;
2593 if (type_isa<RefType>(result.getType()))
2594 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2595 else if (type_isa<ClassType>(type))
2596 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2597 else if (type_isa<DomainType>(type))
2598 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2599 else if (type_isa<BundleType>(type))
2600 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2602 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2604 if (failed(subResult))
2606 result = *subResult;
2615ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2616 auto loc = getToken().getLoc();
2618 if (parseIntLit(indexNo,
"expected index") ||
2619 parseToken(FIRToken::r_square,
"expected ']'"))
2623 return emitError(loc,
"invalid index specifier"), failure();
2625 FailureOr<Value> subResult;
2626 if (type_isa<RefType>(result.getType()))
2627 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2628 else if (type_isa<FVectorType>(result.getType()))
2629 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2631 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2633 if (failed(subResult))
2635 result = *subResult;
2643ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2644 auto loc = getToken().getLoc();
2646 if (parseExp(index,
"expected subscript index expression") ||
2647 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2651 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2653 return emitError(
"expected base type for index expression");
2654 indexType = indexType.getPassiveType();
2655 locationProcessor.setLoc(loc);
2660 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2663 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2664 translateLocation(loc));
2669 auto op = SubaccessOp::create(builder, resultType, result, index);
2670 result = op.getResult();
2681FIRStmtParser::parseIntegerLiteralExp(Value &result,
bool isSigned,
2682 std::optional<int32_t> allocatedWidth) {
2683 auto loc = getToken().getLoc();
2686 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2691 int32_t width = allocatedWidth.value_or(-1);
2697 parseToken(FIRToken::l_paren,
"expected '(' in integer expression"))
2700 if (parseIntLit(value,
"expected integer value") ||
2701 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2706 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2708 IntegerType::SignednessSemantics signedness =
2709 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2711 if (!value.isZero())
2712 return emitError(loc,
"zero bit constant must be zero");
2713 value = value.trunc(0);
2714 }
else if (width != -1) {
2716 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2718 return emitError(loc,
"initializer too wide for declared width");
2719 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2723 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2724 auto attr = builder.getIntegerAttr(attrType, value);
2726 locationProcessor.setLoc(loc);
2727 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2732ParseResult FIRStmtParser::parseListExp(Value &result) {
2733 auto loc = getToken().getLoc();
2734 bool hasLAngle = getToken().is(FIRToken::langle_List);
2735 bool hasLParen = getToken().is(FIRToken::lp_List);
2740 if (!hasLAngle && parseToken(FIRToken::less,
"expected '<' in List type"))
2743 if (parsePropertyType(
elementType,
"expected List element type") ||
2744 parseToken(FIRToken::greater,
"expected '>' in List type"))
2747 auto listType = ListType::get(getContext(),
elementType);
2751 parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2754 SmallVector<Value, 3> operands;
2755 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2757 locationProcessor.setLoc(loc);
2758 if (parseExp(operand,
"expected expression in List expression"))
2762 if (!isa<AnyRefType>(elementType) ||
2763 !isa<ClassType>(operand.getType()))
2764 return emitError(loc,
"unexpected expression of type ")
2765 << operand.getType() <<
" in List expression of type "
2767 operand = ObjectAnyRefCastOp::create(builder, operand);
2770 operands.push_back(operand);
2775 locationProcessor.setLoc(loc);
2776 result = ListCreateOp::create(builder, listType, operands);
2781ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2782 consumeToken(FIRToken::lp_list_concat);
2784 auto loc = getToken().getLoc();
2786 SmallVector<Value, 3> operands;
2787 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2789 locationProcessor.setLoc(loc);
2790 if (parseExp(operand,
"expected expression in List concat expression"))
2793 if (!type_isa<ListType>(operand.getType()))
2794 return emitError(loc,
"unexpected expression of type ")
2795 << operand.getType() <<
" in List concat expression";
2798 type = type_cast<ListType>(operand.getType());
2800 if (operand.getType() != type)
2801 return emitError(loc,
"unexpected expression of type ")
2802 << operand.getType() <<
" in List concat expression of type "
2805 operands.push_back(operand);
2810 if (operands.empty())
2811 return emitError(loc,
"need at least one List to concatenate");
2813 locationProcessor.setLoc(loc);
2814 result = ListConcatOp::create(builder, type, operands);
2819ParseResult FIRStmtParser::parseCatExp(Value &result) {
2820 consumeToken(FIRToken::lp_cat);
2822 auto loc = getToken().getLoc();
2823 SmallVector<Value, 3> operands;
2824 std::optional<bool> isSigned;
2825 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2827 locationProcessor.setLoc(loc);
2828 auto operandLoc = getToken().getLoc();
2829 if (parseExp(operand,
"expected expression in cat expression"))
2831 if (!type_isa<IntType>(operand.getType())) {
2832 auto diag = emitError(loc,
"all operands must be Int type");
2833 diag.attachNote(translateLocation(operandLoc))
2834 <<
"non-integer operand is here";
2838 isSigned = type_isa<SIntType>(operand.getType());
2839 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2840 auto diag = emitError(loc,
"all operands must have same signedness");
2841 diag.attachNote(translateLocation(operandLoc))
2842 <<
"operand with different signedness is here";
2846 operands.push_back(operand);
2851 if (operands.size() != 2) {
2856 locationProcessor.setLoc(loc);
2857 result = CatPrimOp::create(builder, operands);
2862ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2863 consumeToken(FIRToken::lp_string_concat);
2865 auto loc = getToken().getLoc();
2866 SmallVector<Value, 3> operands;
2867 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2869 locationProcessor.setLoc(loc);
2870 if (parseExp(operand,
2871 "expected expression in string_concat expression"))
2873 if (!type_isa<StringType>(operand.getType()))
2874 return emitError(loc,
"all operands must be String type");
2875 operands.push_back(operand);
2880 if (operands.empty())
2881 return emitError(loc,
"need at least one String to concatenate");
2883 locationProcessor.setLoc(loc);
2884 auto type = StringType::get(builder.getContext());
2885 result = builder.create<StringConcatOp>(type, operands);
2889ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2890 consumeToken(FIRToken::lp_unsafe_domain_cast);
2892 auto loc = getToken().getLoc();
2894 if (parseExp(input,
"expected input"))
2897 SmallVector<Value> domains;
2898 if (consumeIf(FIRToken::comma)) {
2899 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2901 if (parseExp(domain,
"expected domain"))
2903 domains.push_back(domain);
2907 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2911 locationProcessor.setLoc(loc);
2912 result = UnsafeDomainCastOp::create(builder, input, domains);
2916ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2917 auto loc = getToken().getLoc();
2918 consumeToken(FIRToken::lp_Unknown);
2922 if (parsePropertyType(type,
"expected property type") ||
2923 parseToken(FIRToken::r_paren,
"expected ')' in unknown property"))
2926 locationProcessor.setLoc(loc);
2927 result = UnknownValueOp::create(builder, type);
2948std::optional<ParseResult>
2949FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2950 switch (getToken().getKind()) {
2953 return std::nullopt;
2955 case FIRToken::period:
2956 case FIRToken::l_square:
2957 case FIRToken::kw_is:
2958 case FIRToken::less_equal:
2964 auto loc = keyword.
getLoc();
2966 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2967 return ParseResult(failure());
2973 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2976 if (!consumeIf(FIRToken::period))
2977 return ParseResult(failure());
2979 StringRef fieldName;
2980 if (parseFieldId(fieldName,
"expected field name") ||
2981 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2982 return ParseResult(failure());
2986 if (parseOptionalExpPostscript(lhs))
2987 return ParseResult(failure());
2989 return parseLeadingExpStmt(lhs);
2995ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2998 if (getToken().isAny(FIRToken::eof, FIRToken::error))
3001 auto subIndent = getIndentation();
3002 if (!subIndent.has_value())
3003 return emitError(
"expected statement to be on its own line"), failure();
3005 if (*subIndent <= indent)
3009 if (parseSimpleStmt(*subIndent))
3014ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
3015 locationProcessor.startStatement();
3016 auto result = parseSimpleStmtImpl(stmtIndent);
3017 locationProcessor.endStatement(*
this);
3039ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
3040 auto kind = getToken().getKind();
3043 case FIRToken::kw_invalidate:
3044 case FIRToken::kw_connect:
3045 case FIRToken::kw_regreset:
3049 kind = FIRToken::identifier;
3056 case FIRToken::kw_attach:
3057 return parseAttach();
3058 case FIRToken::kw_infer:
3059 return parseMemPort(MemDirAttr::Infer);
3060 case FIRToken::kw_read:
3061 return parseMemPort(MemDirAttr::Read);
3062 case FIRToken::kw_write:
3063 return parseMemPort(MemDirAttr::Write);
3064 case FIRToken::kw_rdwr:
3065 return parseMemPort(MemDirAttr::ReadWrite);
3066 case FIRToken::kw_connect:
3067 return parseConnect();
3068 case FIRToken::kw_propassign:
3069 if (requireFeature({3, 1, 0},
"properties"))
3071 return parsePropAssign();
3072 case FIRToken::kw_invalidate:
3073 return parseInvalidate();
3074 case FIRToken::lp_printf:
3075 return parsePrintf();
3076 case FIRToken::lp_fprintf:
3077 return parseFPrintf();
3078 case FIRToken::lp_fflush:
3079 return parseFFlush();
3080 case FIRToken::kw_skip:
3082 case FIRToken::lp_stop:
3084 case FIRToken::lp_assert:
3085 return parseAssert();
3086 case FIRToken::lp_assume:
3087 return parseAssume();
3088 case FIRToken::lp_cover:
3089 return parseCover();
3090 case FIRToken::kw_when:
3091 return parseWhen(stmtIndent);
3092 case FIRToken::kw_match:
3093 return parseMatch(stmtIndent);
3094 case FIRToken::kw_domain:
3096 return parseDomainInstantiation();
3097 case FIRToken::kw_domain_define:
3098 return parseDomainDefine();
3099 case FIRToken::kw_define:
3100 return parseRefDefine();
3101 case FIRToken::lp_force:
3102 return parseRefForce();
3103 case FIRToken::lp_force_initial:
3104 return parseRefForceInitial();
3105 case FIRToken::lp_release:
3106 return parseRefRelease();
3107 case FIRToken::lp_release_initial:
3108 return parseRefReleaseInitial();
3109 case FIRToken::kw_group:
3110 if (requireFeature({3, 2, 0},
"optional groups") ||
3111 removedFeature({3, 3, 0},
"optional groups"))
3113 return parseLayerBlockOrGroup(stmtIndent);
3114 case FIRToken::kw_layerblock:
3115 if (requireFeature({3, 3, 0},
"layers"))
3117 return parseLayerBlockOrGroup(stmtIndent);
3118 case FIRToken::lp_intrinsic:
3119 if (requireFeature({4, 0, 0},
"generic intrinsics"))
3121 return parseIntrinsicStmt();
3125 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
3132 return parseLeadingExpStmt(lhs);
3136 case FIRToken::kw_inst:
3137 return parseInstance();
3138 case FIRToken::kw_instchoice:
3139 return parseInstanceChoice();
3140 case FIRToken::kw_object:
3141 return parseObject();
3142 case FIRToken::kw_cmem:
3143 return parseCombMem();
3144 case FIRToken::kw_smem:
3145 return parseSeqMem();
3146 case FIRToken::kw_mem:
3147 return parseMem(stmtIndent);
3148 case FIRToken::kw_node:
3150 case FIRToken::kw_wire:
3152 case FIRToken::kw_reg:
3153 return parseRegister(stmtIndent);
3154 case FIRToken::kw_regreset:
3155 return parseRegisterWithReset();
3156 case FIRToken::kw_contract:
3157 return parseContract(stmtIndent);
3161ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3163 SymbolRefAttr layerSym) {
3165 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3166 moduleContext, &blockToInsertInto);
3171 UnbundledValueRestorer x(moduleContext.unbundledValues);
3175 auto subParser = std::make_unique<FIRStmtParser>(
3176 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3180 auto stmtIndent = getIndentation();
3183 if (!stmtIndent.has_value())
3184 return subParser->parseSimpleStmt(indent);
3186 if (*stmtIndent <= indent)
3187 return emitError(
"statement must be indented more than previous statement"),
3191 return subParser->parseSimpleStmtBlock(indent);
3195ParseResult FIRStmtParser::parseAttach() {
3196 auto startTok = consumeToken(FIRToken::kw_attach);
3199 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3202 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3205 SmallVector<Value, 4> operands;
3206 operands.push_back({});
3207 if (parseExp(operands.back(),
"expected operand in attach"))
3210 while (consumeIf(FIRToken::comma)) {
3211 operands.push_back({});
3212 if (parseExp(operands.back(),
"expected operand in attach"))
3215 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3218 if (parseOptionalInfo())
3221 locationProcessor.setLoc(startTok.getLoc());
3222 AttachOp::create(builder, operands);
3229ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3230 auto startTok = consumeToken();
3231 auto startLoc = startTok.getLoc();
3235 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3241 Value memory, indexExp, clock;
3242 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3243 parseId(
id,
"expected result name") ||
3244 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3245 parseId(memName,
"expected memory name") ||
3246 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3247 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3248 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3249 parseExp(indexExp,
"expected index expression") ||
3250 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3251 parseToken(FIRToken::comma,
"expected ','") ||
3252 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3255 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3257 return emitError(startLoc,
3258 "memory port should have behavioral memory type");
3259 auto resultType = memVType.getElementType();
3261 ArrayAttr annotations = getConstants().emptyArrayAttr;
3262 locationProcessor.setLoc(startLoc);
3265 Value memoryPort, memoryData;
3267 OpBuilder::InsertionGuard guard(builder);
3268 builder.setInsertionPointAfterValue(memory);
3269 auto memoryPortOp = MemoryPortOp::create(
3270 builder, resultType, CMemoryPortType::get(getContext()), memory,
3271 direction,
id, annotations);
3272 memoryData = memoryPortOp.getResult(0);
3273 memoryPort = memoryPortOp.getResult(1);
3277 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3279 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3285ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3286 StringRef formatString,
3287 ArrayRef<Value> specOperands,
3288 StringAttr &formatStringResult,
3289 SmallVectorImpl<Value> &operands) {
3292 operands.append(specOperands.begin(), specOperands.end());
3293 formatStringResult =
3299 auto loc = translateLocation(formatStringLoc);
3302 formatStringResult, operands);
3307ParseResult FIRStmtParser::parsePrintf() {
3308 auto startTok = consumeToken(FIRToken::lp_printf);
3310 Value clock, condition;
3311 StringRef formatString;
3312 if (parseExp(clock,
"expected clock expression in printf") ||
3313 parseToken(FIRToken::comma,
"expected ','") ||
3314 parseExp(condition,
"expected condition in printf") ||
3315 parseToken(FIRToken::comma,
"expected ','"))
3318 auto formatStringLoc = getToken().getLoc();
3319 if (parseGetSpelling(formatString) ||
3320 parseToken(FIRToken::string,
"expected format string in printf"))
3323 SmallVector<Value, 4> specOperands;
3324 while (consumeIf(FIRToken::comma)) {
3325 specOperands.push_back({});
3326 if (parseExp(specOperands.back(),
"expected operand in printf"))
3331 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3332 parseOptionalName(name) || parseOptionalInfo())
3335 locationProcessor.setLoc(startTok.getLoc());
3337 StringAttr formatStrUnescaped;
3338 SmallVector<Value> operands;
3340 formatStrUnescaped, operands))
3343 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3349ParseResult FIRStmtParser::parseFPrintf() {
3352 auto startTok = consumeToken(FIRToken::lp_fprintf);
3354 Value clock, condition;
3355 StringRef outputFile, formatString;
3356 if (parseExp(clock,
"expected clock expression in fprintf") ||
3357 parseToken(FIRToken::comma,
"expected ','") ||
3358 parseExp(condition,
"expected condition in fprintf") ||
3359 parseToken(FIRToken::comma,
"expected ','"))
3362 auto outputFileLoc = getToken().getLoc();
3363 if (parseGetSpelling(outputFile) ||
3364 parseToken(FIRToken::string,
"expected output file in fprintf"))
3367 SmallVector<Value, 4> outputFileSpecOperands;
3368 while (consumeIf(FIRToken::comma)) {
3370 if (getToken().getKind() == FIRToken::string)
3372 outputFileSpecOperands.push_back({});
3373 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3377 auto formatStringLoc = getToken().getLoc();
3378 if (parseGetSpelling(formatString) ||
3379 parseToken(FIRToken::string,
"expected format string in printf"))
3382 SmallVector<Value, 4> specOperands;
3383 while (consumeIf(FIRToken::comma)) {
3384 specOperands.push_back({});
3385 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3390 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3391 parseOptionalName(name) || parseOptionalInfo())
3394 locationProcessor.setLoc(startTok.getLoc());
3396 StringAttr outputFileNameStrUnescaped;
3397 SmallVector<Value> outputFileOperands;
3399 outputFileNameStrUnescaped, outputFileOperands))
3402 StringAttr formatStrUnescaped;
3403 SmallVector<Value> operands;
3405 formatStrUnescaped, operands))
3408 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3409 outputFileOperands, formatStrUnescaped, operands, name);
3414ParseResult FIRStmtParser::parseFFlush() {
3418 auto startTok = consumeToken(FIRToken::lp_fflush);
3420 Value clock, condition;
3421 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3422 parseToken(FIRToken::comma,
"expected ','") ||
3423 parseExp(condition,
"expected condition in 'fflush'"))
3426 locationProcessor.setLoc(startTok.getLoc());
3427 StringAttr outputFileNameStrUnescaped;
3428 SmallVector<Value> outputFileOperands;
3430 if (consumeIf(FIRToken::comma)) {
3431 SmallVector<Value, 4> outputFileSpecOperands;
3432 auto outputFileLoc = getToken().getLoc();
3433 StringRef outputFile;
3434 if (parseGetSpelling(outputFile) ||
3435 parseToken(FIRToken::string,
"expected output file in fflush"))
3438 while (consumeIf(FIRToken::comma)) {
3439 outputFileSpecOperands.push_back({});
3440 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3445 outputFileNameStrUnescaped, outputFileOperands))
3449 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3450 parseOptionalInfo())
3453 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3454 outputFileOperands);
3459ParseResult FIRStmtParser::parseSkip() {
3460 auto startTok = consumeToken(FIRToken::kw_skip);
3464 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3467 if (parseOptionalInfo())
3470 locationProcessor.setLoc(startTok.getLoc());
3471 SkipOp::create(builder);
3476ParseResult FIRStmtParser::parseStop() {
3477 auto startTok = consumeToken(FIRToken::lp_stop);
3479 Value clock, condition;
3482 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3483 parseToken(FIRToken::comma,
"expected ','") ||
3484 parseExp(condition,
"expected condition in 'stop'") ||
3485 parseToken(FIRToken::comma,
"expected ','") ||
3486 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3487 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3488 parseOptionalName(name) || parseOptionalInfo())
3491 locationProcessor.setLoc(startTok.getLoc());
3492 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3498ParseResult FIRStmtParser::parseAssert() {
3499 auto startTok = consumeToken(FIRToken::lp_assert);
3501 Value clock, predicate, enable;
3502 StringRef formatString;
3504 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3505 parseToken(FIRToken::comma,
"expected ','") ||
3506 parseExp(predicate,
"expected predicate in 'assert'") ||
3507 parseToken(FIRToken::comma,
"expected ','") ||
3508 parseExp(enable,
"expected enable in 'assert'") ||
3509 parseToken(FIRToken::comma,
"expected ','") ||
3510 parseGetSpelling(formatString) ||
3511 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3514 SmallVector<Value, 4> operands;
3515 while (!consumeIf(FIRToken::r_paren)) {
3516 operands.push_back({});
3517 if (parseToken(FIRToken::comma,
"expected ','") ||
3518 parseExp(operands.back(),
"expected operand in 'assert'"))
3522 if (parseOptionalName(name) || parseOptionalInfo())
3525 locationProcessor.setLoc(startTok.getLoc());
3527 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3528 operands, name.getValue());
3533ParseResult FIRStmtParser::parseAssume() {
3534 auto startTok = consumeToken(FIRToken::lp_assume);
3536 Value clock, predicate, enable;
3537 StringRef formatString;
3539 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3540 parseToken(FIRToken::comma,
"expected ','") ||
3541 parseExp(predicate,
"expected predicate in 'assume'") ||
3542 parseToken(FIRToken::comma,
"expected ','") ||
3543 parseExp(enable,
"expected enable in 'assume'") ||
3544 parseToken(FIRToken::comma,
"expected ','") ||
3545 parseGetSpelling(formatString) ||
3546 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3549 SmallVector<Value, 4> operands;
3550 while (!consumeIf(FIRToken::r_paren)) {
3551 operands.push_back({});
3552 if (parseToken(FIRToken::comma,
"expected ','") ||
3553 parseExp(operands.back(),
"expected operand in 'assume'"))
3557 if (parseOptionalName(name) || parseOptionalInfo())
3560 locationProcessor.setLoc(startTok.getLoc());
3562 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3563 operands, name.getValue());
3568ParseResult FIRStmtParser::parseCover() {
3569 auto startTok = consumeToken(FIRToken::lp_cover);
3571 Value clock, predicate, enable;
3574 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3575 parseToken(FIRToken::comma,
"expected ','") ||
3576 parseExp(predicate,
"expected predicate in 'cover'") ||
3577 parseToken(FIRToken::comma,
"expected ','") ||
3578 parseExp(enable,
"expected enable in 'cover'") ||
3579 parseToken(FIRToken::comma,
"expected ','") ||
3580 parseGetSpelling(message) ||
3581 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3582 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3583 parseOptionalName(name) || parseOptionalInfo())
3586 locationProcessor.setLoc(startTok.getLoc());
3588 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3589 ValueRange{}, name.getValue());
3595ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3596 auto startTok = consumeToken(FIRToken::kw_when);
3600 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3604 if (parseExp(condition,
"expected condition in 'when'") ||
3605 parseToken(FIRToken::colon,
"expected ':' in when") ||
3606 parseOptionalInfo())
3609 locationProcessor.setLoc(startTok.getLoc());
3611 auto whenStmt = WhenOp::create(builder, condition,
false);
3614 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3618 if (getToken().isNot(FIRToken::kw_else))
3623 auto elseIndent = getIndentation();
3624 if (elseIndent && *elseIndent < whenIndent)
3627 consumeToken(FIRToken::kw_else);
3630 whenStmt.createElseRegion();
3636 if (getToken().is(FIRToken::kw_when)) {
3638 auto subParser = std::make_unique<FIRStmtParser>(
3639 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3642 return subParser->parseSimpleStmt(whenIndent);
3646 LocationAttr elseLoc;
3647 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3648 parseOptionalInfoLocator(elseLoc) ||
3649 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3658ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3659 auto startLoc = getToken().getLoc();
3660 locationProcessor.setLoc(startLoc);
3662 if (parseEnumType(type))
3666 auto enumType = type_dyn_cast<FEnumType>(type);
3668 return emitError(startLoc,
3669 "expected enumeration type in enumeration expression");
3672 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3673 parseId(tag,
"expected enumeration tag"))
3677 if (consumeIf(FIRToken::r_paren)) {
3680 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3681 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3682 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3683 input = ConstantOp::create(builder, type, attr);
3686 if (parseToken(FIRToken::comma,
"expected ','") ||
3687 parseExp(input,
"expected expression in enumeration value") ||
3688 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3692 value = FEnumCreateOp::create(builder, enumType, tag, input);
3700ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3701 auto startTok = consumeToken(FIRToken::kw_match);
3703 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3707 if (parseExp(input,
"expected expression in 'match'") ||
3708 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3709 parseOptionalInfo())
3712 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3714 return mlir::emitError(
3716 "expected enumeration type for 'match' statement, but got ")
3719 locationProcessor.setLoc(startTok.getLoc());
3721 SmallVector<Attribute> tags;
3722 SmallVector<std::unique_ptr<Region>> regions;
3724 auto tagLoc = getToken().getLoc();
3727 auto caseIndent = getIndentation();
3728 if (!caseIndent || *caseIndent <= matchIndent)
3732 StringRef tagSpelling;
3733 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3735 auto tagIndex = enumType.getElementIndex(tagSpelling);
3737 return emitError(tagLoc,
"tag ")
3738 << tagSpelling <<
" not a member of enumeration " << enumType;
3739 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3740 tags.push_back(tag);
3743 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3746 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3751 UnbundledValueRestorer x(moduleContext.unbundledValues);
3754 if (consumeIf(FIRToken::l_paren)) {
3755 StringAttr identifier;
3756 if (parseId(identifier,
"expected identifier for 'case' binding"))
3760 auto dataType = enumType.getElementType(*tagIndex);
3761 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3763 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3767 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3771 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3772 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3775 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3779 auto subParser = std::make_unique<FIRStmtParser>(
3780 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3782 if (subParser->parseSimpleStmtBlock(*caseIndent))
3786 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3793ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3794 auto loc = getToken().getLoc();
3797 if (parseId(
id,
"expected domain expression") ||
3798 moduleContext.lookupSymbolEntry(entry,
id, loc))
3801 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3803 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3804 parseFieldId(field,
"expected field name") ||
3805 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3809 if (parseOptionalExpPostscript(result,
false))
3812 auto type = result.getType();
3813 if (!type_isa<DomainType>(type))
3814 return emitError(loc) <<
"expected domain-type expression, got " << type;
3821ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3822 auto token = getToken().getKind();
3823 if (token == FIRToken::lp_probe)
3824 return parseProbe(result);
3825 if (token == FIRToken::lp_rwprobe)
3826 return parseRWProbe(result);
3831 return parseStaticRefExp(result, message);
3838ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3839 const Twine &message) {
3840 auto parseIdOrInstance = [&]() -> ParseResult {
3842 auto loc = getToken().getLoc();
3844 if (parseId(
id, message) ||
3845 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3849 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3852 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3855 StringRef fieldName;
3857 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3858 parseFieldId(fieldName,
"expected field name") ||
3859 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3861 return failure(parseIdOrInstance() ||
3862 parseOptionalExpPostscript(result,
false));
3873ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3875 const Twine &message) {
3876 auto loc = getToken().getLoc();
3880 if (parseId(
id, message) ||
3881 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3893 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3895 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3897 StringRef fieldName;
3898 auto loc = getToken().getLoc();
3899 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3900 parseFieldId(fieldName,
"expected field name"))
3905 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3906 for (
auto &elt : ubEntry) {
3907 if (elt.first == fieldAttr) {
3910 auto &instResult = elt.second;
3913 auto *defining = instResult.getDefiningOp();
3915 if (isa<WireOp>(defining)) {
3916 result = instResult;
3921 auto type = instResult.getType();
3925 auto annotations = getConstants().emptyArrayAttr;
3926 StringAttr sym = {};
3927 SmallString<64> name;
3928 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3929 locationProcessor.setLoc(loc);
3930 OpBuilder::InsertionGuard guard(builder);
3931 builder.setInsertionPoint(defining);
3933 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3935 auto bounceVal = bounce.getDataRaw();
3938 instResult.replaceAllUsesWith(bounceVal);
3941 builder.setInsertionPointAfter(defining);
3942 if (
foldFlow(instResult) == Flow::Source)
3949 result = instResult = bounce.getDataRaw();
3955 emitError(loc,
"use of invalid field name '")
3956 << fieldName <<
"' on bundle value";
3961 result = cast<Value>(symtabEntry);
3965 assert(isa<BlockArgument>(result) ||
3966 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3972 type = result.getType();
3974 if (consumeIf(FIRToken::period)) {
3975 SmallVector<StringRef, 3> fields;
3976 if (parseFieldIdSeq(fields,
"expected field name"))
3978 for (
auto fieldName : fields) {
3979 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3980 if (
auto index = bundle.getElementIndex(fieldName)) {
3981 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3982 type = bundle.getElementTypePreservingConst(*index);
3985 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3986 if (
auto index = bundle.getElementIndex(fieldName)) {
3987 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3988 type = bundle.getElementTypePreservingConst(*index);
3992 return emitError(loc,
"subfield requires bundle operand")
3993 <<
"got " << type <<
"\n";
3995 return emitError(loc,
3996 "unknown field '" + fieldName +
"' in bundle type ")
4001 if (consumeIf(FIRToken::l_square)) {
4002 auto loc = getToken().
getLoc();
4004 if (parseIntLit(index,
"expected index") ||
4005 parseToken(FIRToken::r_square,
"expected ']'"))
4009 return emitError(loc,
"invalid index specifier");
4011 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
4012 if ((
unsigned)index < vector.getNumElements()) {
4013 refResult = refResult.
getSubField(vector.getFieldID(index));
4014 type = vector.getElementTypePreservingConst();
4017 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
4018 if ((
unsigned)index < vector.getNumElements()) {
4019 refResult = refResult.
getSubField(vector.getFieldID(index));
4020 type = vector.getElementTypePreservingConst();
4024 return emitError(loc,
"subindex requires vector operand");
4026 return emitError(loc,
"out of range index '")
4027 << index <<
"' for vector type " << type;
4035ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4036 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4037 StringRef intrinsic;
4038 ArrayAttr parameters;
4041 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4042 parseOptionalParams(parameters))
4045 if (consumeIf(FIRToken::colon)) {
4046 if (
parseType(type,
"expected intrinsic return type"))
4048 }
else if (!isStatement)
4049 return emitError(
"expected ':' in intrinsic expression");
4051 SmallVector<Value> operands;
4052 auto loc = startTok.getLoc();
4053 if (consumeIf(FIRToken::comma)) {
4054 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4056 if (parseExp(operand,
"expected operand in intrinsic"))
4058 operands.push_back(operand);
4059 locationProcessor.setLoc(loc);
4064 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4069 if (parseOptionalInfo())
4072 locationProcessor.setLoc(loc);
4074 auto op = GenericIntrinsicOp::create(
4075 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4077 result = op.getResult();
4082ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4083 if (!consumeIf(FIRToken::less))
4086 SmallVector<Attribute, 8> parameters;
4087 SmallPtrSet<StringAttr, 8> seen;
4088 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4092 if (parseParameter(name, value, loc))
4094 auto typedValue = dyn_cast<TypedAttr>(value);
4096 return emitError(loc)
4097 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4098 if (!seen.insert(name).second)
4099 return emitError(loc,
"redefinition of parameter '" +
4100 name.getValue() +
"'");
4101 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4106 resultParameters = ArrayAttr::get(getContext(), parameters);
4112ParseResult FIRStmtParser::parsePathExp(Value &result) {
4113 auto startTok = consumeToken(FIRToken::lp_path);
4114 locationProcessor.setLoc(startTok.getLoc());
4116 if (parseGetSpelling(target) ||
4117 parseToken(FIRToken::string,
4118 "expected target string in path expression") ||
4119 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4121 result = UnresolvedPathOp::create(
4127ParseResult FIRStmtParser::parseDomainInstantiation() {
4128 auto startTok = consumeToken(FIRToken::kw_domain);
4129 auto startLoc = startTok.getLoc();
4132 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4135 locationProcessor.setLoc(startTok.getLoc());
4137 StringAttr instanceName;
4138 StringAttr domainKind;
4141 parseId(instanceName,
"expected domain instance name") ||
4142 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4143 parseId(domainKind,
"expected domain type name"))
4148 const auto &domainMap = getConstants().domainMap;
4149 auto lookup = domainMap.find(domainKind.getValue());
4150 if (lookup == domainMap.end())
4151 return emitError(startTok.getLoc())
4152 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4154 auto domainType = DomainType::getFromDomainOp(lookup->second);
4157 SmallVector<Value> fieldValues;
4158 if (consumeIf(FIRToken::l_paren)) {
4160 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4162 if (parseExp(value,
"expected field value expression"))
4164 fieldValues.push_back(value);
4170 if (parseOptionalInfo())
4173 locationProcessor.setLoc(startLoc);
4175 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4178 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4183ParseResult FIRStmtParser::parseDomainDefine() {
4184 auto startTok = consumeToken(FIRToken::kw_domain_define);
4185 auto startLoc = startTok.getLoc();
4186 locationProcessor.setLoc(startLoc);
4190 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4191 parseDomainExp(src) || parseOptionalInfo())
4199ParseResult FIRStmtParser::parseRefDefine() {
4200 auto startTok = consumeToken(FIRToken::kw_define);
4203 if (parseStaticRefExp(target,
4204 "expected static reference expression in 'define'") ||
4205 parseToken(FIRToken::equal,
4206 "expected '=' after define reference expression") ||
4207 parseRefExp(src,
"expected reference expression in 'define'") ||
4208 parseOptionalInfo())
4212 if (!type_isa<RefType>(target.getType()))
4213 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4214 "'define' target (LHS), got ")
4215 << target.getType();
4216 if (!type_isa<RefType>(src.getType()))
4217 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4218 "'define' source (RHS), got ")
4223 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4224 return emitError(startTok.getLoc(),
4225 "cannot define into a sub-element of a reference");
4227 locationProcessor.setLoc(startTok.getLoc());
4230 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4231 << target.getType() <<
" with incompatible reference of type "
4241ParseResult FIRStmtParser::parseRefRead(Value &result) {
4242 auto startTok = consumeToken(FIRToken::lp_read);
4245 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4246 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4249 locationProcessor.setLoc(startTok.getLoc());
4252 if (!type_isa<RefType>(ref.getType()))
4253 return emitError(startTok.getLoc(),
4254 "expected reference-type expression in 'read', got ")
4257 result = RefResolveOp::create(builder, ref);
4263ParseResult FIRStmtParser::parseProbe(Value &result) {
4264 auto startTok = consumeToken(FIRToken::lp_probe);
4267 if (parseStaticRefExp(staticRef,
4268 "expected static reference expression in 'probe'") ||
4269 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4272 locationProcessor.setLoc(startTok.getLoc());
4275 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4276 return emitError(startTok.getLoc(),
4277 "expected base-type expression in 'probe', got ")
4278 << staticRef.getType();
4282 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4283 MemoryDebugPortOp, MemoryPortAccessOp>(
4284 staticRef.getDefiningOp()))
4285 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4287 result = RefSendOp::create(builder, staticRef);
4293ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4294 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4297 Type parsedTargetType;
4298 if (parseRWProbeStaticRefExp(
4299 staticRef, parsedTargetType,
4300 "expected static reference expression in 'rwprobe'") ||
4301 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4304 locationProcessor.setLoc(startTok.getLoc());
4310 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4312 return emitError(startTok.getLoc(),
4313 "expected base-type expression in 'rwprobe', got ")
4314 << parsedTargetType;
4317 auto *definingOp = root.getDefiningOp();
4319 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4320 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4321 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4325 return emitError(startTok.getLoc(),
"cannot force target of type ")
4329 auto op = RWProbeOp::create(builder, forceableType,
4330 getConstants().placeholderInnerRef);
4337ParseResult FIRStmtParser::parseRefForce() {
4338 auto startTok = consumeToken(FIRToken::lp_force);
4340 Value clock, pred, dest, src;
4341 if (parseExp(clock,
"expected clock expression in force") ||
4342 parseToken(FIRToken::comma,
"expected ','") ||
4343 parseExp(pred,
"expected predicate expression in force") ||
4344 parseToken(FIRToken::comma,
"expected ','") ||
4345 parseRefExp(dest,
"expected destination reference expression in force") ||
4346 parseToken(FIRToken::comma,
"expected ','") ||
4347 parseExp(src,
"expected source expression in force") ||
4348 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4349 parseOptionalInfo())
4353 auto ref = type_dyn_cast<RefType>(dest.getType());
4354 if (!ref || !ref.getForceable())
4357 "expected rwprobe-type expression for force destination, got ")
4359 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4361 return emitError(startTok.getLoc(),
4362 "expected base-type for force source, got ")
4364 if (!srcBaseType.isPassive())
4365 return emitError(startTok.getLoc(),
4366 "expected passive value for force source, got ")
4369 locationProcessor.setLoc(startTok.getLoc());
4372 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4373 if (noConstSrcType != ref.getType()) {
4375 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4377 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4379 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4380 << src.getType() <<
" cannot target destination "
4384 RefForceOp::create(builder, clock, pred, dest, src);
4390ParseResult FIRStmtParser::parseRefForceInitial() {
4391 auto startTok = consumeToken(FIRToken::lp_force_initial);
4395 dest,
"expected destination reference expression in force_initial") ||
4396 parseToken(FIRToken::comma,
"expected ','") ||
4397 parseExp(src,
"expected source expression in force_initial") ||
4398 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4399 parseOptionalInfo())
4403 auto ref = type_dyn_cast<RefType>(dest.getType());
4404 if (!ref || !ref.getForceable())
4405 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4406 "force_initial destination, got ")
4408 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4410 return emitError(startTok.getLoc(),
4411 "expected base-type expression for force_initial "
4414 if (!srcBaseType.isPassive())
4415 return emitError(startTok.getLoc(),
4416 "expected passive value for force_initial source, got ")
4419 locationProcessor.setLoc(startTok.getLoc());
4422 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4423 if (noConstSrcType != ref.getType()) {
4425 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4427 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4429 return emitError(startTok.getLoc(),
4430 "incompatible force_initial source of type ")
4431 << src.getType() <<
" cannot target destination "
4435 auto value = APInt::getAllOnes(1);
4436 auto type = UIntType::get(builder.getContext(), 1);
4437 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4438 value.getBitWidth(),
4439 IntegerType::Unsigned),
4441 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4442 RefForceInitialOp::create(builder, pred, dest, src);
4448ParseResult FIRStmtParser::parseRefRelease() {
4449 auto startTok = consumeToken(FIRToken::lp_release);
4451 Value clock, pred, dest;
4452 if (parseExp(clock,
"expected clock expression in release") ||
4453 parseToken(FIRToken::comma,
"expected ','") ||
4454 parseExp(pred,
"expected predicate expression in release") ||
4455 parseToken(FIRToken::comma,
"expected ','") ||
4457 "expected destination reference expression in release") ||
4458 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4459 parseOptionalInfo())
4463 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4464 !ref || !ref.getForceable())
4467 "expected rwprobe-type expression for release destination, got ")
4470 locationProcessor.setLoc(startTok.getLoc());
4472 RefReleaseOp::create(builder, clock, pred, dest);
4478ParseResult FIRStmtParser::parseRefReleaseInitial() {
4479 auto startTok = consumeToken(FIRToken::lp_release_initial);
4484 "expected destination reference expression in release_initial") ||
4485 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4486 parseOptionalInfo())
4490 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4491 !ref || !ref.getForceable())
4492 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4493 "release_initial destination, got ")
4496 locationProcessor.setLoc(startTok.getLoc());
4498 auto value = APInt::getAllOnes(1);
4499 auto type = UIntType::get(builder.getContext(), 1);
4500 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4501 value.getBitWidth(),
4502 IntegerType::Unsigned),
4504 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4505 RefReleaseInitialOp::create(builder, pred, dest);
4511ParseResult FIRStmtParser::parseConnect() {
4512 auto startTok = consumeToken(FIRToken::kw_connect);
4513 auto loc = startTok.getLoc();
4516 if (parseExp(lhs,
"expected connect expression") ||
4517 parseToken(FIRToken::comma,
"expected ','") ||
4518 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4521 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4522 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4523 if (!lhsType || !rhsType)
4524 return emitError(loc,
"cannot connect reference or property types");
4526 if (lhsType.containsReference() || rhsType.containsReference())
4527 return emitError(loc,
"cannot connect types containing references");
4530 return emitError(loc,
"cannot connect non-equivalent type ")
4531 << rhsType <<
" to " << lhsType;
4533 locationProcessor.setLoc(loc);
4539ParseResult FIRStmtParser::parsePropAssign() {
4540 auto startTok = consumeToken(FIRToken::kw_propassign);
4541 auto loc = startTok.getLoc();
4544 if (parseExp(lhs,
"expected propassign expression") ||
4545 parseToken(FIRToken::comma,
"expected ','") ||
4546 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4549 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4550 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4551 if (!lhsType || !rhsType)
4552 return emitError(loc,
"can only propassign property types");
4553 locationProcessor.setLoc(loc);
4554 if (lhsType != rhsType) {
4556 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4557 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4559 return emitError(loc,
"cannot propassign non-equivalent type ")
4560 << rhsType <<
" to " << lhsType;
4562 PropAssignOp::create(builder, lhs, rhs);
4567ParseResult FIRStmtParser::parseInvalidate() {
4568 auto startTok = consumeToken(FIRToken::kw_invalidate);
4573 auto loc = getToken().getLoc();
4575 if (parseId(
id,
"expected static reference expression") ||
4576 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4581 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4582 if (parseOptionalExpPostscript(lhs,
false) ||
4583 parseOptionalInfo())
4586 locationProcessor.setLoc(startTok.getLoc());
4587 emitInvalidate(lhs);
4594 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4596 if (getToken().isNot(FIRToken::period)) {
4597 locationProcessor.setLoc(loc);
4599 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4601 for (
auto elt : ubEntry)
4602 emitInvalidate(elt.second);
4608 StringRef fieldName;
4609 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4610 parseFieldId(fieldName,
"expected field name") ||
4611 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4615 if (parseOptionalExpPostscript(lhs,
false) ||
4616 parseOptionalInfo())
4619 locationProcessor.setLoc(startTok.getLoc());
4620 emitInvalidate(lhs);
4624ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4626 auto startTok = consumeToken();
4627 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4628 "consumed an unexpected token");
4629 auto loc = startTok.getLoc();
4632 if (parseId(
id,
"expected layer identifer") ||
4633 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4634 parseOptionalInfo())
4637 locationProcessor.setLoc(loc);
4639 StringRef rootLayer;
4640 SmallVector<FlatSymbolRefAttr> nestedLayers;
4644 rootLayer = layerSym.getRootReference();
4645 auto nestedRefs = layerSym.getNestedReferences();
4646 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4647 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4650 auto layerBlockOp = LayerBlockOp::create(
4652 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4653 layerBlockOp->getRegion(0).push_back(
new Block());
4655 if (getIndentation() > indent)
4656 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4657 layerBlockOp.getLayerName()))
4665ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4666 auto loc = getToken().getLoc();
4669 if (consumeIf(FIRToken::kw_is)) {
4670 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4671 parseOptionalInfo())
4674 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4677 locationProcessor.setLoc(loc);
4678 emitInvalidate(lhs);
4682 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4685 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4689 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4692 locationProcessor.setLoc(loc);
4694 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4695 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4696 if (!lhsType || !rhsType)
4697 return emitError(loc,
"cannot connect reference or property types");
4699 if (lhsType.containsReference() || rhsType.containsReference())
4700 return emitError(loc,
"cannot connect types containing references");
4703 return emitError(loc,
"cannot connect non-equivalent type ")
4704 << rhsType <<
" to " << lhsType;
4713ParseResult FIRStmtParser::parseInstance() {
4714 auto startTok = consumeToken(FIRToken::kw_inst);
4718 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4722 StringRef moduleName;
4723 if (parseId(
id,
"expected instance name") ||
4724 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4725 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4728 locationProcessor.setLoc(startTok.getLoc());
4731 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4732 if (!referencedModule)
4735 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4737 auto annotations = getConstants().emptyArrayAttr;
4738 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4740 hw::InnerSymAttr sym = {};
4741 auto result = InstanceOp::create(
4742 builder, referencedModule,
id, NameKindEnum::InterestingName,
4743 annotations.getValue(), portAnnotations,
false,
false, sym);
4749 unbundledValueEntry.reserve(modulePorts.size());
4750 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4751 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4755 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4756 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4757 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4762ParseResult FIRStmtParser::parseInstanceChoice() {
4763 auto startTok = consumeToken(FIRToken::kw_instchoice);
4764 SMLoc loc = startTok.getLoc();
4767 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4774 StringRef defaultModuleName;
4775 StringRef optionGroupName;
4776 if (parseId(
id,
"expected instance name") ||
4777 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4778 parseId(defaultModuleName,
"expected module name") ||
4779 parseToken(FIRToken::comma,
"expected ','") ||
4780 parseId(optionGroupName,
"expected option group name") ||
4781 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4782 parseOptionalInfo())
4785 locationProcessor.setLoc(startTok.getLoc());
4789 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4793 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4796 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4798 return emitError(loc,
4799 "use of undefined option group '" + optionGroupName +
"'");
4801 auto baseIndent = getIndentation();
4802 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4803 while (getIndentation() == baseIndent) {
4805 StringRef caseModuleName;
4806 if (parseId(caseId,
"expected a case identifier") ||
4807 parseToken(FIRToken::equal_greater,
4808 "expected '=> in instance choice definition") ||
4809 parseId(caseModuleName,
"expected module name"))
4812 auto caseModule = getReferencedModule(loc, caseModuleName);
4816 for (
const auto &[defaultPort, casePort] :
4817 llvm::zip(modulePorts, caseModule.getPorts())) {
4818 if (defaultPort.name != casePort.name)
4819 return emitError(loc,
"instance case module port '")
4820 << casePort.name.getValue()
4821 <<
"' does not match the default module port '"
4822 << defaultPort.name.getValue() <<
"'";
4823 if (defaultPort.type != casePort.type)
4824 return emitError(loc,
"instance case port '")
4825 << casePort.name.getValue()
4826 <<
"' type does not match the default module port";
4830 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4832 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4833 caseModules.emplace_back(optionCase, caseModule);
4836 auto annotations = getConstants().emptyArrayAttr;
4837 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4841 auto result = InstanceChoiceOp::create(
4842 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4843 annotations.getValue(), portAnnotations, sym);
4847 unbundledValueEntry.reserve(modulePorts.size());
4848 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4849 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4851 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4852 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4853 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4856FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4857 StringRef moduleName) {
4858 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4859 if (!referencedModule) {
4861 "use of undefined module name '" + moduleName +
"' in instance");
4864 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4865 emitError(loc,
"cannot create instance of class '" + moduleName +
4866 "', did you mean object?");
4869 return referencedModule;
4873ParseResult FIRStmtParser::parseObject() {
4874 auto startTok = consumeToken(FIRToken::kw_object);
4878 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4885 StringRef className;
4886 if (parseId(
id,
"expected object name") ||
4887 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4888 parseId(className,
"expected class name") || parseOptionalInfo())
4891 locationProcessor.setLoc(startTok.getLoc());
4894 const auto &classMap = getConstants().classMap;
4895 auto lookup = classMap.find(className);
4896 if (lookup == classMap.end())
4897 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4898 className +
"' in object");
4899 auto referencedClass = lookup->getSecond();
4900 auto result = ObjectOp::create(builder, referencedClass,
id);
4901 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4905ParseResult FIRStmtParser::parseCombMem() {
4907 auto startTok = consumeToken(FIRToken::kw_cmem);
4911 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4916 if (parseId(
id,
"expected cmem name") ||
4917 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4918 parseType(type,
"expected cmem type") || parseOptionalInfo())
4921 locationProcessor.setLoc(startTok.getLoc());
4924 auto vectorType = type_dyn_cast<FVectorType>(type);
4926 return emitError(
"cmem requires vector type");
4928 auto annotations = getConstants().emptyArrayAttr;
4929 StringAttr sym = {};
4930 auto result = CombMemOp::create(
4931 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4932 NameKindEnum::InterestingName, annotations, sym);
4933 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4937ParseResult FIRStmtParser::parseSeqMem() {
4939 auto startTok = consumeToken(FIRToken::kw_smem);
4943 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4948 RUWBehavior ruw = RUWBehavior::Undefined;
4950 if (parseId(
id,
"expected smem name") ||
4951 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4955 if (consumeIf(FIRToken::comma)) {
4960 if (parseOptionalInfo()) {
4964 locationProcessor.setLoc(startTok.getLoc());
4967 auto vectorType = type_dyn_cast<FVectorType>(type);
4969 return emitError(
"smem requires vector type");
4971 auto annotations = getConstants().emptyArrayAttr;
4972 StringAttr sym = {};
4973 auto result = SeqMemOp::create(
4974 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4975 id, NameKindEnum::InterestingName, annotations, sym);
4976 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4988ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4989 auto startTok = consumeToken(FIRToken::kw_mem);
4993 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4997 if (parseId(
id,
"expected mem name") ||
4998 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
5002 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5003 RUWBehavior ruw = RUWBehavior::Undefined;
5005 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5009 auto nextIndent = getIndentation();
5010 if (!nextIndent || *nextIndent <= memIndent)
5013 auto spelling = getTokenSpelling();
5014 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
5015 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
5018 if (spelling ==
"data-type") {
5020 return emitError(
"'mem' type specified multiple times"), failure();
5022 if (
parseType(type,
"expected type in data-type declaration"))
5026 if (spelling ==
"depth") {
5027 if (parseIntLit(depth,
"expected integer in depth specification"))
5031 if (spelling ==
"read-latency") {
5032 if (parseIntLit(readLatency,
"expected integer latency"))
5036 if (spelling ==
"write-latency") {
5037 if (parseIntLit(writeLatency,
"expected integer latency"))
5041 if (spelling ==
"read-under-write") {
5042 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5043 FIRToken::kw_undefined))
5044 return emitError(
"expected specifier"), failure();
5046 if (parseOptionalRUW(ruw))
5051 MemOp::PortKind portKind;
5052 if (spelling ==
"reader")
5053 portKind = MemOp::PortKind::Read;
5054 else if (spelling ==
"writer")
5055 portKind = MemOp::PortKind::Write;
5056 else if (spelling ==
"readwriter")
5057 portKind = MemOp::PortKind::ReadWrite;
5059 return emitError(
"unexpected field in 'mem' declaration"), failure();
5062 if (parseId(portName,
"expected port name"))
5064 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5066 return emitError(
"unexpected type, must be base type");
5067 ports.push_back({builder.getStringAttr(portName),
5068 MemOp::getTypeForPort(depth, baseType, portKind)});
5070 while (!getIndentation().has_value()) {
5071 if (parseId(portName,
"expected port name"))
5073 ports.push_back({builder.getStringAttr(portName),
5074 MemOp::getTypeForPort(depth, baseType, portKind)});
5085 llvm::array_pod_sort(ports.begin(), ports.end(),
5086 [](
const std::pair<StringAttr, Type> *lhs,
5087 const std::pair<StringAttr, Type> *rhs) ->
int {
5088 return lhs->first.getValue().compare(
5089 rhs->first.getValue());
5092 auto annotations = getConstants().emptyArrayAttr;
5093 SmallVector<Attribute, 4> resultNames;
5094 SmallVector<Type, 4> resultTypes;
5095 SmallVector<Attribute, 4> resultAnnotations;
5096 for (
auto p : ports) {
5097 resultNames.push_back(p.first);
5098 resultTypes.push_back(p.second);
5099 resultAnnotations.push_back(annotations);
5102 locationProcessor.setLoc(startTok.getLoc());
5104 auto result = MemOp::create(
5105 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5106 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5107 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5108 MemoryInitAttr(), StringAttr());
5111 unbundledValueEntry.reserve(result.getNumResults());
5112 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5113 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5115 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5116 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5117 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5121ParseResult FIRStmtParser::parseNode() {
5122 auto startTok = consumeToken(FIRToken::kw_node);
5126 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5131 if (parseId(
id,
"expected node name") ||
5132 parseToken(FIRToken::equal,
"expected '=' in node") ||
5133 parseExp(initializer,
"expected expression for node") ||
5134 parseOptionalInfo())
5137 locationProcessor.setLoc(startTok.getLoc());
5149 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5150 auto initializerBaseType =
5151 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5152 if (type_isa<AnalogType>(initializerType) ||
5153 !(initializerBaseType && initializerBaseType.isPassive())) {
5154 emitError(startTok.getLoc())
5155 <<
"Node cannot be analog and must be passive or passive under a flip "
5156 << initializer.getType();
5160 auto annotations = getConstants().emptyArrayAttr;
5161 StringAttr sym = {};
5163 auto result = NodeOp::create(builder, initializer,
id,
5164 NameKindEnum::InterestingName, annotations, sym);
5165 return moduleContext.addSymbolEntry(
id, result.getResult(),
5170ParseResult FIRStmtParser::parseWire() {
5171 auto startTok = consumeToken(FIRToken::kw_wire);
5175 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5180 if (parseId(
id,
"expected wire name") ||
5181 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5186 SmallVector<Value> domains;
5187 if (consumeIf(FIRToken::kw_domains)) {
5191 if (parseToken(FIRToken::l_square,
"expected '[' after 'domains'"))
5194 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5195 StringRef domainName;
5196 auto domainLoc = getToken().getLoc();
5197 if (parseId(domainName,
"expected domain name"))
5202 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5207 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5210 if (!isa<DomainType>(domainValue.getType()))
5211 return emitError(domainLoc)
5212 <<
"'" << domainName <<
"' is not a domain";
5214 domains.push_back(domainValue);
5220 if (parseOptionalInfo())
5223 locationProcessor.setLoc(startTok.getLoc());
5225 auto annotations = getConstants().emptyArrayAttr;
5226 StringAttr sym = {};
5229 auto namekind = isa<PropertyType, RefType>(type)
5230 ? NameKindEnum::DroppableName
5231 : NameKindEnum::InterestingName;
5233 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym,
5235 return moduleContext.addSymbolEntry(
id, result.getResult(),
5249ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5250 auto startTok = consumeToken(FIRToken::kw_reg);
5254 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5263 if (parseId(
id,
"expected reg name") ||
5264 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5266 parseToken(FIRToken::comma,
"expected ','") ||
5267 parseExp(clock,
"expected expression for register clock"))
5270 if (!type_isa<FIRRTLBaseType>(type))
5271 return emitError(startTok.getLoc(),
"register must have base type");
5274 Value resetSignal, resetValue;
5275 if (consumeIf(FIRToken::kw_with)) {
5276 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5279 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5287 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5289 auto indent = getIndentation();
5290 if (!indent || *indent <= regIndent)
5291 if (!hasExtraLParen)
5292 return emitError(
"expected indented reset specifier in reg"), failure();
5294 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5295 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5296 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5297 parseExp(resetSignal,
"expected expression for reset signal") ||
5298 parseToken(FIRToken::comma,
"expected ','"))
5306 if (getTokenSpelling() ==
id) {
5308 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5310 resetSignal = Value();
5312 if (parseExp(resetValue,
"expected expression for reset value") ||
5313 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5317 if (hasExtraLParen &&
5318 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5324 if (parseOptionalInfo())
5327 locationProcessor.setLoc(startTok.getLoc());
5329 ArrayAttr annotations = getConstants().emptyArrayAttr;
5331 StringAttr sym = {};
5334 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5335 NameKindEnum::InterestingName, annotations, sym)
5338 result = RegOp::create(builder, type, clock,
id,
5339 NameKindEnum::InterestingName, annotations, sym)
5341 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5349ParseResult FIRStmtParser::parseRegisterWithReset() {
5350 auto startTok = consumeToken(FIRToken::kw_regreset);
5354 Value clock, resetSignal, resetValue;
5356 if (parseId(
id,
"expected reg name") ||
5357 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5359 parseToken(FIRToken::comma,
"expected ','") ||
5360 parseExp(clock,
"expected expression for register clock") ||
5361 parseToken(FIRToken::comma,
"expected ','") ||
5362 parseExp(resetSignal,
"expected expression for register reset") ||
5363 parseToken(FIRToken::comma,
"expected ','") ||
5364 parseExp(resetValue,
"expected expression for register reset value") ||
5365 parseOptionalInfo())
5368 if (!type_isa<FIRRTLBaseType>(type))
5369 return emitError(startTok.getLoc(),
"register must have base type");
5371 locationProcessor.setLoc(startTok.getLoc());
5374 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5375 NameKindEnum::InterestingName,
5376 getConstants().emptyArrayAttr, StringAttr{})
5379 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5384ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5388 auto startTok = consumeToken(FIRToken::kw_contract);
5391 SmallVector<StringRef> ids;
5392 SmallVector<SMLoc> locs;
5393 SmallVector<Value> values;
5394 SmallVector<Type> types;
5395 if (!consumeIf(FIRToken::colon)) {
5396 auto parseContractId = [&] {
5398 locs.push_back(getToken().
getLoc());
5399 if (parseId(
id,
"expected contract result name"))
5404 auto parseContractValue = [&] {
5406 if (parseExp(value,
"expected expression for contract result"))
5408 values.push_back(value);
5409 types.push_back(value.getType());
5412 if (parseListUntil(FIRToken::equal, parseContractId) ||
5413 parseListUntil(FIRToken::colon, parseContractValue))
5416 if (parseOptionalInfo())
5420 if (ids.size() != values.size())
5421 return emitError(startTok.getLoc())
5422 <<
"contract requires same number of results and expressions; got "
5423 << ids.size() <<
" results and " << values.size()
5424 <<
" expressions instead";
5426 locationProcessor.setLoc(startTok.getLoc());
5430 auto contract = ContractOp::create(builder, types, values);
5431 auto &block = contract.getBody().emplaceBlock();
5435 FIRModuleContext::ContextScope scope(moduleContext, &block);
5436 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5437 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5438 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5441 if (getIndentation() > blockIndent)
5442 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5447 for (
auto [
id, loc, value, result] :
5448 llvm::zip(ids, locs, values, contract.getResults())) {
5450 moduleContext.removeSymbolEntry(
id);
5451 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5464struct FIRCircuitParser :
public FIRParser {
5465 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5467 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5470 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5471 mlir::TimingScope &ts);
5476 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5477 SmallVectorImpl<Attribute> &attrs);
5479 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5481 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5482 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5483 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5484 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5485 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5486 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5487 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5488 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5490 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5492 ParseResult parseLayerName(SymbolRefAttr &result);
5493 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5494 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5495 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5496 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5497 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5498 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5499 ArrayAttr &knownLayers,
5500 ArrayAttr &externalRequirements);
5502 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5503 SmallVectorImpl<SMLoc> &resultPortLocs,
5507 ParseResult skipToModuleEnd(
unsigned indent);
5509 ParseResult parseTypeDecl();
5511 ParseResult parseOptionDecl(CircuitOp circuit);
5513 ParseResult parseLayer(CircuitOp circuit);
5515 ParseResult resolveDomains(
5516 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5517 const DenseMap<Attribute, size_t> &nameToIndex,
5518 SmallVectorImpl<Attribute> &domainsByIndex);
5521 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5522 const DenseMap<Attribute, size_t> &nameToIndex);
5524 struct DeferredModuleToParse {
5525 FModuleLike moduleOp;
5526 SmallVector<SMLoc> portLocs;
5531 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5532 DeferredModuleToParse &deferredModule,
5533 InnerSymFixups &fixups);
5535 SmallVector<DeferredModuleToParse, 0> deferredModules;
5537 SmallVector<InnerSymFixups, 0> moduleFixups;
5541 ModuleOp mlirModule;
5546FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5547 SmallVectorImpl<Attribute> &attrs) {
5549 auto annotations = json::parse(annotationsStr);
5550 if (
auto err = annotations.takeError()) {
5551 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5552 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5553 diag.attachNote() <<
a.message();
5558 json::Path::Root root;
5559 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5562 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5563 std::string jsonErrorMessage =
5564 "See inline comments for problem area in JSON:\n";
5565 llvm::raw_string_ostream
s(jsonErrorMessage);
5566 root.printErrorContext(annotations.get(), s);
5567 diag.attachNote() << jsonErrorMessage;
5574ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5576 SmallVector<StringRef> strings;
5579 if (parseId(name,
"expected layer name"))
5581 strings.push_back(name);
5582 }
while (consumeIf(FIRToken::period));
5584 SmallVector<FlatSymbolRefAttr> nested;
5585 nested.reserve(strings.size() - 1);
5586 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5587 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5589 result = SymbolRefAttr::get(
context, strings[0], nested);
5593ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5594 SmallVector<Attribute> enabledLayersBuffer;
5596 auto tokenKind = getToken().getKind();
5598 if (tokenKind == FIRToken::kw_enablelayer) {
5599 if (parseEnableLayerSpec(enabledLayersBuffer))
5607 if (enabledLayersBuffer.size() != 0)
5608 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5611 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5615ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5616 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5617 ArrayAttr &externalRequirements) {
5618 SmallVector<Attribute> enabledLayersBuffer;
5619 SmallVector<Attribute> knownLayersBuffer;
5620 SmallVector<Attribute> requirementsBuffer;
5622 auto tokenKind = getToken().getKind();
5624 if (tokenKind == FIRToken::kw_enablelayer) {
5625 if (parseEnableLayerSpec(enabledLayersBuffer))
5630 if (tokenKind == FIRToken::kw_knownlayer) {
5631 if (parseKnownLayerSpec(knownLayersBuffer))
5636 if (tokenKind == FIRToken::kw_requires) {
5637 if (parseRequiresSpec(requirementsBuffer))
5645 if (enabledLayersBuffer.size() != 0)
5646 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5649 if (knownLayersBuffer.size() != 0)
5650 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5653 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5654 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5655 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5660FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5662 SymbolRefAttr layer;
5663 if (parseLayerName(layer))
5665 result.push_back(layer);
5666 }
while (consumeIf(FIRToken::comma));
5671FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5672 consumeToken(FIRToken::kw_enablelayer);
5673 return parseLayerList(result);
5677FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5678 consumeToken(FIRToken::kw_knownlayer);
5679 return parseLayerList(result);
5683FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5684 consumeToken(FIRToken::kw_requires);
5686 StringRef requireStr;
5687 if (parseGetSpelling(requireStr) ||
5688 parseToken(FIRToken::string,
"expected string after 'requires'"))
5692 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5693 }
while (consumeIf(FIRToken::comma));
5701FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5702 SmallVectorImpl<SMLoc> &resultPortLocs,
5708 DenseMap<Attribute, size_t> nameToIndex;
5709 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5712 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5714 getIndentation() > indent) {
5720 auto backtrackState = getLexer().getCursor();
5722 bool isOutput = getToken().is(FIRToken::kw_output);
5727 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5728 !getToken().isKeyword()) {
5729 backtrackState.restore(getLexer());
5736 if (parseId(name,
"expected port name") ||
5737 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5738 parseType(type,
"expected a type in port declaration"))
5740 Attribute domainInfoElement = {};
5741 size_t portIdx = resultPorts.size();
5742 if (
auto domainType = dyn_cast<DomainType>(type)) {
5745 domainInfoElement = ArrayAttr::get(getContext(), {});
5747 if (getToken().is(FIRToken::kw_domains))
5748 if (parseDomains(domainNames[portIdx], nameToIndex))
5752 if (
info.parseOptionalInfo())
5755 StringAttr innerSym = {};
5756 resultPorts.push_back(
PortInfo{name,
5762 domainInfoElement});
5763 resultPortLocs.push_back(
info.getFIRLoc());
5764 nameToIndex.insert({name, portIdx});
5768 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5769 auto &port = resultPorts[portIdx];
5770 Attribute &attr = port.domains;
5774 SmallVector<Attribute> domainInfo;
5775 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5777 attr = ArrayAttr::get(getContext(), domainInfo);
5782 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5783 PortInfo &port = std::get<0>(portAndLoc);
5784 auto &entry = portIds[port.
name];
5785 if (!entry.isValid()) {
5786 entry = std::get<1>(portAndLoc);
5790 emitError(std::get<1>(portAndLoc),
5791 "redefinition of name '" + port.
getName() +
"'")
5792 .attachNote(translateLocation(entry))
5793 <<
"previous definition here";
5802ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5804 switch (getToken().getKind()) {
5808 case FIRToken::error:
5812 case FIRToken::kw_class:
5813 case FIRToken::kw_domain:
5814 case FIRToken::kw_declgroup:
5815 case FIRToken::kw_extclass:
5816 case FIRToken::kw_extmodule:
5817 case FIRToken::kw_intmodule:
5818 case FIRToken::kw_formal:
5819 case FIRToken::kw_module:
5820 case FIRToken::kw_public:
5821 case FIRToken::kw_layer:
5822 case FIRToken::kw_option:
5823 case FIRToken::kw_simulation:
5824 case FIRToken::kw_type:
5828 if (getIndentation() == indent)
5840ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5841 SmallVector<Attribute, 8> parameters;
5842 SmallPtrSet<StringAttr, 8> seen;
5843 while (consumeIf(FIRToken::kw_parameter)) {
5847 if (parseParameter(name, value, loc))
5849 auto typedValue = dyn_cast<TypedAttr>(value);
5851 return emitError(loc)
5852 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5853 if (!seen.insert(name).second)
5854 return emitError(loc,
5855 "redefinition of parameter '" + name.getValue() +
"'");
5856 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5858 resultParameters = ArrayAttr::get(getContext(), parameters);
5863ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5865 SmallVector<PortInfo, 8> portList;
5866 SmallVector<SMLoc> portLocs;
5872 consumeToken(FIRToken::kw_class);
5873 if (parseId(name,
"expected class name") ||
5874 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5878 if (name == circuit.getName())
5879 return mlir::emitError(
info.getLoc(),
5880 "class cannot be the top of a circuit");
5882 for (
auto &portInfo : portList)
5884 return
mlir::emitError(portInfo.loc,
5885 "ports on classes must be properties");
5888 auto builder = circuit.getBodyBuilder();
5889 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5890 classOp.setPrivate();
5891 deferredModules.emplace_back(
5892 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5895 getConstants().classMap[name.getValue()] = classOp;
5896 return skipToModuleEnd(indent);
5900ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5901 consumeToken(FIRToken::kw_domain);
5905 if (parseId(name,
"domain name") ||
5906 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5907 info.parseOptionalInfo())
5910 SmallVector<Attribute> fields;
5912 auto nextIndent = getIndentation();
5913 if (!nextIndent || *nextIndent <= indent)
5916 StringAttr fieldName;
5918 if (parseId(fieldName,
"field name") ||
5919 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5920 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5924 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5927 auto builder = circuit.getBodyBuilder();
5928 auto domainOp = DomainOp::create(builder,
info.getLoc(), name,
5929 builder.getArrayAttr(fields));
5933 getConstants().domainMap[name.getValue()] = domainOp;
5939ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5942 SmallVector<PortInfo, 8> portList;
5943 SmallVector<SMLoc> portLocs;
5949 consumeToken(FIRToken::kw_extclass);
5950 if (parseId(name,
"expected extclass name") ||
5951 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5955 if (name == circuit.getName())
5956 return mlir::emitError(
info.getLoc(),
5957 "extclass cannot be the top of a circuit");
5959 for (
auto &portInfo : portList)
5961 return
mlir::emitError(portInfo.loc,
5962 "ports on extclasses must be properties");
5965 auto builder = circuit.getBodyBuilder();
5966 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5969 getConstants().classMap[name.getValue()] = extClassOp;
5970 return skipToModuleEnd(indent);
5978ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5981 ArrayAttr enabledLayers;
5982 ArrayAttr knownLayers;
5983 ArrayAttr externalRequirements;
5984 SmallVector<PortInfo, 8> portList;
5985 SmallVector<SMLoc> portLocs;
5987 consumeToken(FIRToken::kw_extmodule);
5988 if (parseId(name,
"expected extmodule name") ||
5989 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
5990 externalRequirements) ||
5991 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5996 if (consumeIf(FIRToken::kw_defname)) {
5997 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5998 parseId(defName,
"expected defname name"))
6002 ArrayAttr parameters;
6007 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6008 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6009 if (ftype.hasUninferredWidth())
6010 return emitError(loc,
"extmodule port must have known width");
6015 auto builder = circuit.getBodyBuilder();
6016 auto isMainModule = (name == circuit.getName());
6018 (isMainModule && getConstants().options.scalarizePublicModules) ||
6019 getConstants().options.scalarizeExtModules
6020 ? Convention::Scalarized
6021 : Convention::Internal;
6022 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6023 auto annotations = ArrayAttr::get(getContext(), {});
6024 auto extModuleOp = FExtModuleOp::create(
6025 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
6026 defName, annotations, parameters, enabledLayers, externalRequirements);
6027 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6028 : SymbolTable::Visibility::Private;
6029 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6037ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6041 ArrayAttr enabledLayers;
6042 SmallVector<PortInfo, 8> portList;
6043 SmallVector<SMLoc> portLocs;
6045 consumeToken(FIRToken::kw_intmodule);
6046 if (parseId(name,
"expected intmodule name") ||
6047 parseModuleLayerSpec(enabledLayers) ||
6048 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
6050 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
6051 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
6052 parseId(intName,
"expected intrinsic name"))
6055 ArrayAttr parameters;
6059 ArrayAttr annotations = getConstants().emptyArrayAttr;
6060 auto builder = circuit.getBodyBuilder();
6061 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
6062 annotations, parameters, enabledLayers)
6068ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
6071 SmallVector<PortInfo, 8> portList;
6072 SmallVector<SMLoc> portLocs;
6073 ArrayAttr enabledLayers;
6074 auto modLoc = getToken().getLoc();
6075 LocWithInfo
info(modLoc,
this);
6076 consumeToken(FIRToken::kw_module);
6077 if (parseId(name,
"expected module name") ||
6078 parseModuleLayerSpec(enabledLayers) ||
6079 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
6084 if (name == circuit.getName()) {
6085 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
6090 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
6091 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
6092 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6093 if (ftype.hasUninferredWidth())
6094 return emitError(loc,
"public module port must have known width");
6095 if (ftype.hasUninferredReset())
6096 return emitError(loc,
6097 "public module port must have concrete reset type");
6102 ArrayAttr annotations = getConstants().emptyArrayAttr;
6103 auto convention = Convention::Internal;
6104 if (isPublic && getConstants().options.scalarizePublicModules)
6105 convention = Convention::Scalarized;
6106 if (!isPublic && getConstants().options.scalarizeInternalModules)
6107 convention = Convention::Scalarized;
6108 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6109 auto builder = circuit.getBodyBuilder();
6111 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6112 annotations, enabledLayers);
6114 auto visibility = isPublic ? SymbolTable::Visibility::Public
6115 : SymbolTable::Visibility::Private;
6116 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6120 deferredModules.emplace_back(DeferredModuleToParse{
6121 moduleOp, portLocs, getLexer().getCursor(), indent});
6123 if (skipToModuleEnd(indent))
6129ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6130 consumeToken(FIRToken::kw_formal);
6131 return parseFormalLike<FormalOp>(circuit, indent);
6135ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6137 consumeToken(FIRToken::kw_simulation);
6138 return parseFormalLike<SimulationOp>(circuit, indent);
6145ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6147 StringRef id, moduleName;
6150 auto builder = circuit.getBodyBuilder();
6153 if (parseId(
id,
"expected test name") ||
6154 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6155 parseId(moduleName,
"expected module name"))
6159 NamedAttrList params;
6160 if (consumeIf(FIRToken::comma)) {
6162 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6163 return emitError(
"expected 'bound' after ','");
6165 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6166 parseIntLit(bound,
"expected integer bound after '='"))
6169 return emitError(
"bound must be a positive integer");
6170 if (
info.parseOptionalInfo())
6172 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6175 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6176 info.parseOptionalInfo())
6178 while (getIndentation() > indent) {
6179 StringAttr paramName;
6180 Attribute paramValue;
6182 if (parseParameter(paramName, paramValue, paramLoc,
6185 if (params.set(paramName, paramValue))
6186 return emitError(paramLoc,
"redefinition of parameter '" +
6187 paramName.getValue() +
"'");
6191 Op::create(builder,
info.getLoc(),
id, moduleName,
6192 params.getDictionary(getContext()));
6196ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6198 switch (getToken().getKind()) {
6199 case FIRToken::kw_class:
6200 return parseClass(circuit, indent);
6201 case FIRToken::kw_declgroup:
6202 if (requireFeature({3, 2, 0},
"optional groups") ||
6203 removedFeature({3, 3, 0},
"optional groups"))
6205 return parseLayer(circuit);
6206 case FIRToken::kw_domain:
6209 return parseDomain(circuit, indent);
6210 case FIRToken::kw_extclass:
6211 return parseExtClass(circuit, indent);
6212 case FIRToken::kw_extmodule:
6213 return parseExtModule(circuit, indent);
6214 case FIRToken::kw_formal:
6215 if (requireFeature({4, 0, 0},
"formal tests"))
6217 return parseFormal(circuit, indent);
6218 case FIRToken::kw_intmodule:
6219 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6220 removedFeature({4, 0, 0},
"intrinsic modules"))
6222 return parseIntModule(circuit, indent);
6223 case FIRToken::kw_layer:
6224 if (requireFeature({3, 3, 0},
"layers"))
6226 return parseLayer(circuit);
6227 case FIRToken::kw_module:
6228 return parseModule(circuit,
false, indent);
6229 case FIRToken::kw_public:
6230 if (requireFeature({3, 3, 0},
"public modules"))
6233 if (getToken().getKind() == FIRToken::kw_module)
6234 return parseModule(circuit,
true, indent);
6235 return emitError(getToken().
getLoc(),
"only modules may be public");
6236 case FIRToken::kw_simulation:
6239 return parseSimulation(circuit, indent);
6240 case FIRToken::kw_type:
6241 return parseTypeDecl();
6242 case FIRToken::kw_option:
6245 return parseOptionDecl(circuit);
6247 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6252ParseResult FIRCircuitParser::parseTypeDecl() {
6256 auto loc = getToken().getLoc();
6258 if (getToken().isKeyword())
6259 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6260 <<
"' for type alias name";
6262 if (parseId(
id,
"expected type name") ||
6263 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6266 auto name = StringAttr::get(type.getContext(),
id);
6269 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6270 type = BaseTypeAliasType::get(name, base);
6273 <<
"type alias for non-base type " << type
6274 <<
" is currently not supported. Type alias is stripped immediately";
6276 if (!getConstants().aliasMap.insert({id, type}).second)
6277 return emitError(loc) <<
"type alias `" << name.getValue()
6278 <<
"` is already defined";
6283ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6286 auto loc = getToken().getLoc();
6289 if (parseId(
id,
"expected an option group name") ||
6290 parseToken(FIRToken::colon,
6291 "expected ':' after option group definition") ||
6292 info.parseOptionalInfo())
6295 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6296 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6297 auto *block =
new Block;
6298 optionOp.getBody().push_back(block);
6299 builder.setInsertionPointToEnd(block);
6301 auto baseIndent = getIndentation();
6303 while (getIndentation() == baseIndent) {
6305 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6306 if (parseId(
id,
"expected an option case ID") ||
6307 caseInfo.parseOptionalInfo())
6310 if (!cases.insert(
id).second)
6311 return emitError(loc)
6312 <<
"duplicate option case definition '" <<
id <<
"'";
6314 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6321ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6322 auto baseIndent = getIndentation();
6325 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6328 auto parseOne = [&](
Block *block) -> ParseResult {
6329 auto indent = getIndentation();
6330 StringRef id, convention;
6333 if (parseId(
id,
"expected layer name") ||
6334 parseToken(FIRToken::comma,
"expected ','") ||
6335 parseGetSpelling(convention))
6338 auto layerConvention = symbolizeLayerConvention(convention);
6339 if (!layerConvention) {
6340 emitError() <<
"unknown convention '" << convention
6341 <<
"' (did you misspell it?)";
6344 if (layerConvention == LayerConvention::Inline &&
6345 requireFeature({4, 1, 0},
"inline layers"))
6349 hw::OutputFileAttr outputDir;
6350 if (consumeIf(FIRToken::comma)) {
6351 if (getToken().getKind() == FIRToken::string) {
6352 auto text = getToken().getStringValue();
6354 return emitError() <<
"output directory must not be blank";
6355 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6356 consumeToken(FIRToken::string);
6360 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6361 info.parseOptionalInfo())
6363 auto builder = OpBuilder::atBlockEnd(block);
6366 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6367 layerOp->getRegion(0).push_back(
new Block());
6369 layerOp->setAttr(
"output_file", outputDir);
6370 layerStack.push_back({indent, layerOp});
6374 if (parseOne(circuit.getBodyBlock()))
6378 while (getIndentation() > baseIndent) {
6379 switch (getToken().getKind()) {
6380 case FIRToken::kw_declgroup:
6381 case FIRToken::kw_layer: {
6384 while (layerStack.back().first >= getIndentation())
6385 layerStack.pop_back();
6386 auto parentLayer = layerStack.back().second;
6387 if (parseOne(&parentLayer.getBody().front()))
6392 return emitError(
"expected 'layer'"), failure();
6399ParseResult FIRCircuitParser::resolveDomains(
6400 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6401 const DenseMap<Attribute, size_t> &nameToIndex,
6402 SmallVectorImpl<Attribute> &domainsByIndex) {
6404 for (
auto [attr, loc] : domainsByName) {
6405 auto domain = cast<StringAttr>(attr);
6406 auto indexItr = nameToIndex.find(domain);
6407 if (indexItr == nameToIndex.end()) {
6408 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6411 domainsByIndex.push_back(IntegerAttr::get(
6412 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6419ParseResult FIRCircuitParser::parseDomains(
6420 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6421 const DenseMap<Attribute, size_t> &nameToIndex) {
6424 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6425 parseToken(FIRToken::l_square,
"expected '['"))
6428 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6430 auto domainLoc = getToken().getLoc();
6431 if (parseId(domain,
"expected domain name"))
6433 domains.push_back({domain, domainLoc});
6443FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6444 DeferredModuleToParse &deferredModule,
6445 InnerSymFixups &fixups) {
6446 FModuleLike moduleOp = deferredModule.moduleOp;
6447 auto &body = moduleOp->getRegion(0).front();
6448 auto &portLocs = deferredModule.portLocs;
6452 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6455 deferredModule.lexerCursor.restore(moduleBodyLexer);
6457 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6462 auto portList = moduleOp.getPorts();
6463 auto portArgs = body.getArguments();
6464 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6465 PortInfo &port = std::get<0>(tuple);
6466 llvm::SMLoc loc = std::get<1>(tuple);
6467 BlockArgument portArg = std::get<2>(tuple);
6469 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6473 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6476 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6482 size_t numVerifPrintfs = 0;
6483 std::optional<Location> printfLoc;
6485 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6490 printfLoc = printFOp.getLoc();
6493 if (numVerifPrintfs > 0) {
6495 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6497 <<
" printf-encoded verification operation(s), which are no longer "
6499 diag.attachNote(*printfLoc)
6500 <<
"example printf here, this is now just a printf and nothing more";
6501 diag.attachNote() <<
"For more information, see "
6502 "https://github.com/llvm/circt/issues/6970";
6516ParseResult FIRCircuitParser::parseCircuit(
6517 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6518 mlir::TimingScope &ts) {
6520 auto indent = getIndentation();
6521 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6523 if (!indent.has_value())
6524 return emitError(
"'FIRRTL' must be first token on its line");
6525 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6526 parseVersionLit(
"expected version literal"))
6528 indent = getIndentation();
6530 if (!indent.has_value())
6531 return emitError(
"'circuit' must be first token on its line");
6532 unsigned circuitIndent = *indent;
6536 SMLoc inlineAnnotationsLoc;
6537 StringRef inlineAnnotations;
6540 if (parseToken(FIRToken::kw_circuit,
6541 "expected a top-level 'circuit' definition") ||
6542 parseId(name,
"expected circuit name") ||
6543 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6544 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6545 info.parseOptionalInfo())
6549 OpBuilder
b(mlirModule.getBodyRegion());
6550 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6553 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6559 SmallVector<Attribute> annos;
6560 if (!inlineAnnotations.empty())
6561 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6565 for (
auto *annotationsBuf : annotationsBufs)
6566 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6570 parseAnnotationTimer.stop();
6578 auto parseTimer = ts.nest(
"Parse modules");
6579 deferredModules.reserve(16);
6583 switch (getToken().getKind()) {
6591 case FIRToken::error:
6595 emitError(
"unexpected token in circuit");
6598 case FIRToken::kw_class:
6599 case FIRToken::kw_declgroup:
6600 case FIRToken::kw_domain:
6601 case FIRToken::kw_extclass:
6602 case FIRToken::kw_extmodule:
6603 case FIRToken::kw_intmodule:
6604 case FIRToken::kw_layer:
6605 case FIRToken::kw_formal:
6606 case FIRToken::kw_module:
6607 case FIRToken::kw_option:
6608 case FIRToken::kw_public:
6609 case FIRToken::kw_simulation:
6610 case FIRToken::kw_type: {
6611 auto indent = getIndentation();
6612 if (!indent.has_value())
6613 return emitError(
"'module' must be first token on its line"), failure();
6614 unsigned definitionIndent = *indent;
6616 if (definitionIndent <= circuitIndent)
6617 return emitError(
"module should be indented more"), failure();
6619 if (parseToplevelDefinition(circuit, definitionIndent))
6633 (void)getLexer().translateLocation(
info.getFIRLoc());
6639 DenseMap<Attribute, Location> nameToOrigLoc;
6643 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6648 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6651 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6652 .attachNote(it.first->second)
6653 .append(
"see existing symbol definition here");
6659 SymbolTable circuitSymTbl(circuit);
6661 moduleFixups.resize(deferredModules.size());
6666 for (
auto &d : deferredModules)
6667 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6670 auto anyFailed = mlir::failableParallelForEachN(
6671 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6672 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6673 moduleFixups[index]))
6677 if (failed(anyFailed))
6682 for (
auto &fixups : moduleFixups) {
6683 if (failed(fixups.resolve(innerSymbolNamespaces)))
6689 auto parseLayerName = [&](StringRef name) -> Attribute {
6691 auto [head, rest] = name.split(
".");
6692 SmallVector<FlatSymbolRefAttr> nestedRefs;
6693 while (!rest.empty()) {
6695 std::tie(next, rest) = rest.split(
".");
6696 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6698 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6701 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6702 SmallVector<Attribute> attrArray;
6704 for (
const auto &str : strArray)
6705 attrArray.push_back(getAttr(str));
6706 if (attrArray.empty())
6708 return ArrayAttr::get(
context, attrArray);
6711 if (
auto enableLayers =
6712 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6713 circuit.setEnableLayersAttr(enableLayers);
6714 if (
auto disableLayers =
6715 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6716 circuit.setDisableLayersAttr(disableLayers);
6718 auto getStrAttr = [&](StringRef str) -> Attribute {
6719 return StringAttr::get(getContext(), str);
6722 if (
auto selectInstChoice =
6723 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6724 circuit.setSelectInstChoiceAttr(selectInstChoice);
6726 circuit.setDefaultLayerSpecialization(
6727 getConstants().options.defaultLayerSpecialization);
6740 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6741 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6742 unsigned fileID = 1;
6744 annotationsBufs.push_back(
6745 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6747 context->loadDialect<CHIRRTLDialect>();
6748 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6752 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6755 SharedParserConstants state(
context, options);
6758 .parseCircuit(annotationsBufs, ts))
6763 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6764 if (failed(verify(*module)))
6771 static mlir::TranslateToMLIRRegistration fromFIR(
6772 "import-firrtl",
"import .fir",
6773 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6774 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