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 parseUnsafeDomainCast(Value &result);
2012 ParseResult parseUnknownProperty(Value &result);
2014 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
2015 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2017 auto loc = getToken().getLoc();
2018 locationProcessor.setLoc(loc);
2021 auto vals = std::array<Value, M>();
2022 auto ints = std::array<int64_t, N>();
2026 for (
size_t i = 0; i < M; ++i) {
2028 if (parseToken(FIRToken::comma,
"expected ','"))
2030 if (parseExp(vals[i],
"expected expression in primitive operand"))
2036 for (
size_t i = 0; i < N; ++i) {
2038 if (parseToken(FIRToken::comma,
"expected ','"))
2040 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
2045 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2049 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2053 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2054 translateLocation(loc));
2059 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2060 result = op.getResult();
2064 template <
typename T,
unsigned M,
unsigned N>
2065 ParseResult parsePrimExp(Value &result) {
2066 auto ms = std::make_index_sequence<M>();
2067 auto ns = std::make_index_sequence<N>();
2068 return parsePrim<T, M, N>(ms, ns, result);
2071 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2074 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2075 SymbolRefAttr layerSym);
2076 ParseResult parseAttach();
2077 ParseResult parseMemPort(MemDirAttr direction);
2083 ArrayRef<Value> specOperands,
2084 StringAttr &formatStringResult,
2085 SmallVectorImpl<Value> &operands);
2086 ParseResult parsePrintf();
2087 ParseResult parseFPrintf();
2088 ParseResult parseFFlush();
2089 ParseResult parseSkip();
2090 ParseResult parseStop();
2091 ParseResult parseAssert();
2092 ParseResult parseAssume();
2093 ParseResult parseCover();
2094 ParseResult parseWhen(
unsigned whenIndent);
2095 ParseResult parseMatch(
unsigned matchIndent);
2096 ParseResult parseDomainInstantiation();
2097 ParseResult parseDomainDefine();
2098 ParseResult parseRefDefine();
2099 ParseResult parseRefForce();
2100 ParseResult parseRefForceInitial();
2101 ParseResult parseRefRelease();
2102 ParseResult parseRefReleaseInitial();
2103 ParseResult parseRefRead(Value &result);
2104 ParseResult parseProbe(Value &result);
2105 ParseResult parsePropAssign();
2106 ParseResult parseRWProbe(Value &result);
2107 ParseResult parseLeadingExpStmt(Value lhs);
2108 ParseResult parseConnect();
2109 ParseResult parseInvalidate();
2110 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2113 ParseResult parseInstance();
2114 ParseResult parseInstanceChoice();
2115 ParseResult parseObject();
2116 ParseResult parseCombMem();
2117 ParseResult parseSeqMem();
2118 ParseResult parseMem(
unsigned memIndent);
2119 ParseResult parseNode();
2120 ParseResult parseWire();
2121 ParseResult parseRegister(
unsigned regIndent);
2122 ParseResult parseRegisterWithReset();
2123 ParseResult parseContract(
unsigned blockIndent);
2126 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2129 ImplicitLocOpBuilder builder;
2130 LazyLocationListener locationProcessor;
2133 FIRModuleContext &moduleContext;
2136 InnerSymFixups &innerSymFixups;
2140 SymbolRefAttr layerSym;
2142 const SymbolTable &circuitSymTbl;
2149void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2150 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2157 auto props = tpe.getRecursiveTypeProperties();
2158 if (props.isPassive && !props.containsAnalog) {
2159 if (flow == Flow::Source)
2161 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2172 TypeSwitch<FIRRTLType>(tpe)
2173 .Case<BundleType>([&](
auto tpe) {
2174 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2175 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2177 OpBuilder::InsertionGuard guard(builder);
2178 builder.setInsertionPointAfterValue(val);
2179 subfield = SubfieldOp::create(builder, val, i);
2181 emitInvalidate(subfield,
2182 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2185 .Case<FVectorType>([&](
auto tpe) {
2186 auto tpex = tpe.getElementType();
2187 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2188 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2190 OpBuilder::InsertionGuard guard(builder);
2191 builder.setInsertionPointAfterValue(val);
2192 subindex = SubindexOp::create(builder, tpex, val, i);
2194 emitInvalidate(subindex, flow);
2222ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2223 bool isLeadingStmt) {
2224 auto token = getToken();
2225 auto kind = token.getKind();
2227 case FIRToken::lp_integer_add:
2228 case FIRToken::lp_integer_mul:
2229 case FIRToken::lp_integer_shr:
2230 case FIRToken::lp_integer_shl:
2231 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2240#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2242 case FIRToken::lp_##SPELLING: \
2243 if (requireFeature(VERSION, FEATURE)) \
2245 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2248#include "FIRTokenKinds.def"
2250 case FIRToken::l_brace_bar:
2252 return emitError(
"unexpected enumeration as start of statement");
2253 if (parseEnumExp(result))
2256 case FIRToken::lp_read:
2258 return emitError(
"unexpected read() as start of statement");
2259 if (parseRefRead(result))
2262 case FIRToken::lp_probe:
2264 return emitError(
"unexpected probe() as start of statement");
2265 if (parseProbe(result))
2268 case FIRToken::lp_rwprobe:
2270 return emitError(
"unexpected rwprobe() as start of statement");
2271 if (parseRWProbe(result))
2275 case FIRToken::langle_UInt:
2276 case FIRToken::langle_SInt: {
2279 bool isSigned = getToken().is(FIRToken::langle_SInt);
2282 if (parseWidth(width))
2286 if (parseIntegerLiteralExp(result, isSigned, width))
2291 case FIRToken::lp_UInt:
2292 if (parseIntegerLiteralExp(result,
false))
2295 case FIRToken::lp_SInt:
2296 if (parseIntegerLiteralExp(result,
true))
2299 case FIRToken::lp_String: {
2300 if (requireFeature({3, 1, 0},
"Strings"))
2302 locationProcessor.setLoc(getToken().
getLoc());
2303 consumeToken(FIRToken::lp_String);
2305 if (parseGetSpelling(spelling) ||
2306 parseToken(FIRToken::string,
2307 "expected string literal in String expression") ||
2308 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2311 result = moduleContext.getCachedConstant<StringConstantOp>(
2312 builder, attr, builder.getType<StringType>(), attr);
2315 case FIRToken::lp_Integer: {
2316 if (requireFeature({3, 1, 0},
"Integers"))
2318 locationProcessor.setLoc(getToken().
getLoc());
2319 consumeToken(FIRToken::lp_Integer);
2321 if (parseIntLit(value,
"expected integer literal in Integer expression") ||
2322 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2324 APSInt apint(value,
false);
2325 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2326 builder, IntegerAttr::get(getContext(), apint),
2327 builder.getType<FIntegerType>(), apint);
2330 case FIRToken::lp_Bool: {
2333 locationProcessor.setLoc(getToken().
getLoc());
2334 consumeToken(FIRToken::lp_Bool);
2336 if (consumeIf(FIRToken::kw_true))
2338 else if (consumeIf(FIRToken::kw_false))
2341 return emitError(
"expected true or false in Bool expression");
2342 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2344 auto attr = builder.getBoolAttr(value);
2345 result = moduleContext.getCachedConstant<BoolConstantOp>(
2346 builder, attr, builder.getType<BoolType>(), value);
2349 case FIRToken::lp_Double: {
2352 locationProcessor.setLoc(getToken().
getLoc());
2353 consumeToken(FIRToken::lp_Double);
2354 auto spelling = getTokenSpelling();
2355 if (parseToken(FIRToken::floatingpoint,
2356 "expected floating point in Double expression") ||
2357 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2362 if (!llvm::to_float(spelling, d))
2363 return emitError(
"invalid double");
2364 auto attr = builder.getF64FloatAttr(d);
2365 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2366 builder, attr, builder.getType<DoubleType>(), attr);
2369 case FIRToken::lp_List:
2370 case FIRToken::langle_List: {
2371 if (requireFeature({4, 0, 0},
"Lists"))
2374 return emitError(
"unexpected List<>() as start of statement");
2375 if (parseListExp(result))
2380 case FIRToken::lp_list_concat: {
2382 return emitError(
"unexpected list_create() as start of statement");
2383 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2388 case FIRToken::lp_path:
2390 return emitError(
"unexpected path() as start of statement");
2395 case FIRToken::lp_intrinsic:
2396 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2397 parseIntrinsicExp(result))
2401 case FIRToken::lp_cat:
2402 if (parseCatExp(result))
2406 case FIRToken::lp_unsafe_domain_cast:
2408 parseUnsafeDomainCast(result))
2411 case FIRToken::lp_Unknown:
2412 if (requireFeature(
nextFIRVersion,
"unknown property expressions") ||
2413 parseUnknownProperty(result))
2419 case FIRToken::identifier:
2420 case FIRToken::literal_identifier:
2421 case FIRToken::kw_UInt:
2422 case FIRToken::kw_SInt:
2423 case FIRToken::kw_String:
2424 case FIRToken::kw_Integer:
2425 case FIRToken::kw_Bool:
2426 case FIRToken::kw_Double:
2427 case FIRToken::kw_List:
2430 auto loc = getToken().getLoc();
2432 if (parseId(name, message) ||
2433 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2437 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2440 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2445 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2446 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2447 parseOptionalInfo())
2450 locationProcessor.setLoc(loc);
2452 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2454 moduleContext.getUnbundledEntry(unbundledId);
2455 for (
auto elt : ubEntry)
2456 emitInvalidate(elt.second);
2464 StringRef fieldName;
2465 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2466 parseFieldId(fieldName,
"expected field name") ||
2467 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2475 case FIRToken::lp_shr:
2478 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2479 result = PadPrimOp::create(builder, result, 1);
2485 return parseOptionalExpPostscript(result);
2495ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2496 bool allowDynamic) {
2501 if (consumeIf(FIRToken::period)) {
2502 if (parsePostFixFieldId(result))
2509 if (consumeIf(FIRToken::l_square)) {
2510 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2511 if (parsePostFixIntSubscript(result))
2516 return emitError(
"subaccess not allowed here");
2517 if (parsePostFixDynamicSubscript(result))
2527template <
typename subop>
2529FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2531 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2537 auto baseType = cast<FIRRTLType>(base.getType());
2538 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2541 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2547 locationProcessor.setLoc(loc);
2548 OpBuilder::InsertionGuard guard(builder);
2549 builder.setInsertionPointAfterValue(base);
2550 auto op = subop::create(builder, resultType, base, indexNo);
2553 return value = op.getResult();
2560ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2561 auto loc = getToken().getLoc();
2562 SmallVector<StringRef, 3> fields;
2563 if (parseFieldIdSeq(fields,
"expected field name"))
2565 for (
auto fieldName : fields) {
2566 std::optional<unsigned> indexV;
2567 auto type = result.getType();
2568 if (
auto refTy = type_dyn_cast<RefType>(type))
2569 type = refTy.getType();
2570 if (
auto bundle = type_dyn_cast<BundleType>(type))
2571 indexV = bundle.getElementIndex(fieldName);
2572 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2573 indexV = bundle.getElementIndex(fieldName);
2574 else if (
auto klass = type_dyn_cast<ClassType>(type))
2575 indexV = klass.getElementIndex(fieldName);
2577 return emitError(loc,
"subfield requires bundle or object operand ");
2579 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2580 << result.getType();
2581 auto indexNo = *indexV;
2583 FailureOr<Value> subResult;
2584 if (type_isa<RefType>(result.getType()))
2585 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2586 else if (type_isa<ClassType>(type))
2587 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2588 else if (type_isa<BundleType>(type))
2589 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2591 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2593 if (failed(subResult))
2595 result = *subResult;
2604ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2605 auto loc = getToken().getLoc();
2607 if (parseIntLit(indexNo,
"expected index") ||
2608 parseToken(FIRToken::r_square,
"expected ']'"))
2612 return emitError(loc,
"invalid index specifier"), failure();
2614 FailureOr<Value> subResult;
2615 if (type_isa<RefType>(result.getType()))
2616 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2617 else if (type_isa<FVectorType>(result.getType()))
2618 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2620 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2622 if (failed(subResult))
2624 result = *subResult;
2632ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2633 auto loc = getToken().getLoc();
2635 if (parseExp(index,
"expected subscript index expression") ||
2636 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2640 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2642 return emitError(
"expected base type for index expression");
2643 indexType = indexType.getPassiveType();
2644 locationProcessor.setLoc(loc);
2649 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2652 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2653 translateLocation(loc));
2658 auto op = SubaccessOp::create(builder, resultType, result, index);
2659 result = op.getResult();
2670FIRStmtParser::parseIntegerLiteralExp(Value &result,
bool isSigned,
2671 std::optional<int32_t> allocatedWidth) {
2672 auto loc = getToken().getLoc();
2675 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2680 int32_t width = allocatedWidth.value_or(-1);
2686 parseToken(FIRToken::l_paren,
"expected '(' in integer expression"))
2689 if (parseIntLit(value,
"expected integer value") ||
2690 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2695 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2697 IntegerType::SignednessSemantics signedness =
2698 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2700 if (!value.isZero())
2701 return emitError(loc,
"zero bit constant must be zero");
2702 value = value.trunc(0);
2703 }
else if (width != -1) {
2705 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2707 return emitError(loc,
"initializer too wide for declared width");
2708 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2712 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2713 auto attr = builder.getIntegerAttr(attrType, value);
2715 locationProcessor.setLoc(loc);
2716 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2721ParseResult FIRStmtParser::parseListExp(Value &result) {
2722 auto loc = getToken().getLoc();
2723 bool hasLAngle = getToken().is(FIRToken::langle_List);
2724 bool hasLParen = getToken().is(FIRToken::lp_List);
2729 if (!hasLAngle && parseToken(FIRToken::less,
"expected '<' in List type"))
2732 if (parsePropertyType(
elementType,
"expected List element type") ||
2733 parseToken(FIRToken::greater,
"expected '>' in List type"))
2736 auto listType = ListType::get(getContext(),
elementType);
2740 parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2743 SmallVector<Value, 3> operands;
2744 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2746 locationProcessor.setLoc(loc);
2747 if (parseExp(operand,
"expected expression in List expression"))
2751 if (!isa<AnyRefType>(elementType) ||
2752 !isa<ClassType>(operand.getType()))
2753 return emitError(loc,
"unexpected expression of type ")
2754 << operand.getType() <<
" in List expression of type "
2756 operand = ObjectAnyRefCastOp::create(builder, operand);
2759 operands.push_back(operand);
2764 locationProcessor.setLoc(loc);
2765 result = ListCreateOp::create(builder, listType, operands);
2770ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2771 consumeToken(FIRToken::lp_list_concat);
2773 auto loc = getToken().getLoc();
2775 SmallVector<Value, 3> operands;
2776 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2778 locationProcessor.setLoc(loc);
2779 if (parseExp(operand,
"expected expression in List concat expression"))
2782 if (!type_isa<ListType>(operand.getType()))
2783 return emitError(loc,
"unexpected expression of type ")
2784 << operand.getType() <<
" in List concat expression";
2787 type = type_cast<ListType>(operand.getType());
2789 if (operand.getType() != type)
2790 return emitError(loc,
"unexpected expression of type ")
2791 << operand.getType() <<
" in List concat expression of type "
2794 operands.push_back(operand);
2799 if (operands.empty())
2800 return emitError(loc,
"need at least one List to concatenate");
2802 locationProcessor.setLoc(loc);
2803 result = ListConcatOp::create(builder, type, operands);
2808ParseResult FIRStmtParser::parseCatExp(Value &result) {
2809 consumeToken(FIRToken::lp_cat);
2811 auto loc = getToken().getLoc();
2812 SmallVector<Value, 3> operands;
2813 std::optional<bool> isSigned;
2814 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2816 locationProcessor.setLoc(loc);
2817 auto operandLoc = getToken().getLoc();
2818 if (parseExp(operand,
"expected expression in cat expression"))
2820 if (!type_isa<IntType>(operand.getType())) {
2821 auto diag = emitError(loc,
"all operands must be Int type");
2822 diag.attachNote(translateLocation(operandLoc))
2823 <<
"non-integer operand is here";
2827 isSigned = type_isa<SIntType>(operand.getType());
2828 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2829 auto diag = emitError(loc,
"all operands must have same signedness");
2830 diag.attachNote(translateLocation(operandLoc))
2831 <<
"operand with different signedness is here";
2835 operands.push_back(operand);
2840 if (operands.size() != 2) {
2845 locationProcessor.setLoc(loc);
2846 result = CatPrimOp::create(builder, operands);
2850ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2851 consumeToken(FIRToken::lp_unsafe_domain_cast);
2853 auto loc = getToken().getLoc();
2855 if (parseExp(input,
"expected input"))
2858 SmallVector<Value> domains;
2859 if (consumeIf(FIRToken::comma)) {
2860 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2862 if (parseExp(domain,
"expected domain"))
2864 domains.push_back(domain);
2868 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2872 locationProcessor.setLoc(loc);
2873 result = UnsafeDomainCastOp::create(builder, input, domains);
2877ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
2878 auto loc = getToken().getLoc();
2879 consumeToken(FIRToken::lp_Unknown);
2883 if (parsePropertyType(type,
"expected property type") ||
2884 parseToken(FIRToken::r_paren,
"expected ')' in unknown property"))
2887 locationProcessor.setLoc(loc);
2888 result = UnknownValueOp::create(builder, type);
2909std::optional<ParseResult>
2910FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2911 switch (getToken().getKind()) {
2914 return std::nullopt;
2916 case FIRToken::period:
2917 case FIRToken::l_square:
2918 case FIRToken::kw_is:
2919 case FIRToken::less_equal:
2925 auto loc = keyword.
getLoc();
2927 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2928 return ParseResult(failure());
2934 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2937 if (!consumeIf(FIRToken::period))
2938 return ParseResult(failure());
2940 StringRef fieldName;
2941 if (parseFieldId(fieldName,
"expected field name") ||
2942 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2943 return ParseResult(failure());
2947 if (parseOptionalExpPostscript(lhs))
2948 return ParseResult(failure());
2950 return parseLeadingExpStmt(lhs);
2956ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2959 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2962 auto subIndent = getIndentation();
2963 if (!subIndent.has_value())
2964 return emitError(
"expected statement to be on its own line"), failure();
2966 if (*subIndent <= indent)
2970 if (parseSimpleStmt(*subIndent))
2975ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2976 locationProcessor.startStatement();
2977 auto result = parseSimpleStmtImpl(stmtIndent);
2978 locationProcessor.endStatement(*
this);
3000ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
3001 auto kind = getToken().getKind();
3004 case FIRToken::kw_invalidate:
3005 case FIRToken::kw_connect:
3006 case FIRToken::kw_regreset:
3010 kind = FIRToken::identifier;
3017 case FIRToken::kw_attach:
3018 return parseAttach();
3019 case FIRToken::kw_infer:
3020 return parseMemPort(MemDirAttr::Infer);
3021 case FIRToken::kw_read:
3022 return parseMemPort(MemDirAttr::Read);
3023 case FIRToken::kw_write:
3024 return parseMemPort(MemDirAttr::Write);
3025 case FIRToken::kw_rdwr:
3026 return parseMemPort(MemDirAttr::ReadWrite);
3027 case FIRToken::kw_connect:
3028 return parseConnect();
3029 case FIRToken::kw_propassign:
3030 if (requireFeature({3, 1, 0},
"properties"))
3032 return parsePropAssign();
3033 case FIRToken::kw_invalidate:
3034 return parseInvalidate();
3035 case FIRToken::lp_printf:
3036 return parsePrintf();
3037 case FIRToken::lp_fprintf:
3038 return parseFPrintf();
3039 case FIRToken::lp_fflush:
3040 return parseFFlush();
3041 case FIRToken::kw_skip:
3043 case FIRToken::lp_stop:
3045 case FIRToken::lp_assert:
3046 return parseAssert();
3047 case FIRToken::lp_assume:
3048 return parseAssume();
3049 case FIRToken::lp_cover:
3050 return parseCover();
3051 case FIRToken::kw_when:
3052 return parseWhen(stmtIndent);
3053 case FIRToken::kw_match:
3054 return parseMatch(stmtIndent);
3055 case FIRToken::kw_domain:
3057 return parseDomainInstantiation();
3058 case FIRToken::kw_domain_define:
3059 return parseDomainDefine();
3060 case FIRToken::kw_define:
3061 return parseRefDefine();
3062 case FIRToken::lp_force:
3063 return parseRefForce();
3064 case FIRToken::lp_force_initial:
3065 return parseRefForceInitial();
3066 case FIRToken::lp_release:
3067 return parseRefRelease();
3068 case FIRToken::lp_release_initial:
3069 return parseRefReleaseInitial();
3070 case FIRToken::kw_group:
3071 if (requireFeature({3, 2, 0},
"optional groups") ||
3072 removedFeature({3, 3, 0},
"optional groups"))
3074 return parseLayerBlockOrGroup(stmtIndent);
3075 case FIRToken::kw_layerblock:
3076 if (requireFeature({3, 3, 0},
"layers"))
3078 return parseLayerBlockOrGroup(stmtIndent);
3079 case FIRToken::lp_intrinsic:
3080 if (requireFeature({4, 0, 0},
"generic intrinsics"))
3082 return parseIntrinsicStmt();
3086 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
3093 return parseLeadingExpStmt(lhs);
3097 case FIRToken::kw_inst:
3098 return parseInstance();
3099 case FIRToken::kw_instchoice:
3100 return parseInstanceChoice();
3101 case FIRToken::kw_object:
3102 return parseObject();
3103 case FIRToken::kw_cmem:
3104 return parseCombMem();
3105 case FIRToken::kw_smem:
3106 return parseSeqMem();
3107 case FIRToken::kw_mem:
3108 return parseMem(stmtIndent);
3109 case FIRToken::kw_node:
3111 case FIRToken::kw_wire:
3113 case FIRToken::kw_reg:
3114 return parseRegister(stmtIndent);
3115 case FIRToken::kw_regreset:
3116 return parseRegisterWithReset();
3117 case FIRToken::kw_contract:
3118 return parseContract(stmtIndent);
3122ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3124 SymbolRefAttr layerSym) {
3126 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3127 moduleContext, &blockToInsertInto);
3132 UnbundledValueRestorer x(moduleContext.unbundledValues);
3136 auto subParser = std::make_unique<FIRStmtParser>(
3137 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3141 auto stmtIndent = getIndentation();
3144 if (!stmtIndent.has_value())
3145 return subParser->parseSimpleStmt(indent);
3147 if (*stmtIndent <= indent)
3148 return emitError(
"statement must be indented more than previous statement"),
3152 return subParser->parseSimpleStmtBlock(indent);
3156ParseResult FIRStmtParser::parseAttach() {
3157 auto startTok = consumeToken(FIRToken::kw_attach);
3160 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3163 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3166 SmallVector<Value, 4> operands;
3167 operands.push_back({});
3168 if (parseExp(operands.back(),
"expected operand in attach"))
3171 while (consumeIf(FIRToken::comma)) {
3172 operands.push_back({});
3173 if (parseExp(operands.back(),
"expected operand in attach"))
3176 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3179 if (parseOptionalInfo())
3182 locationProcessor.setLoc(startTok.getLoc());
3183 AttachOp::create(builder, operands);
3190ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3191 auto startTok = consumeToken();
3192 auto startLoc = startTok.getLoc();
3196 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3202 Value memory, indexExp, clock;
3203 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3204 parseId(
id,
"expected result name") ||
3205 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3206 parseId(memName,
"expected memory name") ||
3207 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3208 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3209 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3210 parseExp(indexExp,
"expected index expression") ||
3211 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3212 parseToken(FIRToken::comma,
"expected ','") ||
3213 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3216 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3218 return emitError(startLoc,
3219 "memory port should have behavioral memory type");
3220 auto resultType = memVType.getElementType();
3222 ArrayAttr annotations = getConstants().emptyArrayAttr;
3223 locationProcessor.setLoc(startLoc);
3226 Value memoryPort, memoryData;
3228 OpBuilder::InsertionGuard guard(builder);
3229 builder.setInsertionPointAfterValue(memory);
3230 auto memoryPortOp = MemoryPortOp::create(
3231 builder, resultType, CMemoryPortType::get(getContext()), memory,
3232 direction,
id, annotations);
3233 memoryData = memoryPortOp.getResult(0);
3234 memoryPort = memoryPortOp.getResult(1);
3238 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3240 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3246ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3247 StringRef formatString,
3248 ArrayRef<Value> specOperands,
3249 StringAttr &formatStringResult,
3250 SmallVectorImpl<Value> &operands) {
3253 operands.append(specOperands.begin(), specOperands.end());
3254 formatStringResult =
3260 auto loc = translateLocation(formatStringLoc);
3263 formatStringResult, operands);
3268ParseResult FIRStmtParser::parsePrintf() {
3269 auto startTok = consumeToken(FIRToken::lp_printf);
3271 Value clock, condition;
3272 StringRef formatString;
3273 if (parseExp(clock,
"expected clock expression in printf") ||
3274 parseToken(FIRToken::comma,
"expected ','") ||
3275 parseExp(condition,
"expected condition in printf") ||
3276 parseToken(FIRToken::comma,
"expected ','"))
3279 auto formatStringLoc = getToken().getLoc();
3280 if (parseGetSpelling(formatString) ||
3281 parseToken(FIRToken::string,
"expected format string in printf"))
3284 SmallVector<Value, 4> specOperands;
3285 while (consumeIf(FIRToken::comma)) {
3286 specOperands.push_back({});
3287 if (parseExp(specOperands.back(),
"expected operand in printf"))
3292 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3293 parseOptionalName(name) || parseOptionalInfo())
3296 locationProcessor.setLoc(startTok.getLoc());
3298 StringAttr formatStrUnescaped;
3299 SmallVector<Value> operands;
3301 formatStrUnescaped, operands))
3304 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3310ParseResult FIRStmtParser::parseFPrintf() {
3313 auto startTok = consumeToken(FIRToken::lp_fprintf);
3315 Value clock, condition;
3316 StringRef outputFile, formatString;
3317 if (parseExp(clock,
"expected clock expression in fprintf") ||
3318 parseToken(FIRToken::comma,
"expected ','") ||
3319 parseExp(condition,
"expected condition in fprintf") ||
3320 parseToken(FIRToken::comma,
"expected ','"))
3323 auto outputFileLoc = getToken().getLoc();
3324 if (parseGetSpelling(outputFile) ||
3325 parseToken(FIRToken::string,
"expected output file in fprintf"))
3328 SmallVector<Value, 4> outputFileSpecOperands;
3329 while (consumeIf(FIRToken::comma)) {
3331 if (getToken().getKind() == FIRToken::string)
3333 outputFileSpecOperands.push_back({});
3334 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3338 auto formatStringLoc = getToken().getLoc();
3339 if (parseGetSpelling(formatString) ||
3340 parseToken(FIRToken::string,
"expected format string in printf"))
3343 SmallVector<Value, 4> specOperands;
3344 while (consumeIf(FIRToken::comma)) {
3345 specOperands.push_back({});
3346 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3351 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3352 parseOptionalName(name) || parseOptionalInfo())
3355 locationProcessor.setLoc(startTok.getLoc());
3357 StringAttr outputFileNameStrUnescaped;
3358 SmallVector<Value> outputFileOperands;
3360 outputFileNameStrUnescaped, outputFileOperands))
3363 StringAttr formatStrUnescaped;
3364 SmallVector<Value> operands;
3366 formatStrUnescaped, operands))
3369 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3370 outputFileOperands, formatStrUnescaped, operands, name);
3375ParseResult FIRStmtParser::parseFFlush() {
3379 auto startTok = consumeToken(FIRToken::lp_fflush);
3381 Value clock, condition;
3382 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3383 parseToken(FIRToken::comma,
"expected ','") ||
3384 parseExp(condition,
"expected condition in 'fflush'"))
3387 locationProcessor.setLoc(startTok.getLoc());
3388 StringAttr outputFileNameStrUnescaped;
3389 SmallVector<Value> outputFileOperands;
3391 if (consumeIf(FIRToken::comma)) {
3392 SmallVector<Value, 4> outputFileSpecOperands;
3393 auto outputFileLoc = getToken().getLoc();
3394 StringRef outputFile;
3395 if (parseGetSpelling(outputFile) ||
3396 parseToken(FIRToken::string,
"expected output file in fflush"))
3399 while (consumeIf(FIRToken::comma)) {
3400 outputFileSpecOperands.push_back({});
3401 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3406 outputFileNameStrUnescaped, outputFileOperands))
3410 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3411 parseOptionalInfo())
3414 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3415 outputFileOperands);
3420ParseResult FIRStmtParser::parseSkip() {
3421 auto startTok = consumeToken(FIRToken::kw_skip);
3425 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3428 if (parseOptionalInfo())
3431 locationProcessor.setLoc(startTok.getLoc());
3432 SkipOp::create(builder);
3437ParseResult FIRStmtParser::parseStop() {
3438 auto startTok = consumeToken(FIRToken::lp_stop);
3440 Value clock, condition;
3443 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3444 parseToken(FIRToken::comma,
"expected ','") ||
3445 parseExp(condition,
"expected condition in 'stop'") ||
3446 parseToken(FIRToken::comma,
"expected ','") ||
3447 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3448 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3449 parseOptionalName(name) || parseOptionalInfo())
3452 locationProcessor.setLoc(startTok.getLoc());
3453 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3459ParseResult FIRStmtParser::parseAssert() {
3460 auto startTok = consumeToken(FIRToken::lp_assert);
3462 Value clock, predicate, enable;
3463 StringRef formatString;
3465 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3466 parseToken(FIRToken::comma,
"expected ','") ||
3467 parseExp(predicate,
"expected predicate in 'assert'") ||
3468 parseToken(FIRToken::comma,
"expected ','") ||
3469 parseExp(enable,
"expected enable in 'assert'") ||
3470 parseToken(FIRToken::comma,
"expected ','") ||
3471 parseGetSpelling(formatString) ||
3472 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3475 SmallVector<Value, 4> operands;
3476 while (!consumeIf(FIRToken::r_paren)) {
3477 operands.push_back({});
3478 if (parseToken(FIRToken::comma,
"expected ','") ||
3479 parseExp(operands.back(),
"expected operand in 'assert'"))
3483 if (parseOptionalName(name) || parseOptionalInfo())
3486 locationProcessor.setLoc(startTok.getLoc());
3488 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3489 operands, name.getValue());
3494ParseResult FIRStmtParser::parseAssume() {
3495 auto startTok = consumeToken(FIRToken::lp_assume);
3497 Value clock, predicate, enable;
3498 StringRef formatString;
3500 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3501 parseToken(FIRToken::comma,
"expected ','") ||
3502 parseExp(predicate,
"expected predicate in 'assume'") ||
3503 parseToken(FIRToken::comma,
"expected ','") ||
3504 parseExp(enable,
"expected enable in 'assume'") ||
3505 parseToken(FIRToken::comma,
"expected ','") ||
3506 parseGetSpelling(formatString) ||
3507 parseToken(FIRToken::string,
"expected format string in 'assume'"))
3510 SmallVector<Value, 4> operands;
3511 while (!consumeIf(FIRToken::r_paren)) {
3512 operands.push_back({});
3513 if (parseToken(FIRToken::comma,
"expected ','") ||
3514 parseExp(operands.back(),
"expected operand in 'assume'"))
3518 if (parseOptionalName(name) || parseOptionalInfo())
3521 locationProcessor.setLoc(startTok.getLoc());
3523 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3524 operands, name.getValue());
3529ParseResult FIRStmtParser::parseCover() {
3530 auto startTok = consumeToken(FIRToken::lp_cover);
3532 Value clock, predicate, enable;
3535 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3536 parseToken(FIRToken::comma,
"expected ','") ||
3537 parseExp(predicate,
"expected predicate in 'cover'") ||
3538 parseToken(FIRToken::comma,
"expected ','") ||
3539 parseExp(enable,
"expected enable in 'cover'") ||
3540 parseToken(FIRToken::comma,
"expected ','") ||
3541 parseGetSpelling(message) ||
3542 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3543 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3544 parseOptionalName(name) || parseOptionalInfo())
3547 locationProcessor.setLoc(startTok.getLoc());
3549 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3550 ValueRange{}, name.getValue());
3556ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3557 auto startTok = consumeToken(FIRToken::kw_when);
3561 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3565 if (parseExp(condition,
"expected condition in 'when'") ||
3566 parseToken(FIRToken::colon,
"expected ':' in when") ||
3567 parseOptionalInfo())
3570 locationProcessor.setLoc(startTok.getLoc());
3572 auto whenStmt = WhenOp::create(builder, condition,
false);
3575 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3579 if (getToken().isNot(FIRToken::kw_else))
3584 auto elseIndent = getIndentation();
3585 if (elseIndent && *elseIndent < whenIndent)
3588 consumeToken(FIRToken::kw_else);
3591 whenStmt.createElseRegion();
3597 if (getToken().is(FIRToken::kw_when)) {
3599 auto subParser = std::make_unique<FIRStmtParser>(
3600 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3603 return subParser->parseSimpleStmt(whenIndent);
3607 LocationAttr elseLoc;
3608 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3609 parseOptionalInfoLocator(elseLoc) ||
3610 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3619ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3620 auto startLoc = getToken().getLoc();
3621 locationProcessor.setLoc(startLoc);
3623 if (parseEnumType(type))
3627 auto enumType = type_dyn_cast<FEnumType>(type);
3629 return emitError(startLoc,
3630 "expected enumeration type in enumeration expression");
3633 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3634 parseId(tag,
"expected enumeration tag"))
3638 if (consumeIf(FIRToken::r_paren)) {
3641 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3642 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3643 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3644 input = ConstantOp::create(builder, type, attr);
3647 if (parseToken(FIRToken::comma,
"expected ','") ||
3648 parseExp(input,
"expected expression in enumeration value") ||
3649 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3653 value = FEnumCreateOp::create(builder, enumType, tag, input);
3661ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3662 auto startTok = consumeToken(FIRToken::kw_match);
3664 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3668 if (parseExp(input,
"expected expression in 'match'") ||
3669 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3670 parseOptionalInfo())
3673 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3675 return mlir::emitError(
3677 "expected enumeration type for 'match' statement, but got ")
3680 locationProcessor.setLoc(startTok.getLoc());
3682 SmallVector<Attribute> tags;
3683 SmallVector<std::unique_ptr<Region>> regions;
3685 auto tagLoc = getToken().getLoc();
3688 auto caseIndent = getIndentation();
3689 if (!caseIndent || *caseIndent <= matchIndent)
3693 StringRef tagSpelling;
3694 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3696 auto tagIndex = enumType.getElementIndex(tagSpelling);
3698 return emitError(tagLoc,
"tag ")
3699 << tagSpelling <<
" not a member of enumeration " << enumType;
3700 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3701 tags.push_back(tag);
3704 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3707 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3712 UnbundledValueRestorer x(moduleContext.unbundledValues);
3715 if (consumeIf(FIRToken::l_paren)) {
3716 StringAttr identifier;
3717 if (parseId(identifier,
"expected identifier for 'case' binding"))
3721 auto dataType = enumType.getElementType(*tagIndex);
3722 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3724 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3728 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3732 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3733 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3736 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3740 auto subParser = std::make_unique<FIRStmtParser>(
3741 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3743 if (subParser->parseSimpleStmtBlock(*caseIndent))
3747 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3754ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3755 auto loc = getToken().getLoc();
3758 if (parseId(
id,
"expected domain expression") ||
3759 moduleContext.lookupSymbolEntry(entry,
id, loc))
3762 if (moduleContext.resolveSymbolEntry(result, entry, loc,
false)) {
3764 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3765 parseFieldId(field,
"expected field name") ||
3766 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3770 if (parseOptionalExpPostscript(result,
false))
3773 auto type = result.getType();
3774 if (!type_isa<DomainType>(type))
3775 return emitError(loc) <<
"expected domain-type expression, got " << type;
3782ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3783 auto token = getToken().getKind();
3784 if (token == FIRToken::lp_probe)
3785 return parseProbe(result);
3786 if (token == FIRToken::lp_rwprobe)
3787 return parseRWProbe(result);
3792 return parseStaticRefExp(result, message);
3799ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3800 const Twine &message) {
3801 auto parseIdOrInstance = [&]() -> ParseResult {
3803 auto loc = getToken().getLoc();
3805 if (parseId(
id, message) ||
3806 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3810 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3813 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3816 StringRef fieldName;
3818 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3819 parseFieldId(fieldName,
"expected field name") ||
3820 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3822 return failure(parseIdOrInstance() ||
3823 parseOptionalExpPostscript(result,
false));
3834ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3836 const Twine &message) {
3837 auto loc = getToken().getLoc();
3841 if (parseId(
id, message) ||
3842 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3854 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3856 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3858 StringRef fieldName;
3859 auto loc = getToken().getLoc();
3860 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3861 parseFieldId(fieldName,
"expected field name"))
3866 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3867 for (
auto &elt : ubEntry) {
3868 if (elt.first == fieldAttr) {
3871 auto &instResult = elt.second;
3874 auto *defining = instResult.getDefiningOp();
3876 if (isa<WireOp>(defining)) {
3877 result = instResult;
3882 auto type = instResult.getType();
3886 bool forceable =
static_cast<bool>(
3889 return emitError(loc,
"unable to force instance result of type ")
3893 auto annotations = getConstants().emptyArrayAttr;
3894 StringAttr sym = {};
3895 SmallString<64> name;
3896 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3897 locationProcessor.setLoc(loc);
3898 OpBuilder::InsertionGuard guard(builder);
3899 builder.setInsertionPoint(defining);
3901 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3903 auto bounceVal = bounce.getData();
3906 instResult.replaceAllUsesWith(bounceVal);
3909 builder.setInsertionPointAfter(defining);
3910 if (
foldFlow(instResult) == Flow::Source)
3917 result = instResult = bounce.getDataRaw();
3923 emitError(loc,
"use of invalid field name '")
3924 << fieldName <<
"' on bundle value";
3929 result = cast<Value>(symtabEntry);
3933 assert(isa<BlockArgument>(result) ||
3934 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3940 type = result.getType();
3942 if (consumeIf(FIRToken::period)) {
3943 SmallVector<StringRef, 3> fields;
3944 if (parseFieldIdSeq(fields,
"expected field name"))
3946 for (
auto fieldName : fields) {
3947 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3948 if (
auto index = bundle.getElementIndex(fieldName)) {
3949 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3950 type = bundle.getElementTypePreservingConst(*index);
3953 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3954 if (
auto index = bundle.getElementIndex(fieldName)) {
3955 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3956 type = bundle.getElementTypePreservingConst(*index);
3960 return emitError(loc,
"subfield requires bundle operand")
3961 <<
"got " << type <<
"\n";
3963 return emitError(loc,
3964 "unknown field '" + fieldName +
"' in bundle type ")
3969 if (consumeIf(FIRToken::l_square)) {
3970 auto loc = getToken().
getLoc();
3972 if (parseIntLit(index,
"expected index") ||
3973 parseToken(FIRToken::r_square,
"expected ']'"))
3977 return emitError(loc,
"invalid index specifier");
3979 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3980 if ((
unsigned)index < vector.getNumElements()) {
3981 refResult = refResult.
getSubField(vector.getFieldID(index));
3982 type = vector.getElementTypePreservingConst();
3985 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3986 if ((
unsigned)index < vector.getNumElements()) {
3987 refResult = refResult.
getSubField(vector.getFieldID(index));
3988 type = vector.getElementTypePreservingConst();
3992 return emitError(loc,
"subindex requires vector operand");
3994 return emitError(loc,
"out of range index '")
3995 << index <<
"' for vector type " << type;
4003ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
4004 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4005 StringRef intrinsic;
4006 ArrayAttr parameters;
4009 if (parseId(intrinsic,
"expected intrinsic identifier") ||
4010 parseOptionalParams(parameters))
4013 if (consumeIf(FIRToken::colon)) {
4014 if (
parseType(type,
"expected intrinsic return type"))
4016 }
else if (!isStatement)
4017 return emitError(
"expected ':' in intrinsic expression");
4019 SmallVector<Value> operands;
4020 auto loc = startTok.getLoc();
4021 if (consumeIf(FIRToken::comma)) {
4022 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4024 if (parseExp(operand,
"expected operand in intrinsic"))
4026 operands.push_back(operand);
4027 locationProcessor.setLoc(loc);
4032 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
4037 if (parseOptionalInfo())
4040 locationProcessor.setLoc(loc);
4042 auto op = GenericIntrinsicOp::create(
4043 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4045 result = op.getResult();
4050ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4051 if (!consumeIf(FIRToken::less))
4054 SmallVector<Attribute, 8> parameters;
4055 SmallPtrSet<StringAttr, 8> seen;
4056 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4060 if (parseParameter(name, value, loc))
4062 auto typedValue = dyn_cast<TypedAttr>(value);
4064 return emitError(loc)
4065 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4066 if (!seen.insert(name).second)
4067 return emitError(loc,
"redefinition of parameter '" +
4068 name.getValue() +
"'");
4069 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4074 resultParameters = ArrayAttr::get(getContext(), parameters);
4080ParseResult FIRStmtParser::parsePathExp(Value &result) {
4081 auto startTok = consumeToken(FIRToken::lp_path);
4082 locationProcessor.setLoc(startTok.getLoc());
4084 if (parseGetSpelling(target) ||
4085 parseToken(FIRToken::string,
4086 "expected target string in path expression") ||
4087 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4089 result = UnresolvedPathOp::create(
4095ParseResult FIRStmtParser::parseDomainInstantiation() {
4096 auto startTok = consumeToken(FIRToken::kw_domain);
4099 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4102 locationProcessor.setLoc(startTok.getLoc());
4104 StringAttr instanceName;
4105 StringAttr domainKind;
4108 parseId(instanceName,
"expected domain instance name") ||
4109 parseToken(FIRToken::kw_of,
"expected 'of' after domain instance name") ||
4110 parseId(domainKind,
"expected domain type name") || parseOptionalInfo())
4115 const auto &domainMap = getConstants().domainMap;
4116 auto lookup = domainMap.find(domainKind.getValue());
4117 if (lookup == domainMap.end())
4118 return emitError(startTok.getLoc())
4119 <<
"unknown domain '" << domainKind.getValue() <<
"'";
4121 auto domainType = DomainType::getFromDomainOp(lookup->second);
4122 auto result = builder.create<DomainCreateOp>(domainType, instanceName);
4125 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4130ParseResult FIRStmtParser::parseDomainDefine() {
4131 auto startTok = consumeToken(FIRToken::kw_domain_define);
4132 auto startLoc = startTok.getLoc();
4133 locationProcessor.setLoc(startLoc);
4137 parseDomainExp(dest) || parseToken(FIRToken::equal,
"expected '='") ||
4138 parseDomainExp(src) || parseOptionalInfo())
4146ParseResult FIRStmtParser::parseRefDefine() {
4147 auto startTok = consumeToken(FIRToken::kw_define);
4150 if (parseStaticRefExp(target,
4151 "expected static reference expression in 'define'") ||
4152 parseToken(FIRToken::equal,
4153 "expected '=' after define reference expression") ||
4154 parseRefExp(src,
"expected reference expression in 'define'") ||
4155 parseOptionalInfo())
4159 if (!type_isa<RefType>(target.getType()))
4160 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4161 "'define' target (LHS), got ")
4162 << target.getType();
4163 if (!type_isa<RefType>(src.getType()))
4164 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4165 "'define' source (RHS), got ")
4170 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4171 return emitError(startTok.getLoc(),
4172 "cannot define into a sub-element of a reference");
4174 locationProcessor.setLoc(startTok.getLoc());
4177 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4178 << target.getType() <<
" with incompatible reference of type "
4188ParseResult FIRStmtParser::parseRefRead(Value &result) {
4189 auto startTok = consumeToken(FIRToken::lp_read);
4192 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4193 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4196 locationProcessor.setLoc(startTok.getLoc());
4199 if (!type_isa<RefType>(ref.getType()))
4200 return emitError(startTok.getLoc(),
4201 "expected reference-type expression in 'read', got ")
4204 result = RefResolveOp::create(builder, ref);
4210ParseResult FIRStmtParser::parseProbe(Value &result) {
4211 auto startTok = consumeToken(FIRToken::lp_probe);
4214 if (parseStaticRefExp(staticRef,
4215 "expected static reference expression in 'probe'") ||
4216 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4219 locationProcessor.setLoc(startTok.getLoc());
4222 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4223 return emitError(startTok.getLoc(),
4224 "expected base-type expression in 'probe', got ")
4225 << staticRef.getType();
4229 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4230 MemoryDebugPortOp, MemoryPortAccessOp>(
4231 staticRef.getDefiningOp()))
4232 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4234 result = RefSendOp::create(builder, staticRef);
4240ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4241 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4244 Type parsedTargetType;
4245 if (parseRWProbeStaticRefExp(
4246 staticRef, parsedTargetType,
4247 "expected static reference expression in 'rwprobe'") ||
4248 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4251 locationProcessor.setLoc(startTok.getLoc());
4257 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4259 return emitError(startTok.getLoc(),
4260 "expected base-type expression in 'rwprobe', got ")
4261 << parsedTargetType;
4264 auto *definingOp = root.getDefiningOp();
4266 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4267 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4268 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4272 return emitError(startTok.getLoc(),
"cannot force target of type ")
4276 auto op = RWProbeOp::create(builder, forceableType,
4277 getConstants().placeholderInnerRef);
4284ParseResult FIRStmtParser::parseRefForce() {
4285 auto startTok = consumeToken(FIRToken::lp_force);
4287 Value clock, pred, dest, src;
4288 if (parseExp(clock,
"expected clock expression in force") ||
4289 parseToken(FIRToken::comma,
"expected ','") ||
4290 parseExp(pred,
"expected predicate expression in force") ||
4291 parseToken(FIRToken::comma,
"expected ','") ||
4292 parseRefExp(dest,
"expected destination reference expression in force") ||
4293 parseToken(FIRToken::comma,
"expected ','") ||
4294 parseExp(src,
"expected source expression in force") ||
4295 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4296 parseOptionalInfo())
4300 auto ref = type_dyn_cast<RefType>(dest.getType());
4301 if (!ref || !ref.getForceable())
4304 "expected rwprobe-type expression for force destination, got ")
4306 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4308 return emitError(startTok.getLoc(),
4309 "expected base-type for force source, got ")
4311 if (!srcBaseType.isPassive())
4312 return emitError(startTok.getLoc(),
4313 "expected passive value for force source, got ")
4316 locationProcessor.setLoc(startTok.getLoc());
4319 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4320 if (noConstSrcType != ref.getType()) {
4322 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4324 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4326 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4327 << src.getType() <<
" cannot target destination "
4331 RefForceOp::create(builder, clock, pred, dest, src);
4337ParseResult FIRStmtParser::parseRefForceInitial() {
4338 auto startTok = consumeToken(FIRToken::lp_force_initial);
4342 dest,
"expected destination reference expression in force_initial") ||
4343 parseToken(FIRToken::comma,
"expected ','") ||
4344 parseExp(src,
"expected source expression in force_initial") ||
4345 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4346 parseOptionalInfo())
4350 auto ref = type_dyn_cast<RefType>(dest.getType());
4351 if (!ref || !ref.getForceable())
4352 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4353 "force_initial destination, got ")
4355 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4357 return emitError(startTok.getLoc(),
4358 "expected base-type expression for force_initial "
4361 if (!srcBaseType.isPassive())
4362 return emitError(startTok.getLoc(),
4363 "expected passive value for force_initial source, got ")
4366 locationProcessor.setLoc(startTok.getLoc());
4369 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4370 if (noConstSrcType != ref.getType()) {
4372 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4374 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4376 return emitError(startTok.getLoc(),
4377 "incompatible force_initial source of type ")
4378 << src.getType() <<
" cannot target destination "
4382 auto value = APInt::getAllOnes(1);
4383 auto type = UIntType::get(builder.getContext(), 1);
4384 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4385 value.getBitWidth(),
4386 IntegerType::Unsigned),
4388 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4389 RefForceInitialOp::create(builder, pred, dest, src);
4395ParseResult FIRStmtParser::parseRefRelease() {
4396 auto startTok = consumeToken(FIRToken::lp_release);
4398 Value clock, pred, dest;
4399 if (parseExp(clock,
"expected clock expression in release") ||
4400 parseToken(FIRToken::comma,
"expected ','") ||
4401 parseExp(pred,
"expected predicate expression in release") ||
4402 parseToken(FIRToken::comma,
"expected ','") ||
4404 "expected destination reference expression in release") ||
4405 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4406 parseOptionalInfo())
4410 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4411 !ref || !ref.getForceable())
4414 "expected rwprobe-type expression for release destination, got ")
4417 locationProcessor.setLoc(startTok.getLoc());
4419 RefReleaseOp::create(builder, clock, pred, dest);
4425ParseResult FIRStmtParser::parseRefReleaseInitial() {
4426 auto startTok = consumeToken(FIRToken::lp_release_initial);
4431 "expected destination reference expression in release_initial") ||
4432 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4433 parseOptionalInfo())
4437 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4438 !ref || !ref.getForceable())
4439 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4440 "release_initial destination, got ")
4443 locationProcessor.setLoc(startTok.getLoc());
4445 auto value = APInt::getAllOnes(1);
4446 auto type = UIntType::get(builder.getContext(), 1);
4447 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4448 value.getBitWidth(),
4449 IntegerType::Unsigned),
4451 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4452 RefReleaseInitialOp::create(builder, pred, dest);
4458ParseResult FIRStmtParser::parseConnect() {
4459 auto startTok = consumeToken(FIRToken::kw_connect);
4460 auto loc = startTok.getLoc();
4463 if (parseExp(lhs,
"expected connect expression") ||
4464 parseToken(FIRToken::comma,
"expected ','") ||
4465 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4468 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4469 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4470 if (!lhsType || !rhsType)
4471 return emitError(loc,
"cannot connect reference or property types");
4473 if (lhsType.containsReference() || rhsType.containsReference())
4474 return emitError(loc,
"cannot connect types containing references");
4477 return emitError(loc,
"cannot connect non-equivalent type ")
4478 << rhsType <<
" to " << lhsType;
4480 locationProcessor.setLoc(loc);
4486ParseResult FIRStmtParser::parsePropAssign() {
4487 auto startTok = consumeToken(FIRToken::kw_propassign);
4488 auto loc = startTok.getLoc();
4491 if (parseExp(lhs,
"expected propassign expression") ||
4492 parseToken(FIRToken::comma,
"expected ','") ||
4493 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4496 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4497 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4498 if (!lhsType || !rhsType)
4499 return emitError(loc,
"can only propassign property types");
4500 locationProcessor.setLoc(loc);
4501 if (lhsType != rhsType) {
4503 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4504 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4506 return emitError(loc,
"cannot propassign non-equivalent type ")
4507 << rhsType <<
" to " << lhsType;
4509 PropAssignOp::create(builder, lhs, rhs);
4514ParseResult FIRStmtParser::parseInvalidate() {
4515 auto startTok = consumeToken(FIRToken::kw_invalidate);
4520 auto loc = getToken().getLoc();
4522 if (parseId(
id,
"expected static reference expression") ||
4523 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4528 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4529 if (parseOptionalExpPostscript(lhs,
false) ||
4530 parseOptionalInfo())
4533 locationProcessor.setLoc(startTok.getLoc());
4534 emitInvalidate(lhs);
4541 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4543 if (getToken().isNot(FIRToken::period)) {
4544 locationProcessor.setLoc(loc);
4546 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4548 for (
auto elt : ubEntry)
4549 emitInvalidate(elt.second);
4555 StringRef fieldName;
4556 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4557 parseFieldId(fieldName,
"expected field name") ||
4558 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4562 if (parseOptionalExpPostscript(lhs,
false) ||
4563 parseOptionalInfo())
4566 locationProcessor.setLoc(startTok.getLoc());
4567 emitInvalidate(lhs);
4571ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4573 auto startTok = consumeToken();
4574 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4575 "consumed an unexpected token");
4576 auto loc = startTok.getLoc();
4579 if (parseId(
id,
"expected layer identifer") ||
4580 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4581 parseOptionalInfo())
4584 locationProcessor.setLoc(loc);
4586 StringRef rootLayer;
4587 SmallVector<FlatSymbolRefAttr> nestedLayers;
4591 rootLayer = layerSym.getRootReference();
4592 auto nestedRefs = layerSym.getNestedReferences();
4593 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4594 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4597 auto layerBlockOp = LayerBlockOp::create(
4599 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4600 layerBlockOp->getRegion(0).push_back(
new Block());
4602 if (getIndentation() > indent)
4603 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4604 layerBlockOp.getLayerName()))
4612ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4613 auto loc = getToken().getLoc();
4616 if (consumeIf(FIRToken::kw_is)) {
4617 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4618 parseOptionalInfo())
4621 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4624 locationProcessor.setLoc(loc);
4625 emitInvalidate(lhs);
4629 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4632 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4636 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4639 locationProcessor.setLoc(loc);
4641 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4642 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4643 if (!lhsType || !rhsType)
4644 return emitError(loc,
"cannot connect reference or property types");
4646 if (lhsType.containsReference() || rhsType.containsReference())
4647 return emitError(loc,
"cannot connect types containing references");
4650 return emitError(loc,
"cannot connect non-equivalent type ")
4651 << rhsType <<
" to " << lhsType;
4660ParseResult FIRStmtParser::parseInstance() {
4661 auto startTok = consumeToken(FIRToken::kw_inst);
4665 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4669 StringRef moduleName;
4670 if (parseId(
id,
"expected instance name") ||
4671 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4672 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4675 locationProcessor.setLoc(startTok.getLoc());
4678 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4679 if (!referencedModule)
4682 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4684 auto annotations = getConstants().emptyArrayAttr;
4685 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4687 hw::InnerSymAttr sym = {};
4688 auto result = InstanceOp::create(
4689 builder, referencedModule,
id, NameKindEnum::InterestingName,
4690 annotations.getValue(), portAnnotations,
false,
false, sym);
4696 unbundledValueEntry.reserve(modulePorts.size());
4697 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4698 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4702 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4703 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4704 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4709ParseResult FIRStmtParser::parseInstanceChoice() {
4710 auto startTok = consumeToken(FIRToken::kw_instchoice);
4711 SMLoc loc = startTok.getLoc();
4714 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4721 StringRef defaultModuleName;
4722 StringRef optionGroupName;
4723 if (parseId(
id,
"expected instance name") ||
4724 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4725 parseId(defaultModuleName,
"expected module name") ||
4726 parseToken(FIRToken::comma,
"expected ','") ||
4727 parseId(optionGroupName,
"expected option group name") ||
4728 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4729 parseOptionalInfo())
4732 locationProcessor.setLoc(startTok.getLoc());
4736 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4740 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4743 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4745 return emitError(loc,
4746 "use of undefined option group '" + optionGroupName +
"'");
4748 auto baseIndent = getIndentation();
4749 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4750 while (getIndentation() == baseIndent) {
4752 StringRef caseModuleName;
4753 if (parseId(caseId,
"expected a case identifier") ||
4754 parseToken(FIRToken::equal_greater,
4755 "expected '=> in instance choice definition") ||
4756 parseId(caseModuleName,
"expected module name"))
4759 auto caseModule = getReferencedModule(loc, caseModuleName);
4763 for (
const auto &[defaultPort, casePort] :
4764 llvm::zip(modulePorts, caseModule.getPorts())) {
4765 if (defaultPort.name != casePort.name)
4766 return emitError(loc,
"instance case module port '")
4767 << casePort.name.getValue()
4768 <<
"' does not match the default module port '"
4769 << defaultPort.name.getValue() <<
"'";
4770 if (defaultPort.type != casePort.type)
4771 return emitError(loc,
"instance case port '")
4772 << casePort.name.getValue()
4773 <<
"' type does not match the default module port";
4777 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4779 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4780 caseModules.emplace_back(optionCase, caseModule);
4783 auto annotations = getConstants().emptyArrayAttr;
4784 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4788 auto result = InstanceChoiceOp::create(
4789 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4790 annotations.getValue(), portAnnotations, sym);
4794 unbundledValueEntry.reserve(modulePorts.size());
4795 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4796 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4798 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4799 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4800 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4803FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4804 StringRef moduleName) {
4805 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4806 if (!referencedModule) {
4808 "use of undefined module name '" + moduleName +
"' in instance");
4811 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4812 emitError(loc,
"cannot create instance of class '" + moduleName +
4813 "', did you mean object?");
4816 return referencedModule;
4820ParseResult FIRStmtParser::parseObject() {
4821 auto startTok = consumeToken(FIRToken::kw_object);
4825 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4832 StringRef className;
4833 if (parseId(
id,
"expected object name") ||
4834 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4835 parseId(className,
"expected class name") || parseOptionalInfo())
4838 locationProcessor.setLoc(startTok.getLoc());
4841 const auto &classMap = getConstants().classMap;
4842 auto lookup = classMap.find(className);
4843 if (lookup == classMap.end())
4844 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4845 className +
"' in object");
4846 auto referencedClass = lookup->getSecond();
4847 auto result = ObjectOp::create(builder, referencedClass,
id);
4848 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4852ParseResult FIRStmtParser::parseCombMem() {
4854 auto startTok = consumeToken(FIRToken::kw_cmem);
4858 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4863 if (parseId(
id,
"expected cmem name") ||
4864 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4865 parseType(type,
"expected cmem type") || parseOptionalInfo())
4868 locationProcessor.setLoc(startTok.getLoc());
4871 auto vectorType = type_dyn_cast<FVectorType>(type);
4873 return emitError(
"cmem requires vector type");
4875 auto annotations = getConstants().emptyArrayAttr;
4876 StringAttr sym = {};
4877 auto result = CombMemOp::create(
4878 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4879 NameKindEnum::InterestingName, annotations, sym);
4880 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4884ParseResult FIRStmtParser::parseSeqMem() {
4886 auto startTok = consumeToken(FIRToken::kw_smem);
4890 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4895 RUWBehavior ruw = RUWBehavior::Undefined;
4897 if (parseId(
id,
"expected smem name") ||
4898 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4902 if (consumeIf(FIRToken::comma)) {
4907 if (parseOptionalInfo()) {
4911 locationProcessor.setLoc(startTok.getLoc());
4914 auto vectorType = type_dyn_cast<FVectorType>(type);
4916 return emitError(
"smem requires vector type");
4918 auto annotations = getConstants().emptyArrayAttr;
4919 StringAttr sym = {};
4920 auto result = SeqMemOp::create(
4921 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4922 id, NameKindEnum::InterestingName, annotations, sym);
4923 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4935ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4936 auto startTok = consumeToken(FIRToken::kw_mem);
4940 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4944 if (parseId(
id,
"expected mem name") ||
4945 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4949 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4950 RUWBehavior ruw = RUWBehavior::Undefined;
4952 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4956 auto nextIndent = getIndentation();
4957 if (!nextIndent || *nextIndent <= memIndent)
4960 auto spelling = getTokenSpelling();
4961 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4962 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4965 if (spelling ==
"data-type") {
4967 return emitError(
"'mem' type specified multiple times"), failure();
4969 if (
parseType(type,
"expected type in data-type declaration"))
4973 if (spelling ==
"depth") {
4974 if (parseIntLit(depth,
"expected integer in depth specification"))
4978 if (spelling ==
"read-latency") {
4979 if (parseIntLit(readLatency,
"expected integer latency"))
4983 if (spelling ==
"write-latency") {
4984 if (parseIntLit(writeLatency,
"expected integer latency"))
4988 if (spelling ==
"read-under-write") {
4989 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4990 FIRToken::kw_undefined))
4991 return emitError(
"expected specifier"), failure();
4993 if (parseOptionalRUW(ruw))
4998 MemOp::PortKind portKind;
4999 if (spelling ==
"reader")
5000 portKind = MemOp::PortKind::Read;
5001 else if (spelling ==
"writer")
5002 portKind = MemOp::PortKind::Write;
5003 else if (spelling ==
"readwriter")
5004 portKind = MemOp::PortKind::ReadWrite;
5006 return emitError(
"unexpected field in 'mem' declaration"), failure();
5009 if (parseId(portName,
"expected port name"))
5011 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5013 return emitError(
"unexpected type, must be base type");
5014 ports.push_back({builder.getStringAttr(portName),
5015 MemOp::getTypeForPort(depth, baseType, portKind)});
5017 while (!getIndentation().has_value()) {
5018 if (parseId(portName,
"expected port name"))
5020 ports.push_back({builder.getStringAttr(portName),
5021 MemOp::getTypeForPort(depth, baseType, portKind)});
5032 llvm::array_pod_sort(ports.begin(), ports.end(),
5033 [](
const std::pair<StringAttr, Type> *lhs,
5034 const std::pair<StringAttr, Type> *rhs) ->
int {
5035 return lhs->first.getValue().compare(
5036 rhs->first.getValue());
5039 auto annotations = getConstants().emptyArrayAttr;
5040 SmallVector<Attribute, 4> resultNames;
5041 SmallVector<Type, 4> resultTypes;
5042 SmallVector<Attribute, 4> resultAnnotations;
5043 for (
auto p : ports) {
5044 resultNames.push_back(p.first);
5045 resultTypes.push_back(p.second);
5046 resultAnnotations.push_back(annotations);
5049 locationProcessor.setLoc(startTok.getLoc());
5051 auto result = MemOp::create(
5052 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5053 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
5054 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5055 MemoryInitAttr(), StringAttr());
5058 unbundledValueEntry.reserve(result.getNumResults());
5059 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
5060 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5062 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5063 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
5064 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
5068ParseResult FIRStmtParser::parseNode() {
5069 auto startTok = consumeToken(FIRToken::kw_node);
5073 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5078 if (parseId(
id,
"expected node name") ||
5079 parseToken(FIRToken::equal,
"expected '=' in node") ||
5080 parseExp(initializer,
"expected expression for node") ||
5081 parseOptionalInfo())
5084 locationProcessor.setLoc(startTok.getLoc());
5096 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5097 auto initializerBaseType =
5098 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5099 if (type_isa<AnalogType>(initializerType) ||
5100 !(initializerBaseType && initializerBaseType.isPassive())) {
5101 emitError(startTok.getLoc())
5102 <<
"Node cannot be analog and must be passive or passive under a flip "
5103 << initializer.getType();
5107 auto annotations = getConstants().emptyArrayAttr;
5108 StringAttr sym = {};
5110 auto result = NodeOp::create(builder, initializer,
id,
5111 NameKindEnum::InterestingName, annotations, sym);
5112 return moduleContext.addSymbolEntry(
id, result.getResult(),
5117ParseResult FIRStmtParser::parseWire() {
5118 auto startTok = consumeToken(FIRToken::kw_wire);
5122 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5127 if (parseId(
id,
"expected wire name") ||
5128 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5129 parseType(type,
"expected wire type") || parseOptionalInfo())
5132 locationProcessor.setLoc(startTok.getLoc());
5134 auto annotations = getConstants().emptyArrayAttr;
5135 StringAttr sym = {};
5138 auto namekind = isa<PropertyType, RefType>(type)
5139 ? NameKindEnum::DroppableName
5140 : NameKindEnum::InterestingName;
5142 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
5143 return moduleContext.addSymbolEntry(
id, result.getResult(),
5157ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5158 auto startTok = consumeToken(FIRToken::kw_reg);
5162 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5171 if (parseId(
id,
"expected reg name") ||
5172 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5174 parseToken(FIRToken::comma,
"expected ','") ||
5175 parseExp(clock,
"expected expression for register clock"))
5178 if (!type_isa<FIRRTLBaseType>(type))
5179 return emitError(startTok.getLoc(),
"register must have base type");
5182 Value resetSignal, resetValue;
5183 if (consumeIf(FIRToken::kw_with)) {
5184 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5187 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5195 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5197 auto indent = getIndentation();
5198 if (!indent || *indent <= regIndent)
5199 if (!hasExtraLParen)
5200 return emitError(
"expected indented reset specifier in reg"), failure();
5202 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5203 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5204 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5205 parseExp(resetSignal,
"expected expression for reset signal") ||
5206 parseToken(FIRToken::comma,
"expected ','"))
5214 if (getTokenSpelling() ==
id) {
5216 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5218 resetSignal = Value();
5220 if (parseExp(resetValue,
"expected expression for reset value") ||
5221 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5225 if (hasExtraLParen &&
5226 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5232 if (parseOptionalInfo())
5235 locationProcessor.setLoc(startTok.getLoc());
5237 ArrayAttr annotations = getConstants().emptyArrayAttr;
5239 StringAttr sym = {};
5242 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5243 NameKindEnum::InterestingName, annotations, sym)
5246 result = RegOp::create(builder, type, clock,
id,
5247 NameKindEnum::InterestingName, annotations, sym)
5249 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5257ParseResult FIRStmtParser::parseRegisterWithReset() {
5258 auto startTok = consumeToken(FIRToken::kw_regreset);
5262 Value clock, resetSignal, resetValue;
5264 if (parseId(
id,
"expected reg name") ||
5265 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5267 parseToken(FIRToken::comma,
"expected ','") ||
5268 parseExp(clock,
"expected expression for register clock") ||
5269 parseToken(FIRToken::comma,
"expected ','") ||
5270 parseExp(resetSignal,
"expected expression for register reset") ||
5271 parseToken(FIRToken::comma,
"expected ','") ||
5272 parseExp(resetValue,
"expected expression for register reset value") ||
5273 parseOptionalInfo())
5276 if (!type_isa<FIRRTLBaseType>(type))
5277 return emitError(startTok.getLoc(),
"register must have base type");
5279 locationProcessor.setLoc(startTok.getLoc());
5282 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5283 NameKindEnum::InterestingName,
5284 getConstants().emptyArrayAttr, StringAttr{})
5287 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5292ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5296 auto startTok = consumeToken(FIRToken::kw_contract);
5299 SmallVector<StringRef> ids;
5300 SmallVector<SMLoc> locs;
5301 SmallVector<Value> values;
5302 SmallVector<Type> types;
5303 if (!consumeIf(FIRToken::colon)) {
5304 auto parseContractId = [&] {
5306 locs.push_back(getToken().
getLoc());
5307 if (parseId(
id,
"expected contract result name"))
5312 auto parseContractValue = [&] {
5314 if (parseExp(value,
"expected expression for contract result"))
5316 values.push_back(value);
5317 types.push_back(value.getType());
5320 if (parseListUntil(FIRToken::equal, parseContractId) ||
5321 parseListUntil(FIRToken::colon, parseContractValue))
5324 if (parseOptionalInfo())
5328 if (ids.size() != values.size())
5329 return emitError(startTok.getLoc())
5330 <<
"contract requires same number of results and expressions; got "
5331 << ids.size() <<
" results and " << values.size()
5332 <<
" expressions instead";
5334 locationProcessor.setLoc(startTok.getLoc());
5338 auto contract = ContractOp::create(builder, types, values);
5339 auto &block = contract.getBody().emplaceBlock();
5343 FIRModuleContext::ContextScope scope(moduleContext, &block);
5344 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5345 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5346 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5349 if (getIndentation() > blockIndent)
5350 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5355 for (
auto [
id, loc, value, result] :
5356 llvm::zip(ids, locs, values, contract.getResults())) {
5358 moduleContext.removeSymbolEntry(
id);
5359 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5372struct FIRCircuitParser :
public FIRParser {
5373 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5375 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5378 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5379 mlir::TimingScope &ts);
5384 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5385 SmallVectorImpl<Attribute> &attrs);
5387 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5389 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5390 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5391 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5392 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5393 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5394 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5395 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5396 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5398 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5400 ParseResult parseLayerName(SymbolRefAttr &result);
5401 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5402 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5403 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5404 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5405 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5406 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5407 ArrayAttr &knownLayers,
5408 ArrayAttr &externalRequirements);
5410 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5411 SmallVectorImpl<SMLoc> &resultPortLocs,
5415 ParseResult skipToModuleEnd(
unsigned indent);
5417 ParseResult parseTypeDecl();
5419 ParseResult parseOptionDecl(CircuitOp circuit);
5421 ParseResult parseLayer(CircuitOp circuit);
5423 ParseResult resolveDomains(
5424 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5425 const DenseMap<Attribute, size_t> &nameToIndex,
5426 SmallVectorImpl<Attribute> &domainsByIndex);
5429 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5430 const DenseMap<Attribute, size_t> &nameToIndex);
5432 struct DeferredModuleToParse {
5433 FModuleLike moduleOp;
5434 SmallVector<SMLoc> portLocs;
5439 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5440 DeferredModuleToParse &deferredModule,
5441 InnerSymFixups &fixups);
5443 SmallVector<DeferredModuleToParse, 0> deferredModules;
5445 SmallVector<InnerSymFixups, 0> moduleFixups;
5449 ModuleOp mlirModule;
5454FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5455 SmallVectorImpl<Attribute> &attrs) {
5457 auto annotations = json::parse(annotationsStr);
5458 if (
auto err = annotations.takeError()) {
5459 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5460 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5461 diag.attachNote() <<
a.message();
5466 json::Path::Root root;
5467 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5470 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5471 std::string jsonErrorMessage =
5472 "See inline comments for problem area in JSON:\n";
5473 llvm::raw_string_ostream
s(jsonErrorMessage);
5474 root.printErrorContext(annotations.get(), s);
5475 diag.attachNote() << jsonErrorMessage;
5482ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5484 SmallVector<StringRef> strings;
5487 if (parseId(name,
"expected layer name"))
5489 strings.push_back(name);
5490 }
while (consumeIf(FIRToken::period));
5492 SmallVector<FlatSymbolRefAttr> nested;
5493 nested.reserve(strings.size() - 1);
5494 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5495 nested.push_back(FlatSymbolRefAttr::get(
context, strings[i]));
5497 result = SymbolRefAttr::get(
context, strings[0], nested);
5501ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5502 SmallVector<Attribute> enabledLayersBuffer;
5504 auto tokenKind = getToken().getKind();
5506 if (tokenKind == FIRToken::kw_enablelayer) {
5507 if (parseEnableLayerSpec(enabledLayersBuffer))
5515 if (enabledLayersBuffer.size() != 0)
5516 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5519 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5523ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5524 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5525 ArrayAttr &externalRequirements) {
5526 SmallVector<Attribute> enabledLayersBuffer;
5527 SmallVector<Attribute> knownLayersBuffer;
5528 SmallVector<Attribute> requirementsBuffer;
5530 auto tokenKind = getToken().getKind();
5532 if (tokenKind == FIRToken::kw_enablelayer) {
5533 if (parseEnableLayerSpec(enabledLayersBuffer))
5538 if (tokenKind == FIRToken::kw_knownlayer) {
5539 if (parseKnownLayerSpec(knownLayersBuffer))
5544 if (tokenKind == FIRToken::kw_requires) {
5545 if (parseRequiresSpec(requirementsBuffer))
5553 if (enabledLayersBuffer.size() != 0)
5554 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5557 if (knownLayersBuffer.size() != 0)
5558 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5561 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5562 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5563 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5568FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5570 SymbolRefAttr layer;
5571 if (parseLayerName(layer))
5573 result.push_back(layer);
5574 }
while (consumeIf(FIRToken::comma));
5579FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5580 consumeToken(FIRToken::kw_enablelayer);
5581 return parseLayerList(result);
5585FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5586 consumeToken(FIRToken::kw_knownlayer);
5587 return parseLayerList(result);
5591FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5592 consumeToken(FIRToken::kw_requires);
5594 StringRef requireStr;
5595 if (parseGetSpelling(requireStr) ||
5596 parseToken(FIRToken::string,
"expected string after 'requires'"))
5600 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5601 }
while (consumeIf(FIRToken::comma));
5609FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5610 SmallVectorImpl<SMLoc> &resultPortLocs,
5616 DenseMap<Attribute, size_t> nameToIndex;
5617 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5620 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5622 getIndentation() > indent) {
5628 auto backtrackState = getLexer().getCursor();
5630 bool isOutput = getToken().is(FIRToken::kw_output);
5635 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5636 !getToken().isKeyword()) {
5637 backtrackState.restore(getLexer());
5644 if (parseId(name,
"expected port name") ||
5645 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5646 parseType(type,
"expected a type in port declaration"))
5648 Attribute domainInfoElement = {};
5649 size_t portIdx = resultPorts.size();
5650 if (
auto domainType = dyn_cast<DomainType>(type)) {
5652 domainInfoElement = domainType.getName();
5654 if (getToken().is(FIRToken::kw_domains))
5655 if (parseDomains(domainNames[portIdx], nameToIndex))
5659 if (
info.parseOptionalInfo())
5662 StringAttr innerSym = {};
5663 resultPorts.push_back(
PortInfo{name,
5669 domainInfoElement});
5670 resultPortLocs.push_back(
info.getFIRLoc());
5671 nameToIndex.insert({name, portIdx});
5675 for (
size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5676 auto &port = resultPorts[portIdx];
5677 Attribute &attr = port.domains;
5681 SmallVector<Attribute> domainInfo;
5682 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5684 attr = ArrayAttr::get(getContext(), domainInfo);
5689 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5690 PortInfo &port = std::get<0>(portAndLoc);
5691 auto &entry = portIds[port.
name];
5692 if (!entry.isValid()) {
5693 entry = std::get<1>(portAndLoc);
5697 emitError(std::get<1>(portAndLoc),
5698 "redefinition of name '" + port.
getName() +
"'")
5699 .attachNote(translateLocation(entry))
5700 <<
"previous definition here";
5709ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5711 switch (getToken().getKind()) {
5715 case FIRToken::error:
5719 case FIRToken::kw_class:
5720 case FIRToken::kw_domain:
5721 case FIRToken::kw_declgroup:
5722 case FIRToken::kw_extclass:
5723 case FIRToken::kw_extmodule:
5724 case FIRToken::kw_intmodule:
5725 case FIRToken::kw_formal:
5726 case FIRToken::kw_module:
5727 case FIRToken::kw_public:
5728 case FIRToken::kw_layer:
5729 case FIRToken::kw_option:
5730 case FIRToken::kw_simulation:
5731 case FIRToken::kw_type:
5735 if (getIndentation() == indent)
5747ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5748 SmallVector<Attribute, 8> parameters;
5749 SmallPtrSet<StringAttr, 8> seen;
5750 while (consumeIf(FIRToken::kw_parameter)) {
5754 if (parseParameter(name, value, loc))
5756 auto typedValue = dyn_cast<TypedAttr>(value);
5758 return emitError(loc)
5759 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5760 if (!seen.insert(name).second)
5761 return emitError(loc,
5762 "redefinition of parameter '" + name.getValue() +
"'");
5763 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5765 resultParameters = ArrayAttr::get(getContext(), parameters);
5770ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5772 SmallVector<PortInfo, 8> portList;
5773 SmallVector<SMLoc> portLocs;
5779 consumeToken(FIRToken::kw_class);
5780 if (parseId(name,
"expected class name") ||
5781 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5785 if (name == circuit.getName())
5786 return mlir::emitError(
info.getLoc(),
5787 "class cannot be the top of a circuit");
5789 for (
auto &portInfo : portList)
5791 return
mlir::emitError(portInfo.loc,
5792 "ports on classes must be properties");
5795 auto builder = circuit.getBodyBuilder();
5796 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5797 classOp.setPrivate();
5798 deferredModules.emplace_back(
5799 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5802 getConstants().classMap[name.getValue()] = classOp;
5803 return skipToModuleEnd(indent);
5807ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5808 consumeToken(FIRToken::kw_domain);
5812 if (parseId(name,
"domain name") ||
5813 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5814 info.parseOptionalInfo())
5817 SmallVector<Attribute> fields;
5819 auto nextIndent = getIndentation();
5820 if (!nextIndent || *nextIndent <= indent)
5823 StringAttr fieldName;
5825 if (parseId(fieldName,
"field name") ||
5826 parseToken(FIRToken::colon,
"expected ':' after field name") ||
5827 parsePropertyType(type,
"field type") ||
info.parseOptionalInfo())
5831 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5834 auto builder = circuit.getBodyBuilder();
5835 auto domainOp = DomainOp::create(builder,
info.getLoc(), name,
5836 builder.getArrayAttr(fields));
5840 getConstants().domainMap[name.getValue()] = domainOp;
5846ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5849 SmallVector<PortInfo, 8> portList;
5850 SmallVector<SMLoc> portLocs;
5856 consumeToken(FIRToken::kw_extclass);
5857 if (parseId(name,
"expected extclass name") ||
5858 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5862 if (name == circuit.getName())
5863 return mlir::emitError(
info.getLoc(),
5864 "extclass cannot be the top of a circuit");
5866 for (
auto &portInfo : portList)
5868 return
mlir::emitError(portInfo.loc,
5869 "ports on extclasses must be properties");
5872 auto builder = circuit.getBodyBuilder();
5873 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5876 getConstants().classMap[name.getValue()] = extClassOp;
5877 return skipToModuleEnd(indent);
5885ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5888 ArrayAttr enabledLayers;
5889 ArrayAttr knownLayers;
5890 ArrayAttr externalRequirements;
5891 SmallVector<PortInfo, 8> portList;
5892 SmallVector<SMLoc> portLocs;
5894 consumeToken(FIRToken::kw_extmodule);
5895 if (parseId(name,
"expected extmodule name") ||
5896 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
5897 externalRequirements) ||
5898 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5903 if (consumeIf(FIRToken::kw_defname)) {
5904 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5905 parseId(defName,
"expected defname name"))
5909 ArrayAttr parameters;
5914 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5915 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5916 if (ftype.hasUninferredWidth())
5917 return emitError(loc,
"extmodule port must have known width");
5922 auto builder = circuit.getBodyBuilder();
5923 auto isMainModule = (name == circuit.getName());
5925 (isMainModule && getConstants().options.scalarizePublicModules) ||
5926 getConstants().options.scalarizeExtModules
5927 ? Convention::Scalarized
5928 : Convention::Internal;
5929 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5930 auto annotations = ArrayAttr::get(getContext(), {});
5931 auto extModuleOp = FExtModuleOp::create(
5932 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5933 defName, annotations, parameters, enabledLayers, externalRequirements);
5934 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5935 : SymbolTable::Visibility::Private;
5936 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5944ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5948 ArrayAttr enabledLayers;
5949 SmallVector<PortInfo, 8> portList;
5950 SmallVector<SMLoc> portLocs;
5952 consumeToken(FIRToken::kw_intmodule);
5953 if (parseId(name,
"expected intmodule name") ||
5954 parseModuleLayerSpec(enabledLayers) ||
5955 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5957 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5958 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5959 parseId(intName,
"expected intrinsic name"))
5962 ArrayAttr parameters;
5966 ArrayAttr annotations = getConstants().emptyArrayAttr;
5967 auto builder = circuit.getBodyBuilder();
5968 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5969 annotations, parameters, enabledLayers)
5975ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5978 SmallVector<PortInfo, 8> portList;
5979 SmallVector<SMLoc> portLocs;
5980 ArrayAttr enabledLayers;
5981 auto modLoc = getToken().getLoc();
5982 LocWithInfo
info(modLoc,
this);
5983 consumeToken(FIRToken::kw_module);
5984 if (parseId(name,
"expected module name") ||
5985 parseModuleLayerSpec(enabledLayers) ||
5986 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5991 if (name == circuit.getName()) {
5992 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5997 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
5998 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5999 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6000 if (ftype.hasUninferredWidth())
6001 return emitError(loc,
"public module port must have known width");
6002 if (ftype.hasUninferredReset())
6003 return emitError(loc,
6004 "public module port must have concrete reset type");
6009 ArrayAttr annotations = getConstants().emptyArrayAttr;
6010 auto convention = Convention::Internal;
6011 if (isPublic && getConstants().options.scalarizePublicModules)
6012 convention = Convention::Scalarized;
6013 if (!isPublic && getConstants().options.scalarizeInternalModules)
6014 convention = Convention::Scalarized;
6015 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6016 auto builder = circuit.getBodyBuilder();
6018 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
6019 annotations, enabledLayers);
6021 auto visibility = isPublic ? SymbolTable::Visibility::Public
6022 : SymbolTable::Visibility::Private;
6023 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6027 deferredModules.emplace_back(DeferredModuleToParse{
6028 moduleOp, portLocs, getLexer().getCursor(), indent});
6030 if (skipToModuleEnd(indent))
6036ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
6037 consumeToken(FIRToken::kw_formal);
6038 return parseFormalLike<FormalOp>(circuit, indent);
6042ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6044 consumeToken(FIRToken::kw_simulation);
6045 return parseFormalLike<SimulationOp>(circuit, indent);
6052ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6054 StringRef id, moduleName;
6057 auto builder = circuit.getBodyBuilder();
6060 if (parseId(
id,
"expected test name") ||
6061 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
6062 parseId(moduleName,
"expected module name"))
6066 NamedAttrList params;
6067 if (consumeIf(FIRToken::comma)) {
6069 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
6070 return emitError(
"expected 'bound' after ','");
6072 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
6073 parseIntLit(bound,
"expected integer bound after '='"))
6076 return emitError(
"bound must be a positive integer");
6077 if (
info.parseOptionalInfo())
6079 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6082 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
6083 info.parseOptionalInfo())
6085 while (getIndentation() > indent) {
6086 StringAttr paramName;
6087 Attribute paramValue;
6089 if (parseParameter(paramName, paramValue, paramLoc,
6092 if (params.set(paramName, paramValue))
6093 return emitError(paramLoc,
"redefinition of parameter '" +
6094 paramName.getValue() +
"'");
6098 Op::create(builder,
info.getLoc(),
id, moduleName,
6099 params.getDictionary(getContext()));
6103ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6105 switch (getToken().getKind()) {
6106 case FIRToken::kw_class:
6107 return parseClass(circuit, indent);
6108 case FIRToken::kw_declgroup:
6109 if (requireFeature({3, 2, 0},
"optional groups") ||
6110 removedFeature({3, 3, 0},
"optional groups"))
6112 return parseLayer(circuit);
6113 case FIRToken::kw_domain:
6116 return parseDomain(circuit, indent);
6117 case FIRToken::kw_extclass:
6118 return parseExtClass(circuit, indent);
6119 case FIRToken::kw_extmodule:
6120 return parseExtModule(circuit, indent);
6121 case FIRToken::kw_formal:
6122 if (requireFeature({4, 0, 0},
"formal tests"))
6124 return parseFormal(circuit, indent);
6125 case FIRToken::kw_intmodule:
6126 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6127 removedFeature({4, 0, 0},
"intrinsic modules"))
6129 return parseIntModule(circuit, indent);
6130 case FIRToken::kw_layer:
6131 if (requireFeature({3, 3, 0},
"layers"))
6133 return parseLayer(circuit);
6134 case FIRToken::kw_module:
6135 return parseModule(circuit,
false, indent);
6136 case FIRToken::kw_public:
6137 if (requireFeature({3, 3, 0},
"public modules"))
6140 if (getToken().getKind() == FIRToken::kw_module)
6141 return parseModule(circuit,
true, indent);
6142 return emitError(getToken().
getLoc(),
"only modules may be public");
6143 case FIRToken::kw_simulation:
6146 return parseSimulation(circuit, indent);
6147 case FIRToken::kw_type:
6148 return parseTypeDecl();
6149 case FIRToken::kw_option:
6152 return parseOptionDecl(circuit);
6154 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6159ParseResult FIRCircuitParser::parseTypeDecl() {
6163 auto loc = getToken().getLoc();
6165 if (getToken().isKeyword())
6166 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6167 <<
"' for type alias name";
6169 if (parseId(
id,
"expected type name") ||
6170 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6173 auto name = StringAttr::get(type.getContext(),
id);
6176 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6177 type = BaseTypeAliasType::get(name, base);
6180 <<
"type alias for non-base type " << type
6181 <<
" is currently not supported. Type alias is stripped immediately";
6183 if (!getConstants().aliasMap.insert({id, type}).second)
6184 return emitError(loc) <<
"type alias `" << name.getValue()
6185 <<
"` is already defined";
6190ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6193 auto loc = getToken().getLoc();
6196 if (parseId(
id,
"expected an option group name") ||
6197 parseToken(FIRToken::colon,
6198 "expected ':' after option group definition") ||
6199 info.parseOptionalInfo())
6202 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6203 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6204 auto *block =
new Block;
6205 optionOp.getBody().push_back(block);
6206 builder.setInsertionPointToEnd(block);
6208 auto baseIndent = getIndentation();
6210 while (getIndentation() == baseIndent) {
6212 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6213 if (parseId(
id,
"expected an option case ID") ||
6214 caseInfo.parseOptionalInfo())
6217 if (!cases.insert(
id).second)
6218 return emitError(loc)
6219 <<
"duplicate option case definition '" <<
id <<
"'";
6221 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6228ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6229 auto baseIndent = getIndentation();
6232 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6235 auto parseOne = [&](
Block *block) -> ParseResult {
6236 auto indent = getIndentation();
6237 StringRef id, convention;
6240 if (parseId(
id,
"expected layer name") ||
6241 parseToken(FIRToken::comma,
"expected ','") ||
6242 parseGetSpelling(convention))
6245 auto layerConvention = symbolizeLayerConvention(convention);
6246 if (!layerConvention) {
6247 emitError() <<
"unknown convention '" << convention
6248 <<
"' (did you misspell it?)";
6251 if (layerConvention == LayerConvention::Inline &&
6252 requireFeature({4, 1, 0},
"inline layers"))
6256 hw::OutputFileAttr outputDir;
6257 if (consumeIf(FIRToken::comma)) {
6258 if (getToken().getKind() == FIRToken::string) {
6259 auto text = getToken().getStringValue();
6261 return emitError() <<
"output directory must not be blank";
6262 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6263 consumeToken(FIRToken::string);
6267 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6268 info.parseOptionalInfo())
6270 auto builder = OpBuilder::atBlockEnd(block);
6273 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6274 layerOp->getRegion(0).push_back(
new Block());
6276 layerOp->setAttr(
"output_file", outputDir);
6277 layerStack.push_back({indent, layerOp});
6281 if (parseOne(circuit.getBodyBlock()))
6285 while (getIndentation() > baseIndent) {
6286 switch (getToken().getKind()) {
6287 case FIRToken::kw_declgroup:
6288 case FIRToken::kw_layer: {
6291 while (layerStack.back().first >= getIndentation())
6292 layerStack.pop_back();
6293 auto parentLayer = layerStack.back().second;
6294 if (parseOne(&parentLayer.getBody().front()))
6299 return emitError(
"expected 'layer'"), failure();
6306ParseResult FIRCircuitParser::resolveDomains(
6307 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6308 const DenseMap<Attribute, size_t> &nameToIndex,
6309 SmallVectorImpl<Attribute> &domainsByIndex) {
6311 for (
auto [attr, loc] : domainsByName) {
6312 auto domain = cast<StringAttr>(attr);
6313 auto indexItr = nameToIndex.find(domain);
6314 if (indexItr == nameToIndex.end()) {
6315 emitError(loc) <<
"unknown domain name '" << domain.getValue() <<
"'";
6318 domainsByIndex.push_back(IntegerAttr::get(
6319 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6326ParseResult FIRCircuitParser::parseDomains(
6327 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6328 const DenseMap<Attribute, size_t> &nameToIndex) {
6331 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6332 parseToken(FIRToken::l_square,
"expected '['"))
6335 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6337 auto domainLoc = getToken().getLoc();
6338 if (parseId(domain,
"expected domain name"))
6340 domains.push_back({domain, domainLoc});
6350FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6351 DeferredModuleToParse &deferredModule,
6352 InnerSymFixups &fixups) {
6353 FModuleLike moduleOp = deferredModule.moduleOp;
6354 auto &body = moduleOp->getRegion(0).front();
6355 auto &portLocs = deferredModule.portLocs;
6359 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6362 deferredModule.lexerCursor.restore(moduleBodyLexer);
6364 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6369 auto portList = moduleOp.getPorts();
6370 auto portArgs = body.getArguments();
6371 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6372 PortInfo &port = std::get<0>(tuple);
6373 llvm::SMLoc loc = std::get<1>(tuple);
6374 BlockArgument portArg = std::get<2>(tuple);
6376 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6380 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6383 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6389 size_t numVerifPrintfs = 0;
6390 std::optional<Location> printfLoc;
6392 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6397 printfLoc = printFOp.getLoc();
6400 if (numVerifPrintfs > 0) {
6402 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6404 <<
" printf-encoded verification operation(s), which are no longer "
6406 diag.attachNote(*printfLoc)
6407 <<
"example printf here, this is now just a printf and nothing more";
6408 diag.attachNote() <<
"For more information, see "
6409 "https://github.com/llvm/circt/issues/6970";
6423ParseResult FIRCircuitParser::parseCircuit(
6424 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6425 mlir::TimingScope &ts) {
6427 auto indent = getIndentation();
6428 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6430 if (!indent.has_value())
6431 return emitError(
"'FIRRTL' must be first token on its line");
6432 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6433 parseVersionLit(
"expected version literal"))
6435 indent = getIndentation();
6437 if (!indent.has_value())
6438 return emitError(
"'circuit' must be first token on its line");
6439 unsigned circuitIndent = *indent;
6443 SMLoc inlineAnnotationsLoc;
6444 StringRef inlineAnnotations;
6447 if (parseToken(FIRToken::kw_circuit,
6448 "expected a top-level 'circuit' definition") ||
6449 parseId(name,
"expected circuit name") ||
6450 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6451 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6452 info.parseOptionalInfo())
6456 OpBuilder
b(mlirModule.getBodyRegion());
6457 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6460 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6466 SmallVector<Attribute> annos;
6467 if (!inlineAnnotations.empty())
6468 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6472 for (
auto *annotationsBuf : annotationsBufs)
6473 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6477 parseAnnotationTimer.stop();
6485 auto parseTimer = ts.nest(
"Parse modules");
6486 deferredModules.reserve(16);
6490 switch (getToken().getKind()) {
6498 case FIRToken::error:
6502 emitError(
"unexpected token in circuit");
6505 case FIRToken::kw_class:
6506 case FIRToken::kw_declgroup:
6507 case FIRToken::kw_domain:
6508 case FIRToken::kw_extclass:
6509 case FIRToken::kw_extmodule:
6510 case FIRToken::kw_intmodule:
6511 case FIRToken::kw_layer:
6512 case FIRToken::kw_formal:
6513 case FIRToken::kw_module:
6514 case FIRToken::kw_option:
6515 case FIRToken::kw_public:
6516 case FIRToken::kw_simulation:
6517 case FIRToken::kw_type: {
6518 auto indent = getIndentation();
6519 if (!indent.has_value())
6520 return emitError(
"'module' must be first token on its line"), failure();
6521 unsigned definitionIndent = *indent;
6523 if (definitionIndent <= circuitIndent)
6524 return emitError(
"module should be indented more"), failure();
6526 if (parseToplevelDefinition(circuit, definitionIndent))
6540 (void)getLexer().translateLocation(
info.getFIRLoc());
6546 DenseMap<Attribute, Location> nameToOrigLoc;
6550 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6555 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6558 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6559 .attachNote(it.first->second)
6560 .append(
"see existing symbol definition here");
6566 SymbolTable circuitSymTbl(circuit);
6568 moduleFixups.resize(deferredModules.size());
6573 for (
auto &d : deferredModules)
6574 innerSymbolNamespaces.
get(
d.moduleOp.getOperation());
6577 auto anyFailed = mlir::failableParallelForEachN(
6578 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6579 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6580 moduleFixups[index]))
6584 if (failed(anyFailed))
6589 for (
auto &fixups : moduleFixups) {
6590 if (failed(fixups.resolve(innerSymbolNamespaces)))
6596 auto parseLayerName = [&](StringRef name) -> Attribute {
6598 auto [head, rest] = name.split(
".");
6599 SmallVector<FlatSymbolRefAttr> nestedRefs;
6600 while (!rest.empty()) {
6602 std::tie(next, rest) = rest.split(
".");
6603 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6605 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6608 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6609 SmallVector<Attribute> attrArray;
6611 for (
const auto &str : strArray)
6612 attrArray.push_back(getAttr(str));
6613 if (attrArray.empty())
6615 return ArrayAttr::get(
context, attrArray);
6618 if (
auto enableLayers =
6619 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6620 circuit.setEnableLayersAttr(enableLayers);
6621 if (
auto disableLayers =
6622 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6623 circuit.setDisableLayersAttr(disableLayers);
6625 auto getStrAttr = [&](StringRef str) -> Attribute {
6626 return StringAttr::get(getContext(), str);
6629 if (
auto selectInstChoice =
6630 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6631 circuit.setSelectInstChoiceAttr(selectInstChoice);
6633 circuit.setDefaultLayerSpecialization(
6634 getConstants().options.defaultLayerSpecialization);
6647 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6648 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6649 unsigned fileID = 1;
6651 annotationsBufs.push_back(
6652 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6654 context->loadDialect<CHIRRTLDialect>();
6655 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6659 FileLineColLoc::get(
context, sourceBuf->getBufferIdentifier(),
6662 SharedParserConstants state(
context, options);
6665 .parseCircuit(annotationsBufs, ts))
6670 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6671 if (failed(verify(*module)))
6678 static mlir::TranslateToMLIRRegistration fromFIR(
6679 "import-firrtl",
"import .fir",
6680 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
6681 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