26#include "mlir/IR/BuiltinOps.h"
27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Diagnostics.h"
29#include "mlir/IR/ImplicitLocOpBuilder.h"
30#include "mlir/IR/PatternMatch.h"
31#include "mlir/IR/Threading.h"
32#include "mlir/IR/Verifier.h"
33#include "mlir/Support/Timing.h"
34#include "mlir/Tools/mlir-translate/Translation.h"
35#include "llvm/ADT/PointerEmbeddedInt.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallPtrSet.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/StringSet.h"
40#include "llvm/ADT/StringSwitch.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/JSON.h"
43#include "llvm/Support/LogicalResult.h"
44#include "llvm/Support/SourceMgr.h"
45#include "llvm/Support/raw_ostream.h"
50using namespace firrtl;
51using namespace chirrtl;
55using mlir::LocationAttr;
68struct SharedParserConstants {
70 : context(context), options(options),
71 emptyArrayAttr(ArrayAttr::
get(context, {})),
72 loIdentifier(StringAttr::get(context,
"lo")),
73 hiIdentifier(StringAttr::get(context,
"hi")),
74 amountIdentifier(StringAttr::get(context,
"amount")),
76 hw::InnerRefAttr::get(StringAttr::get(context,
"module"),
77 StringAttr::get(context,
"placeholder"))) {}
80 MLIRContext *
const context;
86 llvm::StringMap<FIRRTLType> aliasMap;
89 llvm::DenseMap<StringRef, ClassLike> classMap;
92 const ArrayAttr emptyArrayAttr;
95 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
98 const hw::InnerRefAttr placeholderInnerRef;
101 SharedParserConstants(
const SharedParserConstants &) =
delete;
102 void operator=(
const SharedParserConstants &) =
delete;
115 FIRParser(SharedParserConstants &constants,
FIRLexer &lexer,
117 : version(version), constants(constants), lexer(lexer),
118 locatorFilenameCache(constants.loIdentifier ) {
122 SharedParserConstants &getConstants()
const {
return constants; }
123 MLIRContext *getContext()
const {
return constants.context; }
125 FIRLexer &getLexer() {
return lexer; }
128 std::optional<unsigned> getIndentation()
const {
133 const FIRToken &getToken()
const {
return lexer.getToken(); }
134 StringRef getTokenSpelling()
const {
return getToken().
getSpelling(); }
141 InFlightDiagnostic emitError(
const Twine &message = {}) {
142 return emitError(getToken().
getLoc(), message);
144 InFlightDiagnostic emitError(SMLoc loc,
const Twine &message = {});
147 InFlightDiagnostic emitWarning(
const Twine &message = {}) {
148 return emitWarning(getToken().
getLoc(), message);
151 InFlightDiagnostic emitWarning(SMLoc loc,
const Twine &message = {});
161 Location translateLocation(llvm::SMLoc loc) {
162 return lexer.translateLocation(loc);
167 ParseResult parseOptionalInfoLocator(LocationAttr &result);
171 ParseResult parseOptionalName(StringAttr &name);
177 ParseResult requireFeature(
FIRVersion minimum, StringRef feature) {
178 return requireFeature(minimum, feature, getToken().
getLoc());
181 ParseResult requireFeature(
FIRVersion minimum, StringRef feature, SMLoc loc) {
182 if (version < minimum)
183 return emitError(loc)
184 << feature <<
" are a FIRRTL " << minimum
185 <<
"+ feature, but the specified FIRRTL version was " << version;
189 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature) {
190 return removedFeature(removedVersion, feature, getToken().
getLoc());
193 ParseResult removedFeature(
FIRVersion removedVersion, StringRef feature,
195 if (version >= removedVersion)
196 return emitError(loc)
197 << feature <<
" were removed in FIRRTL " << removedVersion
198 <<
", but the specified FIRRTL version was " << version;
208 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
217 if (getToken().isNot(kind))
227 FIRToken consumedToken = getToken();
228 assert(consumedToken.
isNot(FIRToken::eof, FIRToken::error) &&
229 "shouldn't advance past EOF or errors");
231 return consumedToken;
240 FIRToken consumedToken = getToken();
241 assert(consumedToken.
is(kind) &&
"consumed an unexpected token");
243 return consumedToken;
248 ParseResult parseGetSpelling(StringRef &spelling) {
249 spelling = getTokenSpelling();
255 ParseResult parseToken(
FIRToken::Kind expectedToken,
const Twine &message);
260 const std::function<ParseResult()> &parseElement);
267 ParseResult parseIntLit(APInt &result,
const Twine &message);
268 ParseResult parseIntLit(int64_t &result,
const Twine &message);
269 ParseResult parseIntLit(int32_t &result,
const Twine &message);
272 ParseResult parseVersionLit(
const Twine &message);
275 template <
typename T>
276 ParseResult parseOptionalWidth(T &result);
279 ParseResult parseId(StringRef &result,
const Twine &message);
280 ParseResult parseId(StringAttr &result,
const Twine &message);
281 ParseResult parseFieldId(StringRef &result,
const Twine &message);
282 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
283 const Twine &message);
284 ParseResult parseEnumType(
FIRRTLType &result);
285 ParseResult parseListType(
FIRRTLType &result);
288 ParseResult parsePropertyType(
PropertyType &result,
const Twine &message);
290 ParseResult parseRUW(RUWBehavior &result);
291 ParseResult parseOptionalRUW(RUWBehavior &result);
293 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
294 SMLoc &resultLoc,
bool allowAggregates =
false);
295 ParseResult parseParameterValue(Attribute &resultValue,
296 bool allowAggregates =
false);
302 FIRParser(
const FIRParser &) =
delete;
303 void operator=(
const FIRParser &) =
delete;
307 SharedParserConstants &constants;
311 StringAttr locatorFilenameCache;
313 FileLineColLoc fileLineColLocCache;
322InFlightDiagnostic FIRParser::emitError(SMLoc loc,
const Twine &message) {
323 auto diag = mlir::emitError(translateLocation(loc), message);
327 if (getToken().is(FIRToken::error))
332InFlightDiagnostic FIRParser::emitWarning(SMLoc loc,
const Twine &message) {
333 return mlir::emitWarning(translateLocation(loc), message);
343 const Twine &message) {
344 if (consumeIf(expectedToken))
346 return emitError(message);
353 const std::function<ParseResult()> &parseElement) {
354 if (consumeIf(rightToken))
360 while (consumeIf(FIRToken::comma)) {
365 if (parseToken(rightToken,
"expected ','"))
397 if (failed(
parser->parseOptionalInfoLocator(loc)))
401 switch (
parser->constants.options.infoLocatorHandling) {
402 case ILH::IgnoreInfo:
403 assert(0 &&
"Should not return info locations if ignoring");
405 case ILH::PreferInfo:
409 infoLoc = FusedLoc::get(loc.getContext(),
410 {loc, parser->translateLocation(firLoc)});
437ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
438 if (getToken().isNot(FIRToken::fileinfo))
441 auto loc = getToken().getLoc();
443 auto spelling = getTokenSpelling();
444 consumeToken(FIRToken::fileinfo);
448 constants.options.infoLocatorHandling ==
449 FIRParserOptions::InfoLocHandling::IgnoreInfo,
450 locatorFilenameCache, fileLineColLocCache, getContext());
453 if (!locationPair.first) {
454 mlir::emitWarning(translateLocation(loc),
455 "ignoring unknown @ info record format");
461 if (locationPair.first && constants.options.infoLocatorHandling ==
462 FIRParserOptions::InfoLocHandling::IgnoreInfo)
466 result = *locationPair.second;
474ParseResult FIRParser::parseOptionalName(StringAttr &name) {
476 if (getToken().isNot(FIRToken::colon)) {
477 name = StringAttr::get(getContext(),
"");
481 consumeToken(FIRToken::colon);
483 if (parseId(nameRef,
"expected result name"))
486 name = StringAttr::get(getContext(), nameRef);
497ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
499 if (getToken().isNot(FIRToken::inlineannotation))
502 loc = getToken().getLoc();
504 result = getTokenSpelling().drop_front(2).drop_back(1);
505 consumeToken(FIRToken::inlineannotation);
523ParseResult FIRParser::parseIntLit(APInt &result,
const Twine &message) {
524 auto spelling = getTokenSpelling();
525 bool isNegative =
false;
526 switch (getToken().getKind()) {
527 case FIRToken::signed_integer:
528 isNegative = spelling[0] ==
'-';
529 assert(spelling[0] ==
'+' || spelling[0] ==
'-');
530 spelling = spelling.drop_front();
532 case FIRToken::integer:
533 if (spelling.getAsInteger(10, result))
534 return emitError(message), failure();
538 if (result.isNegative())
539 result = result.zext(result.getBitWidth() + 1);
548 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
549 result = result.trunc(32);
553 case FIRToken::radix_specified_integer: {
554 if (requireFeature({2, 4, 0},
"radix-specified integer literals"))
556 if (spelling[0] ==
'-') {
558 spelling = spelling.drop_front();
560 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
565 spelling = spelling.drop_front(2);
566 if (spelling.getAsInteger(base, result))
567 return emitError(
"invalid character in integer literal"), failure();
568 if (result.isNegative())
569 result = result.zext(result.getBitWidth() + 1);
575 case FIRToken::string: {
578 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
581 assert(spelling.front() ==
'"' && spelling.back() ==
'"');
582 spelling = spelling.drop_back().drop_front();
586 switch (spelling.empty() ?
' ' : spelling.front()) {
597 return emitError(
"expected base specifier (h/o/b) in integer literal"),
600 spelling = spelling.drop_front();
603 bool isNegative =
false;
604 if (!spelling.empty() && spelling.front() ==
'+')
605 spelling = spelling.drop_front();
606 else if (!spelling.empty() && spelling.front() ==
'-') {
608 spelling = spelling.drop_front();
612 if (spelling.empty())
613 return emitError(
"expected digits in integer literal"), failure();
615 if (spelling.getAsInteger(base, result))
616 return emitError(
"invalid character in integer literal"), failure();
621 if (result.isNegative())
622 result = result.zext(result.getBitWidth() + 1);
627 consumeToken(FIRToken::string);
632 return emitError(
"expected integer literal"), failure();
636ParseResult FIRParser::parseIntLit(int64_t &result,
const Twine &message) {
638 auto loc = getToken().getLoc();
639 if (parseIntLit(value, message))
642 result = (int64_t)value.getLimitedValue(INT64_MAX);
644 return emitError(loc,
"value is too big to handle"), failure();
648ParseResult FIRParser::parseIntLit(int32_t &result,
const Twine &message) {
650 auto loc = getToken().getLoc();
651 if (parseIntLit(value, message))
654 result = (int32_t)value.getLimitedValue(INT32_MAX);
656 return emitError(loc,
"value is too big to handle"), failure();
662ParseResult FIRParser::parseVersionLit(
const Twine &message) {
663 auto spelling = getTokenSpelling();
664 if (getToken().getKind() != FIRToken::version)
665 return emitError(message), failure();
667 auto [a, d] = spelling.split(
".");
668 auto [b, c] = d.split(
".");
669 APInt aInt, bInt, cInt;
670 if (a.getAsInteger(10, aInt) || b.getAsInteger(10, bInt) ||
671 c.getAsInteger(10, cInt))
672 return emitError(
"failed to parse version string"), failure();
673 version.major = aInt.getLimitedValue(UINT32_MAX);
674 version.minor = bInt.getLimitedValue(UINT32_MAX);
675 version.patch = cInt.getLimitedValue(UINT32_MAX);
676 if (version.major != aInt || version.minor != bInt || version.patch != cInt)
677 return emitError(
"integers out of range"), failure();
681 consumeToken(FIRToken::version);
689ParseResult FIRParser::parseOptionalWidth(T &result) {
690 if (!consumeIf(FIRToken::less))
691 return result = -1, success();
694 auto widthLoc = getToken().getLoc();
695 if (parseIntLit(result,
"expected width") ||
696 parseToken(FIRToken::greater,
"expected >"))
700 return emitError(widthLoc,
"invalid width specifier"), failure();
709ParseResult FIRParser::parseId(StringRef &result,
const Twine &message) {
710 switch (getToken().getKind()) {
712 case FIRToken::identifier:
713 case FIRToken::literal_identifier:
715#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
716#include "FIRTokenKinds.def"
721 if (getToken().getKind() == FIRToken::literal_identifier)
722 result = getTokenSpelling().drop_front().drop_back();
724 result = getTokenSpelling();
734ParseResult FIRParser::parseId(StringAttr &result,
const Twine &message) {
736 if (parseId(name, message))
739 result = StringAttr::get(getContext(), name);
748ParseResult FIRParser::parseFieldId(StringRef &result,
const Twine &message) {
750 result = getTokenSpelling();
751 if (consumeIf(FIRToken::integer))
757 if (parseId(result, message))
769ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
770 const Twine &message) {
772 StringRef tmp = getTokenSpelling();
774 if (consumeIf(FIRToken::integer)) {
775 result.push_back(tmp);
779 if (consumeIf(FIRToken::floatingpoint)) {
783 auto [a, b] = tmp.split(
".");
789 if (consumeIf(FIRToken::version)) {
791 auto [a, d] = tmp.split(
".");
792 auto [b, c] = d.split(
".");
800 if (parseId(tmp, message))
802 result.push_back(tmp);
808ParseResult FIRParser::parseEnumType(
FIRRTLType &result) {
809 if (parseToken(FIRToken::l_brace_bar,
810 "expected leading '{|' in enumeration type"))
812 SmallVector<StringAttr> names;
813 SmallVector<APInt> values;
814 SmallVector<FIRRTLBaseType> types;
815 SmallVector<SMLoc> locs;
816 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
817 auto fieldLoc = getToken().getLoc();
818 locs.push_back(fieldLoc);
822 if (parseId(nameStr,
"expected valid identifier for enumeration tag"))
824 auto name = StringAttr::get(getContext(), nameStr);
825 names.push_back(name);
831 if (consumeIf(FIRToken::equal)) {
832 if (parseIntLit(value,
"expected integer value for enumeration tag"))
834 if (value.isNegative())
835 return emitError(fieldLoc,
"enum tag value must be non-negative");
836 }
else if (values.empty()) {
842 auto &prev = values.back();
843 if (prev.isMaxValue())
844 value = prev.zext(prev.getBitWidth() + 1);
849 values.push_back(std::move(value));
853 if (consumeIf(FIRToken::colon)) {
855 if (
parseType(parsedType,
"expected enumeration type"))
857 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
859 return emitError(fieldLoc,
"field must be a base type");
862 type = UIntType::get(getContext(), 0);
864 types.push_back(type);
866 auto r = type.getRecursiveTypeProperties();
868 return emitError(fieldLoc) <<
"enum field " << name <<
" not passive";
869 if (r.containsAnalog)
870 return emitError(fieldLoc)
871 <<
"enum field " << name <<
" contains analog";
872 if (r.hasUninferredWidth)
873 return emitError(fieldLoc)
874 <<
"enum field " << name <<
" has uninferred width";
875 if (r.hasUninferredReset)
876 return emitError(fieldLoc)
877 <<
"enum field " << name <<
" has uninferred reset";
883 SmallPtrSet<StringAttr, 4> nameSet;
884 for (
auto [name, loc] :
llvm::zip(names, locs))
885 if (!nameSet.insert(name).second)
886 return emitError(loc,
887 "duplicate variant name in enum: " + name.getValue());
890 unsigned bitwidth = 0;
891 for (
auto &value : values)
892 bitwidth = std::max(bitwidth, value.getActiveBits());
894 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
898 SmallPtrSet<IntegerAttr, 4> valueSet;
899 SmallVector<FEnumType::EnumElement, 4> elements;
900 for (
auto [name, value, type, loc] :
llvm::zip(names, values, types, locs)) {
901 auto tagValue = value.zextOrTrunc(bitwidth);
902 auto attr = IntegerAttr::get(tagType, tagValue);
904 if (!valueSet.insert(attr).second)
905 return emitError(loc,
"duplicate variant value in enum: ") << attr;
906 elements.push_back({name, attr, type});
909 llvm::sort(elements);
910 result = FEnumType::get(getContext(), elements);
914ParseResult FIRParser::parsePropertyType(
PropertyType &result,
915 const Twine &message) {
919 auto prop = type_dyn_cast<PropertyType>(type);
921 return emitError(
"expected property type");
927ParseResult FIRParser::parseListType(
FIRRTLType &result) {
928 consumeToken(FIRToken::kw_List);
931 if (parseToken(FIRToken::less,
"expected '<' in List type") ||
932 parsePropertyType(
elementType,
"expected List element type") ||
933 parseToken(FIRToken::greater,
"expected '>' in List type"))
959ParseResult FIRParser::parseType(
FIRRTLType &result,
const Twine &message) {
960 switch (getToken().getKind()) {
962 return emitError(message), failure();
964 case FIRToken::kw_Clock:
965 consumeToken(FIRToken::kw_Clock);
966 result = ClockType::get(getContext());
969 case FIRToken::kw_Inst: {
973 consumeToken(FIRToken::kw_Inst);
974 if (parseToken(FIRToken::less,
"expected < in Inst type"))
977 auto loc = getToken().getLoc();
979 if (parseId(
id,
"expected class name in Inst type"))
983 const auto &classMap = getConstants().classMap;
984 auto lookup = classMap.find(
id);
985 if (lookup == classMap.end())
986 return emitError(loc) <<
"unknown class '" <<
id <<
"'";
988 auto classOp = lookup->second;
990 if (parseToken(FIRToken::greater,
"expected > in Inst type"))
993 result = classOp.getInstanceType();
997 case FIRToken::kw_AnyRef: {
1001 consumeToken(FIRToken::kw_AnyRef);
1002 result = AnyRefType::get(getContext());
1006 case FIRToken::kw_Reset:
1007 consumeToken(FIRToken::kw_Reset);
1008 result = ResetType::get(getContext());
1011 case FIRToken::kw_AsyncReset:
1012 consumeToken(FIRToken::kw_AsyncReset);
1013 result = AsyncResetType::get(getContext());
1016 case FIRToken::kw_UInt:
1017 case FIRToken::kw_SInt:
1018 case FIRToken::kw_Analog: {
1019 auto kind = getToken().getKind();
1024 if (parseOptionalWidth(width))
1027 if (kind == FIRToken::kw_SInt)
1028 result = SIntType::get(getContext(), width);
1029 else if (kind == FIRToken::kw_UInt)
1030 result = UIntType::get(getContext(), width);
1032 assert(kind == FIRToken::kw_Analog);
1033 result = AnalogType::get(getContext(), width);
1038 case FIRToken::kw_Domain: {
1042 result = DomainType::get(getContext());
1046 case FIRToken::kw_Probe:
1047 case FIRToken::kw_RWProbe: {
1048 auto kind = getToken().getKind();
1049 auto loc = getToken().getLoc();
1054 if (parseToken(FIRToken::less,
"expected '<' in reference type") ||
1055 parseType(type,
"expected probe data type"))
1058 SmallVector<StringRef> layers;
1059 if (consumeIf(FIRToken::comma)) {
1060 if (requireFeature({4, 0, 0},
"colored probes"))
1065 loc = getToken().getLoc();
1066 if (parseId(layer,
"expected layer name"))
1068 layers.push_back(layer);
1069 }
while (consumeIf(FIRToken::period));
1072 if (!consumeIf(FIRToken::greater))
1073 return emitError(loc,
"expected '>' to end reference type");
1075 bool forceable = kind == FIRToken::kw_RWProbe;
1077 auto innerType = type_dyn_cast<FIRRTLBaseType>(type);
1079 return emitError(loc,
"invalid probe inner type, must be base-type");
1082 return emitError(loc,
"probe inner type must be passive");
1084 if (forceable &&
innerType.containsConst())
1085 return emitError(loc,
"rwprobe cannot contain const");
1087 SymbolRefAttr layer;
1088 if (!layers.empty()) {
1090 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1091 return FlatSymbolRefAttr::get(getContext(), a);
1093 layer = SymbolRefAttr::get(getContext(), layers.front(),
1094 llvm::to_vector(nestedLayers));
1097 result = RefType::get(innerType, forceable, layer);
1101 case FIRToken::l_brace: {
1102 consumeToken(FIRToken::l_brace);
1104 SmallVector<OpenBundleType::BundleElement, 4> elements;
1105 SmallPtrSet<StringAttr, 4> nameSet;
1106 bool bundleCompatible =
true;
1107 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1108 bool isFlipped = consumeIf(FIRToken::kw_flip);
1110 auto loc = getToken().getLoc();
1111 StringRef fieldNameStr;
1112 if (parseFieldId(fieldNameStr,
"expected bundle field name") ||
1113 parseToken(FIRToken::colon,
"expected ':' in bundle"))
1115 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1118 if (!nameSet.insert(fieldName).second)
1119 return emitError(loc,
"duplicate field name in bundle: " +
1120 fieldName.getValue());
1123 if (
parseType(type,
"expected bundle field type"))
1126 elements.push_back({fieldName, isFlipped, type});
1127 bundleCompatible &= isa<BundleType::ElementType>(type);
1134 if (bundleCompatible) {
1135 auto bundleElements = llvm::map_range(elements, [](
auto element) {
1136 return BundleType::BundleElement{
1137 element.name, element.isFlip,
1138 cast<BundleType::ElementType>(element.type)};
1140 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1142 result = OpenBundleType::get(getContext(), elements);
1146 case FIRToken::l_brace_bar: {
1147 if (parseEnumType(result))
1152 case FIRToken::identifier: {
1154 auto loc = getToken().getLoc();
1155 if (parseId(
id,
"expected a type alias name"))
1157 auto it = constants.aliasMap.find(
id);
1158 if (it == constants.aliasMap.end()) {
1159 emitError(loc) <<
"type identifier `" <<
id <<
"` is not declared";
1162 result = it->second;
1166 case FIRToken::kw_const: {
1167 consumeToken(FIRToken::kw_const);
1168 auto nextToken = getToken();
1169 auto loc = nextToken.getLoc();
1172 if (nextToken.is(FIRToken::kw_const))
1173 return emitError(loc,
"'const' can only be specified once on a type");
1178 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1180 return emitError(loc,
"only hardware types can be 'const'");
1182 result = baseType.getConstType(
true);
1186 case FIRToken::kw_String:
1187 if (requireFeature({3, 1, 0},
"Strings"))
1189 consumeToken(FIRToken::kw_String);
1190 result = StringType::get(getContext());
1192 case FIRToken::kw_Integer:
1193 if (requireFeature({3, 1, 0},
"Integers"))
1195 consumeToken(FIRToken::kw_Integer);
1196 result = FIntegerType::get(getContext());
1198 case FIRToken::kw_Bool:
1201 consumeToken(FIRToken::kw_Bool);
1202 result = BoolType::get(getContext());
1204 case FIRToken::kw_Double:
1207 consumeToken(FIRToken::kw_Double);
1208 result = DoubleType::get(getContext());
1210 case FIRToken::kw_Path:
1213 consumeToken(FIRToken::kw_Path);
1214 result = PathType::get(getContext());
1216 case FIRToken::kw_List:
1217 if (requireFeature({4, 0, 0},
"Lists") || parseListType(result))
1223 while (consumeIf(FIRToken::l_square)) {
1224 auto sizeLoc = getToken().getLoc();
1226 if (parseIntLit(size,
"expected width") ||
1227 parseToken(FIRToken::r_square,
"expected ]"))
1231 return emitError(sizeLoc,
"invalid size specifier"), failure();
1233 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1235 result = FVectorType::get(baseType, size);
1237 result = OpenVectorType::get(result, size);
1244ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1245 switch (getToken().getKind()) {
1247 case FIRToken::kw_old:
1248 result = RUWBehavior::Old;
1249 consumeToken(FIRToken::kw_old);
1251 case FIRToken::kw_new:
1252 result = RUWBehavior::New;
1253 consumeToken(FIRToken::kw_new);
1255 case FIRToken::kw_undefined:
1256 result = RUWBehavior::Undefined;
1257 consumeToken(FIRToken::kw_undefined);
1267ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1268 switch (getToken().getKind()) {
1272 case FIRToken::kw_old:
1273 result = RUWBehavior::Old;
1274 consumeToken(FIRToken::kw_old);
1276 case FIRToken::kw_new:
1277 result = RUWBehavior::New;
1278 consumeToken(FIRToken::kw_new);
1280 case FIRToken::kw_undefined:
1281 result = RUWBehavior::Undefined;
1282 consumeToken(FIRToken::kw_undefined);
1290ParseResult FIRParser::parseParameter(StringAttr &resultName,
1291 Attribute &resultValue, SMLoc &resultLoc,
1292 bool allowAggregates) {
1293 auto loc = getToken().getLoc();
1297 if (parseId(name,
"expected parameter name") ||
1298 parseToken(FIRToken::equal,
"expected '=' in parameter"))
1303 if (parseParameterValue(value, allowAggregates))
1306 resultName = StringAttr::get(getContext(), name);
1307 resultValue = value;
1318ParseResult FIRParser::parseParameterValue(Attribute &value,
1319 bool allowAggregates) {
1320 mlir::Builder builder(getContext());
1321 switch (getToken().getKind()) {
1324 case FIRToken::integer:
1325 case FIRToken::signed_integer: {
1327 if (parseIntLit(result,
"invalid integer parameter"))
1333 if (result.getBitWidth() < 32)
1334 result = result.sext(32);
1336 value = builder.getIntegerAttr(
1337 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1343 case FIRToken::string: {
1345 value = builder.getStringAttr(getToken().getStringValue());
1346 consumeToken(FIRToken::string);
1351 case FIRToken::verbatim_string: {
1353 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1354 value = hw::ParamVerbatimAttr::get(text);
1355 consumeToken(FIRToken::verbatim_string);
1360 case FIRToken::floatingpoint: {
1362 if (!llvm::to_float(getTokenSpelling(), v))
1363 return emitError(
"invalid float parameter syntax"), failure();
1365 value = builder.getF64FloatAttr(v);
1366 consumeToken(FIRToken::floatingpoint);
1371 case FIRToken::l_square: {
1372 if (!allowAggregates)
1373 return emitError(
"expected non-aggregate parameter value");
1376 SmallVector<Attribute> elements;
1377 auto parseElement = [&] {
1378 return parseParameterValue(elements.emplace_back(),
1381 if (parseListUntil(FIRToken::r_square, parseElement))
1384 value = builder.getArrayAttr(elements);
1389 case FIRToken::l_brace: {
1390 if (!allowAggregates)
1391 return emitError(
"expected non-aggregate parameter value");
1394 NamedAttrList fields;
1395 auto parseField = [&]() -> ParseResult {
1396 StringAttr fieldName;
1397 Attribute fieldValue;
1399 if (parseParameter(fieldName, fieldValue, fieldLoc,
1402 if (fields.set(fieldName, fieldValue))
1403 return emitError(fieldLoc)
1404 <<
"redefinition of parameter '" << fieldName.getValue() <<
"'";
1407 if (parseListUntil(FIRToken::r_brace, parseField))
1410 value = fields.getDictionary(getContext());
1415 return emitError(
"expected parameter value");
1430 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1438struct UnbundledValueRestorer {
1440 size_t startingSize;
1442 startingSize = list.size();
1444 ~UnbundledValueRestorer() { list.resize(startingSize); }
1453struct FIRModuleContext :
public FIRParser {
1454 explicit FIRModuleContext(Block *topLevelBlock,
1455 SharedParserConstants &constants,
FIRLexer &lexer,
1457 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1460 template <
typename OpTy = ConstantOp,
typename... Args>
1461 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1462 Type type, Args &&...args) {
1463 auto &result = constantCache[{attr, type}];
1469 OpBuilder::InsertPoint savedIP;
1472 if (builder.getInsertionBlock() != topLevelBlock) {
1473 savedIP = builder.saveInsertionPoint();
1474 auto *block = builder.getInsertionBlock();
1476 auto *op = block->getParentOp();
1477 if (!op || !op->getBlock()) {
1479 builder.setInsertionPointToEnd(topLevelBlock);
1482 if (op->getBlock() == topLevelBlock) {
1483 builder.setInsertionPoint(op);
1486 block = op->getBlock();
1490 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1492 if (savedIP.isSet())
1493 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1504 Value &getCachedSubaccess(Value value,
unsigned index) {
1505 auto &result = subaccessCache[{value, index}];
1508 auto it = scopeMap.find(value.getParentBlock());
1509 if (it != scopeMap.end())
1510 it->second->scopedSubaccesses.push_back({result, index});
1520 ParseResult addSymbolEntry(StringRef name,
SymbolValueEntry entry, SMLoc loc,
1521 bool insertNameIntoGlobalScope =
false);
1522 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1523 bool insertNameIntoGlobalScope =
false) {
1525 insertNameIntoGlobalScope);
1529 void removeSymbolEntry(StringRef name);
1533 SMLoc loc,
bool fatal =
true);
1538 StringRef field, SMLoc loc);
1546 assert(index < unbundledValues.size());
1547 return unbundledValues[index];
1557 struct ContextScope {
1558 friend struct FIRModuleContext;
1559 ContextScope(FIRModuleContext &moduleContext, Block *block)
1560 : moduleContext(moduleContext), block(block),
1561 previousScope(moduleContext.currentScope) {
1562 moduleContext.currentScope =
this;
1563 moduleContext.scopeMap[block] =
this;
1568 for (
auto *entryPtr : scopedDecls)
1569 entryPtr->second.first = SMLoc();
1572 for (
auto subaccess : scopedSubaccesses)
1573 moduleContext.subaccessCache.erase(subaccess);
1575 moduleContext.scopeMap.erase(block);
1577 moduleContext.currentScope = previousScope;
1581 void operator=(
const ContextScope &) =
delete;
1582 ContextScope(
const ContextScope &) =
delete;
1584 FIRModuleContext &moduleContext;
1586 ContextScope *previousScope;
1587 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1588 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1593 Block *topLevelBlock;
1599 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1611 DenseMap<Block *, ContextScope *> scopeMap;
1616 ContextScope *currentScope =
nullptr;
1622void FIRModuleContext::removeSymbolEntry(StringRef name) {
1623 symbolTable.erase(name);
1632ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1634 bool insertNameIntoGlobalScope) {
1637 auto [entryIt, inserted] =
1642 if (entryIt->second.first.isValid()) {
1644 emitError(loc,
"redefinition of name '" + name +
"' ")
1645 .attachNote(translateLocation(entryIt->second.first))
1646 <<
"previous definition here.";
1649 emitError(loc,
"redefinition of name '" + name +
"' ")
1650 <<
"- FIRRTL has flat namespace and requires all "
1651 <<
"declarations in a module to have unique names.";
1658 entryIt->second = {loc, entry};
1659 if (currentScope && !insertNameIntoGlobalScope)
1660 currentScope->scopedDecls.push_back(&*entryIt);
1667 StringRef name, SMLoc loc) {
1668 auto &entry = symbolTable[name];
1669 if (!entry.first.isValid())
1670 return emitError(loc,
"use of unknown declaration '" + name +
"'");
1671 result = entry.second;
1672 assert(result &&
"name in symbol table without definition");
1676ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1678 SMLoc loc,
bool fatal) {
1679 if (!isa<Value>(entry)) {
1681 emitError(loc,
"bundle value should only be used from subfield");
1684 result = cast<Value>(entry);
1688ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1690 StringRef fieldName,
1692 if (!isa<UnbundledID>(entry)) {
1693 emitError(loc,
"value should not be used from subfield");
1697 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1699 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1700 assert(unbundledId < unbundledValues.size());
1702 for (
auto elt : ubEntry) {
1703 if (elt.first == fieldAttr) {
1704 result = elt.second;
1709 emitError(loc,
"use of invalid field name '")
1710 << fieldName <<
"' on bundle value";
1736struct LazyLocationListener :
public OpBuilder::Listener {
1737 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1738 assert(builder.getListener() ==
nullptr);
1739 builder.setListener(
this);
1742 ~LazyLocationListener() {
1743 assert(subOps.empty() &&
"didn't process parsed operations");
1744 assert(builder.getListener() ==
this);
1745 builder.setListener(
nullptr);
1748 void startStatement() {
1749 assert(!isActive &&
"Already processing a statement");
1755 void endStatement(FIRParser &parser) {
1756 assert(isActive &&
"Not parsing a statement");
1760 for (
auto opAndSMLoc : subOps) {
1764 switch (parser.getConstants().options.infoLocatorHandling) {
1765 case ILH::IgnoreInfo:
1767 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1769 case ILH::PreferInfo:
1770 opAndSMLoc.first->setLoc(infoLoc);
1772 case ILH::FusedInfo:
1773 opAndSMLoc.first->setLoc(FusedLoc::get(
1774 infoLoc.getContext(),
1775 {infoLoc, parser.translateLocation(opAndSMLoc.second)}));
1782 for (
auto opAndSMLoc : subOps)
1783 opAndSMLoc.first->setLoc(parser.translateLocation(opAndSMLoc.second));
1788 infoLoc = LocationAttr();
1789 currentSMLoc = SMLoc();
1794 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1797 void setInfoLoc(LocationAttr loc) {
1798 assert(!infoLoc &&
"Info location multiply specified");
1804 void notifyOperationInserted(Operation *op,
1805 mlir::IRRewriter::InsertPoint)
override {
1806 assert(currentSMLoc != SMLoc() &&
"No .fir file location specified");
1807 assert(isActive &&
"Not parsing a statement");
1808 subOps.push_back({op, currentSMLoc});
1813 bool isActive =
false;
1821 LocationAttr infoLoc;
1828 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1830 void operator=(
const LazyLocationListener &) =
delete;
1831 LazyLocationListener(
const LazyLocationListener &) =
delete;
1839struct InnerSymFixups {
1842 fixups.push_back({user, target});
1851 hw::InnerRefUserOpInterface innerRefUser;
1854 SmallVector<Fixup, 0> fixups;
1860 for (
auto &f : fixups) {
1863 return isnc.get(module);
1865 assert(ref &&
"unable to resolve inner symbol target");
1869 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1870 .Case<RWProbeOp>([ref](RWProbeOp op) {
1871 op.setTargetAttr(ref);
1874 .Default([](
auto *op) {
1875 return op->emitError(
"unknown inner-ref user requiring fixup");
1886struct FIRStmtParser :
public FIRParser {
1887 explicit FIRStmtParser(Block &blockToInsertInto,
1888 FIRModuleContext &moduleContext,
1889 InnerSymFixups &innerSymFixups,
1890 const SymbolTable &circuitSymTbl,
FIRVersion version,
1891 SymbolRefAttr layerSym = {})
1892 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1894 builder(UnknownLoc::
get(getContext()), getContext()),
1895 locationProcessor(this->builder), moduleContext(moduleContext),
1896 innerSymFixups(innerSymFixups), layerSym(layerSym),
1897 circuitSymTbl(circuitSymTbl) {
1898 builder.setInsertionPointToEnd(&blockToInsertInto);
1901 ParseResult parseSimpleStmt(
unsigned stmtIndent);
1902 ParseResult parseSimpleStmtBlock(
unsigned indent);
1905 ParseResult parseSimpleStmtImpl(
unsigned stmtIndent);
1908 void emitInvalidate(Value val,
Flow flow);
1914 void emitInvalidate(Value val) { emitInvalidate(val,
foldFlow(val)); }
1917 ParseResult parseOptionalInfo() {
1919 if (failed(parseOptionalInfoLocator(loc)))
1921 locationProcessor.setInfoLoc(loc);
1926 ParseResult parseExpImpl(Value &result,
const Twine &message,
1927 bool isLeadingStmt);
1928 ParseResult parseExp(Value &result,
const Twine &message) {
1929 return parseExpImpl(result, message,
false);
1931 ParseResult parseExpLeadingStmt(Value &result,
const Twine &message) {
1932 return parseExpImpl(result, message,
true);
1934 ParseResult parseEnumExp(Value &result);
1935 ParseResult parsePathExp(Value &result);
1936 ParseResult parseRefExp(Value &result,
const Twine &message);
1937 ParseResult parseStaticRefExp(Value &result,
const Twine &message);
1938 ParseResult parseRWProbeStaticRefExp(
FieldRef &refResult, Type &type,
1939 const Twine &message);
1942 ParseResult parseIntrinsic(Value &result,
bool isStatement);
1943 ParseResult parseIntrinsicStmt() {
1945 return parseIntrinsic(unused,
true);
1947 ParseResult parseIntrinsicExp(Value &result) {
1948 return parseIntrinsic(result,
false);
1950 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
1952 template <
typename subop>
1953 FailureOr<Value> emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc);
1954 ParseResult parseOptionalExpPostscript(Value &result,
1955 bool allowDynamic =
true);
1956 ParseResult parsePostFixFieldId(Value &result);
1957 ParseResult parsePostFixIntSubscript(Value &result);
1958 ParseResult parsePostFixDynamicSubscript(Value &result);
1959 ParseResult parseIntegerLiteralExp(Value &result);
1960 ParseResult parseListExp(Value &result);
1961 ParseResult parseListConcatExp(Value &result);
1962 ParseResult parseCatExp(Value &result);
1963 ParseResult parseUnsafeDomainCast(Value &result);
1965 template <
typename T,
size_t M,
size_t N,
size_t... Ms,
size_t... Ns>
1966 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
1968 auto loc = getToken().getLoc();
1969 locationProcessor.setLoc(loc);
1972 auto vals = std::array<Value, M>();
1973 auto ints = std::array<int64_t, N>();
1977 for (
size_t i = 0; i < M; ++i) {
1979 if (parseToken(FIRToken::comma,
"expected ','"))
1981 if (parseExp(vals[i],
"expected expression in primitive operand"))
1987 for (
size_t i = 0; i < N; ++i) {
1989 if (parseToken(FIRToken::comma,
"expected ','"))
1991 if (parseIntLit(ints[i],
"expected integer in primitive operand"))
1996 if (parseToken(FIRToken::r_paren,
"expected ')'"))
2000 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2004 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2005 translateLocation(loc));
2010 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2011 result = op.getResult();
2015 template <
typename T,
unsigned M,
unsigned N>
2016 ParseResult parsePrimExp(Value &result) {
2017 auto ms = std::make_index_sequence<M>();
2018 auto ns = std::make_index_sequence<N>();
2019 return parsePrim<T, M, N>(ms, ns, result);
2022 std::optional<ParseResult> parseExpWithLeadingKeyword(
FIRToken keyword);
2025 ParseResult parseSubBlock(Block &blockToInsertInto,
unsigned indent,
2026 SymbolRefAttr layerSym);
2027 ParseResult parseAttach();
2028 ParseResult parseMemPort(MemDirAttr direction);
2033 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
2034 ArrayRef<Value> specOperands,
2035 StringAttr &formatStringResult,
2036 SmallVectorImpl<Value> &operands);
2037 ParseResult parsePrintf();
2038 ParseResult parseFPrintf();
2039 ParseResult parseFFlush();
2040 ParseResult parseSkip();
2041 ParseResult parseStop();
2042 ParseResult parseAssert();
2043 ParseResult parseAssume();
2044 ParseResult parseCover();
2045 ParseResult parseWhen(
unsigned whenIndent);
2046 ParseResult parseMatch(
unsigned matchIndent);
2047 ParseResult parseRefDefine();
2048 ParseResult parseRefForce();
2049 ParseResult parseRefForceInitial();
2050 ParseResult parseRefRelease();
2051 ParseResult parseRefReleaseInitial();
2052 ParseResult parseRefRead(Value &result);
2053 ParseResult parseProbe(Value &result);
2054 ParseResult parsePropAssign();
2055 ParseResult parseRWProbe(Value &result);
2056 ParseResult parseLeadingExpStmt(Value lhs);
2057 ParseResult parseConnect();
2058 ParseResult parseInvalidate();
2059 ParseResult parseLayerBlockOrGroup(
unsigned indent);
2062 ParseResult parseInstance();
2063 ParseResult parseInstanceChoice();
2064 ParseResult parseObject();
2065 ParseResult parseCombMem();
2066 ParseResult parseSeqMem();
2067 ParseResult parseMem(
unsigned memIndent);
2068 ParseResult parseNode();
2069 ParseResult parseWire();
2070 ParseResult parseRegister(
unsigned regIndent);
2071 ParseResult parseRegisterWithReset();
2072 ParseResult parseContract(
unsigned blockIndent);
2075 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2078 ImplicitLocOpBuilder builder;
2079 LazyLocationListener locationProcessor;
2082 FIRModuleContext &moduleContext;
2085 InnerSymFixups &innerSymFixups;
2089 SymbolRefAttr layerSym;
2091 const SymbolTable &circuitSymTbl;
2098void FIRStmtParser::emitInvalidate(Value val,
Flow flow) {
2099 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2106 auto props = tpe.getRecursiveTypeProperties();
2107 if (props.isPassive && !props.containsAnalog) {
2108 if (flow == Flow::Source)
2110 emitConnect(builder, val, InvalidValueOp::create(builder, tpe));
2121 TypeSwitch<FIRRTLType>(tpe)
2122 .Case<BundleType>([&](
auto tpe) {
2123 for (
size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2124 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2126 OpBuilder::InsertionGuard guard(builder);
2127 builder.setInsertionPointAfterValue(val);
2128 subfield = SubfieldOp::create(builder, val, i);
2130 emitInvalidate(subfield,
2131 tpe.getElement(i).isFlip ?
swapFlow(flow) : flow);
2134 .Case<FVectorType>([&](
auto tpe) {
2135 auto tpex = tpe.getElementType();
2136 for (
size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2137 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2139 OpBuilder::InsertionGuard guard(builder);
2140 builder.setInsertionPointAfterValue(val);
2141 subindex = SubindexOp::create(builder, tpex, val, i);
2143 emitInvalidate(subindex, flow);
2171ParseResult FIRStmtParser::parseExpImpl(Value &result,
const Twine &message,
2172 bool isLeadingStmt) {
2173 auto token = getToken();
2174 auto kind = token.getKind();
2176 case FIRToken::lp_integer_add:
2177 case FIRToken::lp_integer_mul:
2178 case FIRToken::lp_integer_shr:
2179 case FIRToken::lp_integer_shl:
2180 if (requireFeature({4, 0, 0},
"Integer arithmetic expressions"))
2189#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2191 case FIRToken::lp_##SPELLING: \
2192 if (requireFeature(VERSION, FEATURE)) \
2194 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2197#include "FIRTokenKinds.def"
2199 case FIRToken::l_brace_bar:
2201 return emitError(
"unexpected enumeration as start of statement");
2202 if (parseEnumExp(result))
2205 case FIRToken::lp_read:
2207 return emitError(
"unexpected read() as start of statement");
2208 if (parseRefRead(result))
2211 case FIRToken::lp_probe:
2213 return emitError(
"unexpected probe() as start of statement");
2214 if (parseProbe(result))
2217 case FIRToken::lp_rwprobe:
2219 return emitError(
"unexpected rwprobe() as start of statement");
2220 if (parseRWProbe(result))
2224 case FIRToken::kw_UInt:
2225 case FIRToken::kw_SInt:
2226 if (parseIntegerLiteralExp(result))
2229 case FIRToken::kw_String: {
2230 if (requireFeature({3, 1, 0},
"Strings"))
2232 locationProcessor.setLoc(getToken().
getLoc());
2233 consumeToken(FIRToken::kw_String);
2235 if (parseToken(FIRToken::l_paren,
"expected '(' in String expression") ||
2236 parseGetSpelling(spelling) ||
2237 parseToken(FIRToken::string,
2238 "expected string literal in String expression") ||
2239 parseToken(FIRToken::r_paren,
"expected ')' in String expression"))
2242 result = moduleContext.getCachedConstant<StringConstantOp>(
2243 builder, attr, builder.getType<StringType>(), attr);
2246 case FIRToken::kw_Integer: {
2247 if (requireFeature({3, 1, 0},
"Integers"))
2249 locationProcessor.setLoc(getToken().
getLoc());
2250 consumeToken(FIRToken::kw_Integer);
2252 if (parseToken(FIRToken::l_paren,
"expected '(' in Integer expression") ||
2253 parseIntLit(value,
"expected integer literal in Integer expression") ||
2254 parseToken(FIRToken::r_paren,
"expected ')' in Integer expression"))
2256 APSInt apint(value,
false);
2257 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2258 builder, IntegerAttr::get(getContext(), apint),
2259 builder.getType<FIntegerType>(), apint);
2262 case FIRToken::kw_Bool: {
2265 locationProcessor.setLoc(getToken().
getLoc());
2266 consumeToken(FIRToken::kw_Bool);
2267 if (parseToken(FIRToken::l_paren,
"expected '(' in Bool expression"))
2270 if (consumeIf(FIRToken::kw_true))
2272 else if (consumeIf(FIRToken::kw_false))
2275 return emitError(
"expected true or false in Bool expression");
2276 if (parseToken(FIRToken::r_paren,
"expected ')' in Bool expression"))
2278 auto attr = builder.getBoolAttr(value);
2279 result = moduleContext.getCachedConstant<BoolConstantOp>(
2280 builder, attr, builder.getType<BoolType>(), value);
2283 case FIRToken::kw_Double: {
2286 locationProcessor.setLoc(getToken().
getLoc());
2287 consumeToken(FIRToken::kw_Double);
2288 if (parseToken(FIRToken::l_paren,
"expected '(' in Double expression"))
2290 auto spelling = getTokenSpelling();
2291 if (parseToken(FIRToken::floatingpoint,
2292 "expected floating point in Double expression") ||
2293 parseToken(FIRToken::r_paren,
"expected ')' in Double expression"))
2298 if (!llvm::to_float(spelling, d))
2299 return emitError(
"invalid double");
2300 auto attr = builder.getF64FloatAttr(d);
2301 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2302 builder, attr, builder.getType<DoubleType>(), attr);
2305 case FIRToken::kw_List: {
2306 if (requireFeature({4, 0, 0},
"Lists"))
2309 return emitError(
"unexpected List<>() as start of statement");
2310 if (parseListExp(result))
2315 case FIRToken::lp_list_concat: {
2317 return emitError(
"unexpected list_create() as start of statement");
2318 if (requireFeature({4, 0, 0},
"List concat") || parseListConcatExp(result))
2323 case FIRToken::lp_path:
2325 return emitError(
"unexpected path() as start of statement");
2330 case FIRToken::lp_intrinsic:
2331 if (requireFeature({4, 0, 0},
"generic intrinsics") ||
2332 parseIntrinsicExp(result))
2336 case FIRToken::lp_cat:
2337 if (parseCatExp(result))
2341 case FIRToken::lp_unsafe_domain_cast:
2343 parseUnsafeDomainCast(result))
2349 case FIRToken::identifier:
2350 case FIRToken::literal_identifier:
2353 auto loc = getToken().getLoc();
2355 if (parseId(name, message) ||
2356 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2360 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
2363 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
2368 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2369 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
2370 parseOptionalInfo())
2373 locationProcessor.setLoc(loc);
2375 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2377 moduleContext.getUnbundledEntry(unbundledId);
2378 for (
auto elt : ubEntry)
2379 emitInvalidate(elt.second);
2387 StringRef fieldName;
2388 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
2389 parseFieldId(fieldName,
"expected field name") ||
2390 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2398 case FIRToken::lp_shr:
2401 if (version <
FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2402 result = PadPrimOp::create(builder, result, 1);
2408 return parseOptionalExpPostscript(result);
2418ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2419 bool allowDynamic) {
2424 if (consumeIf(FIRToken::period)) {
2425 if (parsePostFixFieldId(result))
2432 if (consumeIf(FIRToken::l_square)) {
2433 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2434 if (parsePostFixIntSubscript(result))
2439 return emitError(
"subaccess not allowed here");
2440 if (parsePostFixDynamicSubscript(result))
2450template <
typename subop>
2452FIRStmtParser::emitCachedSubAccess(Value base,
unsigned indexNo, SMLoc loc) {
2454 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2460 auto baseType = cast<FIRRTLType>(base.getType());
2461 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2464 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2470 locationProcessor.setLoc(loc);
2471 OpBuilder::InsertionGuard guard(builder);
2472 builder.setInsertionPointAfterValue(base);
2473 auto op = subop::create(builder, resultType, base, indexNo);
2476 return value = op.getResult();
2483ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2484 auto loc = getToken().getLoc();
2485 SmallVector<StringRef, 3> fields;
2486 if (parseFieldIdSeq(fields,
"expected field name"))
2488 for (
auto fieldName : fields) {
2489 std::optional<unsigned> indexV;
2490 auto type = result.getType();
2491 if (
auto refTy = type_dyn_cast<RefType>(type))
2492 type = refTy.getType();
2493 if (
auto bundle = type_dyn_cast<BundleType>(type))
2494 indexV = bundle.getElementIndex(fieldName);
2495 else if (
auto bundle = type_dyn_cast<OpenBundleType>(type))
2496 indexV = bundle.getElementIndex(fieldName);
2497 else if (
auto klass = type_dyn_cast<ClassType>(type))
2498 indexV = klass.getElementIndex(fieldName);
2500 return emitError(loc,
"subfield requires bundle or object operand ");
2502 return emitError(loc,
"unknown field '" + fieldName +
"' in type ")
2503 << result.getType();
2504 auto indexNo = *indexV;
2506 FailureOr<Value> subResult;
2507 if (type_isa<RefType>(result.getType()))
2508 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2509 else if (type_isa<ClassType>(type))
2510 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2511 else if (type_isa<BundleType>(type))
2512 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2514 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2516 if (failed(subResult))
2518 result = *subResult;
2527ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2528 auto loc = getToken().getLoc();
2530 if (parseIntLit(indexNo,
"expected index") ||
2531 parseToken(FIRToken::r_square,
"expected ']'"))
2535 return emitError(loc,
"invalid index specifier"), failure();
2537 FailureOr<Value> subResult;
2538 if (type_isa<RefType>(result.getType()))
2539 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2540 else if (type_isa<FVectorType>(result.getType()))
2541 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2543 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2545 if (failed(subResult))
2547 result = *subResult;
2555ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2556 auto loc = getToken().getLoc();
2558 if (parseExp(index,
"expected subscript index expression") ||
2559 parseToken(FIRToken::r_square,
"expected ']' in subscript"))
2563 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2565 return emitError(
"expected base type for index expression");
2566 indexType = indexType.getPassiveType();
2567 locationProcessor.setLoc(loc);
2572 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2575 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2576 translateLocation(loc));
2581 auto op = SubaccessOp::create(builder, resultType, result, index);
2582 result = op.getResult();
2588ParseResult FIRStmtParser::parseIntegerLiteralExp(Value &result) {
2589 bool isSigned = getToken().is(FIRToken::kw_SInt);
2590 auto loc = getToken().getLoc();
2596 if (parseOptionalWidth(width) ||
2597 parseToken(FIRToken::l_paren,
"expected '(' in integer expression") ||
2598 parseIntLit(value,
"expected integer value") ||
2599 parseToken(FIRToken::r_paren,
"expected ')' in integer expression"))
2604 auto type =
IntType::get(builder.getContext(), isSigned, width,
true);
2606 IntegerType::SignednessSemantics signedness =
2607 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2609 if (!value.isZero())
2610 return emitError(loc,
"zero bit constant must be zero");
2611 value = value.trunc(0);
2612 }
else if (width != -1) {
2614 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2616 return emitError(loc,
"initializer too wide for declared width");
2617 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2621 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2622 auto attr = builder.getIntegerAttr(attrType, value);
2624 locationProcessor.setLoc(loc);
2625 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2630ParseResult FIRStmtParser::parseListExp(Value &result) {
2631 auto loc = getToken().getLoc();
2633 if (parseListType(type))
2635 auto listType = type_cast<ListType>(type);
2638 if (parseToken(FIRToken::l_paren,
"expected '(' in List expression"))
2641 SmallVector<Value, 3> operands;
2642 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2644 locationProcessor.setLoc(loc);
2645 if (parseExp(operand,
"expected expression in List expression"))
2649 if (!isa<AnyRefType>(elementType) ||
2650 !isa<ClassType>(operand.getType()))
2651 return emitError(loc,
"unexpected expression of type ")
2652 << operand.getType() <<
" in List expression of type "
2654 operand = ObjectAnyRefCastOp::create(builder, operand);
2657 operands.push_back(operand);
2662 locationProcessor.setLoc(loc);
2663 result = ListCreateOp::create(builder, listType, operands);
2668ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2669 consumeToken(FIRToken::lp_list_concat);
2671 auto loc = getToken().getLoc();
2673 SmallVector<Value, 3> operands;
2674 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2676 locationProcessor.setLoc(loc);
2677 if (parseExp(operand,
"expected expression in List concat expression"))
2680 if (!type_isa<ListType>(operand.getType()))
2681 return emitError(loc,
"unexpected expression of type ")
2682 << operand.getType() <<
" in List concat expression";
2685 type = type_cast<ListType>(operand.getType());
2687 if (operand.getType() != type)
2688 return emitError(loc,
"unexpected expression of type ")
2689 << operand.getType() <<
" in List concat expression of type "
2692 operands.push_back(operand);
2697 if (operands.empty())
2698 return emitError(loc,
"need at least one List to concatenate");
2700 locationProcessor.setLoc(loc);
2701 result = ListConcatOp::create(builder, type, operands);
2706ParseResult FIRStmtParser::parseCatExp(Value &result) {
2707 consumeToken(FIRToken::lp_cat);
2709 auto loc = getToken().getLoc();
2710 SmallVector<Value, 3> operands;
2711 std::optional<bool> isSigned;
2712 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2714 locationProcessor.setLoc(loc);
2715 auto operandLoc = getToken().getLoc();
2716 if (parseExp(operand,
"expected expression in cat expression"))
2718 if (!type_isa<IntType>(operand.getType())) {
2719 auto diag = emitError(loc,
"all operands must be Int type");
2720 diag.attachNote(translateLocation(operandLoc))
2721 <<
"non-integer operand is here";
2725 isSigned = type_isa<SIntType>(operand.getType());
2726 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2727 auto diag = emitError(loc,
"all operands must have same signedness");
2728 diag.attachNote(translateLocation(operandLoc))
2729 <<
"operand with different signedness is here";
2733 operands.push_back(operand);
2738 if (operands.size() != 2) {
2743 locationProcessor.setLoc(loc);
2744 result = CatPrimOp::create(builder, operands);
2748ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
2749 consumeToken(FIRToken::lp_unsafe_domain_cast);
2751 auto loc = getToken().getLoc();
2753 if (parseExp(input,
"expected input"))
2756 SmallVector<Value> domains;
2757 if (consumeIf(FIRToken::comma)) {
2758 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2760 if (parseExp(domain,
"expected domain"))
2762 domains.push_back(domain);
2766 }
else if (parseToken(FIRToken::r_paren,
"expected closing parenthesis")) {
2770 locationProcessor.setLoc(loc);
2771 result = UnsafeDomainCastOp::create(builder, input, domains);
2792std::optional<ParseResult>
2793FIRStmtParser::parseExpWithLeadingKeyword(
FIRToken keyword) {
2794 switch (getToken().getKind()) {
2797 return std::nullopt;
2799 case FIRToken::period:
2800 case FIRToken::l_square:
2801 case FIRToken::kw_is:
2802 case FIRToken::less_equal:
2808 auto loc = keyword.
getLoc();
2810 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.
getSpelling(), loc))
2811 return ParseResult(failure());
2817 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
2820 if (!consumeIf(FIRToken::period))
2821 return ParseResult(failure());
2823 StringRef fieldName;
2824 if (parseFieldId(fieldName,
"expected field name") ||
2825 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
2826 return ParseResult(failure());
2830 if (parseOptionalExpPostscript(lhs))
2831 return ParseResult(failure());
2833 return parseLeadingExpStmt(lhs);
2839ParseResult FIRStmtParser::parseSimpleStmtBlock(
unsigned indent) {
2842 if (getToken().isAny(FIRToken::eof, FIRToken::error))
2845 auto subIndent = getIndentation();
2846 if (!subIndent.has_value())
2847 return emitError(
"expected statement to be on its own line"), failure();
2849 if (*subIndent <= indent)
2853 if (parseSimpleStmt(*subIndent))
2858ParseResult FIRStmtParser::parseSimpleStmt(
unsigned stmtIndent) {
2859 locationProcessor.startStatement();
2860 auto result = parseSimpleStmtImpl(stmtIndent);
2861 locationProcessor.endStatement(*
this);
2883ParseResult FIRStmtParser::parseSimpleStmtImpl(
unsigned stmtIndent) {
2884 auto kind = getToken().getKind();
2887 case FIRToken::kw_invalidate:
2888 case FIRToken::kw_connect:
2889 case FIRToken::kw_regreset:
2893 kind = FIRToken::identifier;
2900 case FIRToken::kw_attach:
2901 return parseAttach();
2902 case FIRToken::kw_infer:
2903 return parseMemPort(MemDirAttr::Infer);
2904 case FIRToken::kw_read:
2905 return parseMemPort(MemDirAttr::Read);
2906 case FIRToken::kw_write:
2907 return parseMemPort(MemDirAttr::Write);
2908 case FIRToken::kw_rdwr:
2909 return parseMemPort(MemDirAttr::ReadWrite);
2910 case FIRToken::kw_connect:
2911 return parseConnect();
2912 case FIRToken::kw_propassign:
2913 if (requireFeature({3, 1, 0},
"properties"))
2915 return parsePropAssign();
2916 case FIRToken::kw_invalidate:
2917 return parseInvalidate();
2918 case FIRToken::lp_printf:
2919 return parsePrintf();
2920 case FIRToken::lp_fprintf:
2921 return parseFPrintf();
2922 case FIRToken::lp_fflush:
2923 return parseFFlush();
2924 case FIRToken::kw_skip:
2926 case FIRToken::lp_stop:
2928 case FIRToken::lp_assert:
2929 return parseAssert();
2930 case FIRToken::lp_assume:
2931 return parseAssume();
2932 case FIRToken::lp_cover:
2933 return parseCover();
2934 case FIRToken::kw_when:
2935 return parseWhen(stmtIndent);
2936 case FIRToken::kw_match:
2937 return parseMatch(stmtIndent);
2938 case FIRToken::kw_define:
2939 return parseRefDefine();
2940 case FIRToken::lp_force:
2941 return parseRefForce();
2942 case FIRToken::lp_force_initial:
2943 return parseRefForceInitial();
2944 case FIRToken::lp_release:
2945 return parseRefRelease();
2946 case FIRToken::lp_release_initial:
2947 return parseRefReleaseInitial();
2948 case FIRToken::kw_group:
2949 if (requireFeature({3, 2, 0},
"optional groups") ||
2950 removedFeature({3, 3, 0},
"optional groups"))
2952 return parseLayerBlockOrGroup(stmtIndent);
2953 case FIRToken::kw_layerblock:
2954 if (requireFeature({3, 3, 0},
"layers"))
2956 return parseLayerBlockOrGroup(stmtIndent);
2957 case FIRToken::lp_intrinsic:
2958 if (requireFeature({4, 0, 0},
"generic intrinsics"))
2960 return parseIntrinsicStmt();
2964 if (parseExpLeadingStmt(lhs,
"unexpected token in module"))
2971 return parseLeadingExpStmt(lhs);
2975 case FIRToken::kw_inst:
2976 return parseInstance();
2977 case FIRToken::kw_instchoice:
2978 return parseInstanceChoice();
2979 case FIRToken::kw_object:
2980 return parseObject();
2981 case FIRToken::kw_cmem:
2982 return parseCombMem();
2983 case FIRToken::kw_smem:
2984 return parseSeqMem();
2985 case FIRToken::kw_mem:
2986 return parseMem(stmtIndent);
2987 case FIRToken::kw_node:
2989 case FIRToken::kw_wire:
2991 case FIRToken::kw_reg:
2992 return parseRegister(stmtIndent);
2993 case FIRToken::kw_regreset:
2994 return parseRegisterWithReset();
2995 case FIRToken::kw_contract:
2996 return parseContract(stmtIndent);
3000ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3002 SymbolRefAttr layerSym) {
3004 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3005 moduleContext, &blockToInsertInto);
3010 UnbundledValueRestorer x(moduleContext.unbundledValues);
3014 auto subParser = std::make_unique<FIRStmtParser>(
3015 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3019 auto stmtIndent = getIndentation();
3022 if (!stmtIndent.has_value())
3023 return subParser->parseSimpleStmt(indent);
3025 if (*stmtIndent <= indent)
3026 return emitError(
"statement must be indented more than previous statement"),
3030 return subParser->parseSimpleStmtBlock(indent);
3034ParseResult FIRStmtParser::parseAttach() {
3035 auto startTok = consumeToken(FIRToken::kw_attach);
3038 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3041 if (parseToken(FIRToken::l_paren,
"expected '(' after attach"))
3044 SmallVector<Value, 4> operands;
3045 operands.push_back({});
3046 if (parseExp(operands.back(),
"expected operand in attach"))
3049 while (consumeIf(FIRToken::comma)) {
3050 operands.push_back({});
3051 if (parseExp(operands.back(),
"expected operand in attach"))
3054 if (parseToken(FIRToken::r_paren,
"expected close paren"))
3057 if (parseOptionalInfo())
3060 locationProcessor.setLoc(startTok.getLoc());
3061 AttachOp::create(builder, operands);
3068ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3069 auto startTok = consumeToken();
3070 auto startLoc = startTok.getLoc();
3074 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3080 Value memory, indexExp, clock;
3081 if (parseToken(FIRToken::kw_mport,
"expected 'mport' in memory port") ||
3082 parseId(
id,
"expected result name") ||
3083 parseToken(FIRToken::equal,
"expected '=' in memory port") ||
3084 parseId(memName,
"expected memory name") ||
3085 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3086 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3087 parseToken(FIRToken::l_square,
"expected '[' in memory port") ||
3088 parseExp(indexExp,
"expected index expression") ||
3089 parseToken(FIRToken::r_square,
"expected ']' in memory port") ||
3090 parseToken(FIRToken::comma,
"expected ','") ||
3091 parseExp(clock,
"expected clock expression") || parseOptionalInfo())
3094 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3096 return emitError(startLoc,
3097 "memory port should have behavioral memory type");
3098 auto resultType = memVType.getElementType();
3100 ArrayAttr annotations = getConstants().emptyArrayAttr;
3101 locationProcessor.setLoc(startLoc);
3104 Value memoryPort, memoryData;
3106 OpBuilder::InsertionGuard guard(builder);
3107 builder.setInsertionPointAfterValue(memory);
3108 auto memoryPortOp = MemoryPortOp::create(
3109 builder, resultType, CMemoryPortType::get(getContext()), memory,
3110 direction,
id, annotations);
3111 memoryData = memoryPortOp.getResult(0);
3112 memoryPort = memoryPortOp.getResult(1);
3116 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3118 return moduleContext.addSymbolEntry(
id, memoryData, startLoc,
true);
3124ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3125 StringRef formatString,
3126 ArrayRef<Value> specOperands,
3127 StringAttr &formatStringResult,
3128 SmallVectorImpl<Value> &operands) {
3132 SmallVector<Attribute, 4> specialSubstitutions;
3133 SmallString<64> validatedFormatString;
3135 validatedFormatString = formatString;
3136 operands.append(specOperands.begin(), specOperands.end());
3138 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
3139 auto c = formatString[i];
3144 validatedFormatString.push_back(c);
3147 SmallString<6> width;
3148 c = formatString[++i];
3151 c = formatString[++i];
3157 if (!width.empty()) {
3158 emitError(formatStringLoc) <<
"ASCII character format specifiers "
3159 "('%c') may not specify a width";
3167 validatedFormatString.append(width);
3168 operands.push_back(specOperands[opIdx++]);
3171 if (!width.empty()) {
3172 emitError(formatStringLoc)
3173 <<
"literal percents ('%%') may not specify a width";
3179 emitError(formatStringLoc)
3180 <<
"unknown printf substitution '%" << width << c <<
"'";
3183 validatedFormatString.push_back(c);
3191 if (formatString[i + 1] !=
'{') {
3192 validatedFormatString.push_back(c);
3198 while (formatString[i] !=
'}')
3200 if (formatString[i] !=
'}') {
3201 llvm::errs() <<
"expected '}' to terminate special substitution";
3205 auto specialString = formatString.slice(start, i);
3206 if (specialString ==
"SimulationTime") {
3207 operands.push_back(TimeOp::create(builder));
3208 }
else if (specialString ==
"HierarchicalModuleName") {
3209 operands.push_back(HierarchicalModuleNameOp::create(builder));
3211 emitError(formatStringLoc)
3212 <<
"unknown printf substitution '" << specialString
3213 <<
"' (did you misspell it?)";
3217 validatedFormatString.append(
"{{}}");
3222 validatedFormatString.push_back(c);
3227 formatStringResult =
3233ParseResult FIRStmtParser::parsePrintf() {
3234 auto startTok = consumeToken(FIRToken::lp_printf);
3236 Value clock, condition;
3237 StringRef formatString;
3238 if (parseExp(clock,
"expected clock expression in printf") ||
3239 parseToken(FIRToken::comma,
"expected ','") ||
3240 parseExp(condition,
"expected condition in printf") ||
3241 parseToken(FIRToken::comma,
"expected ','"))
3244 auto formatStringLoc = getToken().getLoc();
3245 if (parseGetSpelling(formatString) ||
3246 parseToken(FIRToken::string,
"expected format string in printf"))
3249 SmallVector<Value, 4> specOperands;
3250 while (consumeIf(FIRToken::comma)) {
3251 specOperands.push_back({});
3252 if (parseExp(specOperands.back(),
"expected operand in printf"))
3257 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3258 parseOptionalName(name) || parseOptionalInfo())
3261 locationProcessor.setLoc(startTok.getLoc());
3263 StringAttr formatStrUnescaped;
3264 SmallVector<Value> operands;
3265 if (parseFormatString(formatStringLoc, formatString, specOperands,
3266 formatStrUnescaped, operands))
3269 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3275ParseResult FIRStmtParser::parseFPrintf() {
3278 auto startTok = consumeToken(FIRToken::lp_fprintf);
3280 Value clock, condition;
3281 StringRef outputFile, formatString;
3282 if (parseExp(clock,
"expected clock expression in fprintf") ||
3283 parseToken(FIRToken::comma,
"expected ','") ||
3284 parseExp(condition,
"expected condition in fprintf") ||
3285 parseToken(FIRToken::comma,
"expected ','"))
3288 auto outputFileLoc = getToken().getLoc();
3289 if (parseGetSpelling(outputFile) ||
3290 parseToken(FIRToken::string,
"expected output file in fprintf"))
3293 SmallVector<Value, 4> outputFileSpecOperands;
3294 while (consumeIf(FIRToken::comma)) {
3296 if (getToken().getKind() == FIRToken::string)
3298 outputFileSpecOperands.push_back({});
3299 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fprintf"))
3303 auto formatStringLoc = getToken().getLoc();
3304 if (parseGetSpelling(formatString) ||
3305 parseToken(FIRToken::string,
"expected format string in printf"))
3308 SmallVector<Value, 4> specOperands;
3309 while (consumeIf(FIRToken::comma)) {
3310 specOperands.push_back({});
3311 if (parseExp(specOperands.back(),
"expected operand in fprintf"))
3316 if (parseToken(FIRToken::r_paren,
"expected ')'") ||
3317 parseOptionalName(name) || parseOptionalInfo())
3320 locationProcessor.setLoc(startTok.getLoc());
3322 StringAttr outputFileNameStrUnescaped;
3323 SmallVector<Value> outputFileOperands;
3324 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3325 outputFileNameStrUnescaped, outputFileOperands))
3328 StringAttr formatStrUnescaped;
3329 SmallVector<Value> operands;
3330 if (parseFormatString(formatStringLoc, formatString, specOperands,
3331 formatStrUnescaped, operands))
3334 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3335 outputFileOperands, formatStrUnescaped, operands, name);
3340ParseResult FIRStmtParser::parseFFlush() {
3344 auto startTok = consumeToken(FIRToken::lp_fflush);
3346 Value clock, condition;
3347 if (parseExp(clock,
"expected clock expression in 'fflush'") ||
3348 parseToken(FIRToken::comma,
"expected ','") ||
3349 parseExp(condition,
"expected condition in 'fflush'"))
3352 locationProcessor.setLoc(startTok.getLoc());
3353 StringAttr outputFileNameStrUnescaped;
3354 SmallVector<Value> outputFileOperands;
3356 if (consumeIf(FIRToken::comma)) {
3357 SmallVector<Value, 4> outputFileSpecOperands;
3358 auto outputFileLoc = getToken().getLoc();
3359 StringRef outputFile;
3360 if (parseGetSpelling(outputFile) ||
3361 parseToken(FIRToken::string,
"expected output file in fflush"))
3364 while (consumeIf(FIRToken::comma)) {
3365 outputFileSpecOperands.push_back({});
3366 if (parseExp(outputFileSpecOperands.back(),
"expected operand in fflush"))
3370 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3371 outputFileNameStrUnescaped, outputFileOperands))
3375 if (parseToken(FIRToken::r_paren,
"expected ')' in 'fflush'") ||
3376 parseOptionalInfo())
3379 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3380 outputFileOperands);
3385ParseResult FIRStmtParser::parseSkip() {
3386 auto startTok = consumeToken(FIRToken::kw_skip);
3390 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3393 if (parseOptionalInfo())
3396 locationProcessor.setLoc(startTok.getLoc());
3397 SkipOp::create(builder);
3402ParseResult FIRStmtParser::parseStop() {
3403 auto startTok = consumeToken(FIRToken::lp_stop);
3405 Value clock, condition;
3408 if (parseExp(clock,
"expected clock expression in 'stop'") ||
3409 parseToken(FIRToken::comma,
"expected ','") ||
3410 parseExp(condition,
"expected condition in 'stop'") ||
3411 parseToken(FIRToken::comma,
"expected ','") ||
3412 parseIntLit(exitCode,
"expected exit code in 'stop'") ||
3413 parseToken(FIRToken::r_paren,
"expected ')' in 'stop'") ||
3414 parseOptionalName(name) || parseOptionalInfo())
3417 locationProcessor.setLoc(startTok.getLoc());
3418 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3424ParseResult FIRStmtParser::parseAssert() {
3425 auto startTok = consumeToken(FIRToken::lp_assert);
3427 Value clock, predicate, enable;
3428 StringRef formatString;
3430 if (parseExp(clock,
"expected clock expression in 'assert'") ||
3431 parseToken(FIRToken::comma,
"expected ','") ||
3432 parseExp(predicate,
"expected predicate in 'assert'") ||
3433 parseToken(FIRToken::comma,
"expected ','") ||
3434 parseExp(enable,
"expected enable in 'assert'") ||
3435 parseToken(FIRToken::comma,
"expected ','") ||
3436 parseGetSpelling(formatString) ||
3437 parseToken(FIRToken::string,
"expected format string in 'assert'"))
3440 SmallVector<Value, 4> operands;
3441 while (!consumeIf(FIRToken::r_paren)) {
3442 operands.push_back({});
3443 if (parseToken(FIRToken::comma,
"expected ','") ||
3444 parseExp(operands.back(),
"expected operand in 'assert'"))
3448 if (parseOptionalName(name) || parseOptionalInfo())
3451 locationProcessor.setLoc(startTok.getLoc());
3453 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3454 operands, name.getValue());
3459ParseResult FIRStmtParser::parseAssume() {
3460 auto startTok = consumeToken(FIRToken::lp_assume);
3462 Value clock, predicate, enable;
3463 StringRef formatString;
3465 if (parseExp(clock,
"expected clock expression in 'assume'") ||
3466 parseToken(FIRToken::comma,
"expected ','") ||
3467 parseExp(predicate,
"expected predicate in 'assume'") ||
3468 parseToken(FIRToken::comma,
"expected ','") ||
3469 parseExp(enable,
"expected enable in 'assume'") ||
3470 parseToken(FIRToken::comma,
"expected ','") ||
3471 parseGetSpelling(formatString) ||
3472 parseToken(FIRToken::string,
"expected format string in 'assume'"))
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 'assume'"))
3483 if (parseOptionalName(name) || parseOptionalInfo())
3486 locationProcessor.setLoc(startTok.getLoc());
3488 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3489 operands, name.getValue());
3494ParseResult FIRStmtParser::parseCover() {
3495 auto startTok = consumeToken(FIRToken::lp_cover);
3497 Value clock, predicate, enable;
3500 if (parseExp(clock,
"expected clock expression in 'cover'") ||
3501 parseToken(FIRToken::comma,
"expected ','") ||
3502 parseExp(predicate,
"expected predicate in 'cover'") ||
3503 parseToken(FIRToken::comma,
"expected ','") ||
3504 parseExp(enable,
"expected enable in 'cover'") ||
3505 parseToken(FIRToken::comma,
"expected ','") ||
3506 parseGetSpelling(message) ||
3507 parseToken(FIRToken::string,
"expected message in 'cover'") ||
3508 parseToken(FIRToken::r_paren,
"expected ')' in 'cover'") ||
3509 parseOptionalName(name) || parseOptionalInfo())
3512 locationProcessor.setLoc(startTok.getLoc());
3514 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3515 ValueRange{}, name.getValue());
3521ParseResult FIRStmtParser::parseWhen(
unsigned whenIndent) {
3522 auto startTok = consumeToken(FIRToken::kw_when);
3526 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3530 if (parseExp(condition,
"expected condition in 'when'") ||
3531 parseToken(FIRToken::colon,
"expected ':' in when") ||
3532 parseOptionalInfo())
3535 locationProcessor.setLoc(startTok.getLoc());
3537 auto whenStmt = WhenOp::create(builder, condition,
false);
3540 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3544 if (getToken().isNot(FIRToken::kw_else))
3549 auto elseIndent = getIndentation();
3550 if (elseIndent && *elseIndent < whenIndent)
3553 consumeToken(FIRToken::kw_else);
3556 whenStmt.createElseRegion();
3562 if (getToken().is(FIRToken::kw_when)) {
3564 auto subParser = std::make_unique<FIRStmtParser>(
3565 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3568 return subParser->parseSimpleStmt(whenIndent);
3572 LocationAttr elseLoc;
3573 if (parseToken(FIRToken::colon,
"expected ':' after 'else'") ||
3574 parseOptionalInfoLocator(elseLoc) ||
3575 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3584ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3585 auto startLoc = getToken().getLoc();
3586 locationProcessor.setLoc(startLoc);
3588 if (parseEnumType(type))
3592 auto enumType = type_dyn_cast<FEnumType>(type);
3594 return emitError(startLoc,
3595 "expected enumeration type in enumeration expression");
3598 if (parseToken(FIRToken::l_paren,
"expected '(' in enumeration expression") ||
3599 parseId(tag,
"expected enumeration tag"))
3603 if (consumeIf(FIRToken::r_paren)) {
3606 auto type =
IntType::get(builder.getContext(),
false, 0,
true);
3607 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3608 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0,
false));
3609 input = ConstantOp::create(builder, type, attr);
3612 if (parseToken(FIRToken::comma,
"expected ','") ||
3613 parseExp(input,
"expected expression in enumeration value") ||
3614 parseToken(FIRToken::r_paren,
"expected closing ')'"))
3618 value = FEnumCreateOp::create(builder, enumType, tag, input);
3626ParseResult FIRStmtParser::parseMatch(
unsigned matchIndent) {
3627 auto startTok = consumeToken(FIRToken::kw_match);
3629 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
3633 if (parseExp(input,
"expected expression in 'match'") ||
3634 parseToken(FIRToken::colon,
"expected ':' in 'match'") ||
3635 parseOptionalInfo())
3638 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3640 return mlir::emitError(
3642 "expected enumeration type for 'match' statement, but got ")
3645 locationProcessor.setLoc(startTok.getLoc());
3647 SmallVector<Attribute> tags;
3648 SmallVector<std::unique_ptr<Region>> regions;
3650 auto tagLoc = getToken().getLoc();
3653 auto caseIndent = getIndentation();
3654 if (!caseIndent || *caseIndent <= matchIndent)
3658 StringRef tagSpelling;
3659 if (parseId(tagSpelling,
"expected enumeration tag in match statement"))
3661 auto tagIndex = enumType.getElementIndex(tagSpelling);
3663 return emitError(tagLoc,
"tag ")
3664 << tagSpelling <<
" not a member of enumeration " << enumType;
3665 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3666 tags.push_back(tag);
3669 auto *caseBlock = ®ions.emplace_back(
new Region)->emplaceBlock();
3672 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3677 UnbundledValueRestorer x(moduleContext.unbundledValues);
3680 if (consumeIf(FIRToken::l_paren)) {
3681 StringAttr identifier;
3682 if (parseId(identifier,
"expected identifier for 'case' binding"))
3686 auto dataType = enumType.getElementType(*tagIndex);
3687 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3689 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3693 if (parseToken(FIRToken::r_paren,
"expected ')' in match statement case"))
3697 auto dataType =
IntType::get(builder.getContext(),
false, 0);
3698 caseBlock->addArgument(dataType, LocWithInfo(tagLoc,
this).
getLoc());
3701 if (parseToken(FIRToken::colon,
"expected ':' in match statement case"))
3705 auto subParser = std::make_unique<FIRStmtParser>(
3706 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3708 if (subParser->parseSimpleStmtBlock(*caseIndent))
3712 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3718ParseResult FIRStmtParser::parseRefExp(Value &result,
const Twine &message) {
3719 auto token = getToken().getKind();
3720 if (token == FIRToken::lp_probe)
3721 return parseProbe(result);
3722 if (token == FIRToken::lp_rwprobe)
3723 return parseRWProbe(result);
3728 return parseStaticRefExp(result, message);
3735ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3736 const Twine &message) {
3737 auto parseIdOrInstance = [&]() -> ParseResult {
3739 auto loc = getToken().getLoc();
3741 if (parseId(
id, message) ||
3742 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3746 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc,
false))
3749 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
3752 StringRef fieldName;
3754 parseToken(FIRToken::period,
"expected '.' in field reference") ||
3755 parseFieldId(fieldName,
"expected field name") ||
3756 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3758 return failure(parseIdOrInstance() ||
3759 parseOptionalExpPostscript(result,
false));
3770ParseResult FIRStmtParser::parseRWProbeStaticRefExp(
FieldRef &refResult,
3772 const Twine &message) {
3773 auto loc = getToken().getLoc();
3777 if (parseId(
id, message) ||
3778 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
3790 if (
auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3792 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3794 StringRef fieldName;
3795 auto loc = getToken().getLoc();
3796 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
3797 parseFieldId(fieldName,
"expected field name"))
3802 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3803 for (
auto &elt : ubEntry) {
3804 if (elt.first == fieldAttr) {
3807 auto &instResult = elt.second;
3810 auto *defining = instResult.getDefiningOp();
3812 if (isa<WireOp>(defining)) {
3813 result = instResult;
3818 auto type = instResult.getType();
3822 bool forceable =
static_cast<bool>(
3825 return emitError(loc,
"unable to force instance result of type ")
3829 auto annotations = getConstants().emptyArrayAttr;
3830 StringAttr sym = {};
3831 SmallString<64> name;
3832 (
id +
"_" + fieldName +
"_bounce").
toVector(name);
3833 locationProcessor.setLoc(loc);
3834 OpBuilder::InsertionGuard guard(builder);
3835 builder.setInsertionPoint(defining);
3837 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3839 auto bounceVal = bounce.getData();
3842 instResult.replaceAllUsesWith(bounceVal);
3845 builder.setInsertionPointAfter(defining);
3846 if (
foldFlow(instResult) == Flow::Source)
3853 result = instResult = bounce.getDataRaw();
3859 emitError(loc,
"use of invalid field name '")
3860 << fieldName <<
"' on bundle value";
3865 result = cast<Value>(symtabEntry);
3869 assert(isa<BlockArgument>(result) ||
3870 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3876 type = result.getType();
3878 if (consumeIf(FIRToken::period)) {
3879 SmallVector<StringRef, 3> fields;
3880 if (parseFieldIdSeq(fields,
"expected field name"))
3882 for (
auto fieldName : fields) {
3883 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
3884 if (
auto index = bundle.getElementIndex(fieldName)) {
3885 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3886 type = bundle.getElementTypePreservingConst(*index);
3889 }
else if (
auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3890 if (
auto index = bundle.getElementIndex(fieldName)) {
3891 refResult = refResult.
getSubField(bundle.getFieldID(*index));
3892 type = bundle.getElementTypePreservingConst(*index);
3896 return emitError(loc,
"subfield requires bundle operand")
3897 <<
"got " << type <<
"\n";
3899 return emitError(loc,
3900 "unknown field '" + fieldName +
"' in bundle type ")
3905 if (consumeIf(FIRToken::l_square)) {
3906 auto loc = getToken().
getLoc();
3908 if (parseIntLit(index,
"expected index") ||
3909 parseToken(FIRToken::r_square,
"expected ']'"))
3913 return emitError(loc,
"invalid index specifier");
3915 if (
auto vector = type_dyn_cast<FVectorType>(type)) {
3916 if ((
unsigned)index < vector.getNumElements()) {
3917 refResult = refResult.
getSubField(vector.getFieldID(index));
3918 type = vector.getElementTypePreservingConst();
3921 }
else if (
auto vector = type_dyn_cast<OpenVectorType>(type)) {
3922 if ((
unsigned)index < vector.getNumElements()) {
3923 refResult = refResult.
getSubField(vector.getFieldID(index));
3924 type = vector.getElementTypePreservingConst();
3928 return emitError(loc,
"subindex requires vector operand");
3930 return emitError(loc,
"out of range index '")
3931 << index <<
"' for vector type " << type;
3939ParseResult FIRStmtParser::parseIntrinsic(Value &result,
bool isStatement) {
3940 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3941 StringRef intrinsic;
3942 ArrayAttr parameters;
3945 if (parseId(intrinsic,
"expected intrinsic identifier") ||
3946 parseOptionalParams(parameters))
3949 if (consumeIf(FIRToken::colon)) {
3950 if (
parseType(type,
"expected intrinsic return type"))
3952 }
else if (!isStatement)
3953 return emitError(
"expected ':' in intrinsic expression");
3955 SmallVector<Value> operands;
3956 auto loc = startTok.getLoc();
3957 if (consumeIf(FIRToken::comma)) {
3958 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3960 if (parseExp(operand,
"expected operand in intrinsic"))
3962 operands.push_back(operand);
3963 locationProcessor.setLoc(loc);
3968 if (parseToken(FIRToken::r_paren,
"expected ')' in intrinsic"))
3973 if (parseOptionalInfo())
3976 locationProcessor.setLoc(loc);
3978 auto op = GenericIntrinsicOp::create(
3979 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
3981 result = op.getResult();
3986ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3987 if (!consumeIf(FIRToken::less))
3990 SmallVector<Attribute, 8> parameters;
3991 SmallPtrSet<StringAttr, 8> seen;
3992 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3996 if (parseParameter(name, value, loc))
3998 auto typedValue = dyn_cast<TypedAttr>(value);
4000 return emitError(loc)
4001 <<
"invalid value for parameter '" << name.getValue() <<
"'";
4002 if (!seen.insert(name).second)
4003 return emitError(loc,
"redefinition of parameter '" +
4004 name.getValue() +
"'");
4005 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4010 resultParameters = ArrayAttr::get(getContext(), parameters);
4016ParseResult FIRStmtParser::parsePathExp(Value &result) {
4017 auto startTok = consumeToken(FIRToken::lp_path);
4018 locationProcessor.setLoc(startTok.getLoc());
4020 if (parseGetSpelling(target) ||
4021 parseToken(FIRToken::string,
4022 "expected target string in path expression") ||
4023 parseToken(FIRToken::r_paren,
"expected ')' in path expression"))
4025 result = UnresolvedPathOp::create(
4031ParseResult FIRStmtParser::parseRefDefine() {
4032 auto startTok = consumeToken(FIRToken::kw_define);
4035 if (parseStaticRefExp(target,
4036 "expected static reference expression in 'define'") ||
4037 parseToken(FIRToken::equal,
4038 "expected '=' after define reference expression") ||
4039 parseRefExp(src,
"expected reference expression in 'define'") ||
4040 parseOptionalInfo())
4044 if (!type_isa<RefType>(target.getType()))
4045 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4046 "'define' target (LHS), got ")
4047 << target.getType();
4048 if (!type_isa<RefType>(src.getType()))
4049 return emitError(startTok.getLoc(),
"expected reference-type expression in "
4050 "'define' source (RHS), got ")
4055 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4056 return emitError(startTok.getLoc(),
4057 "cannot define into a sub-element of a reference");
4059 locationProcessor.setLoc(startTok.getLoc());
4062 return emitError(startTok.getLoc(),
"cannot define reference of type ")
4063 << target.getType() <<
" with incompatible reference of type "
4073ParseResult FIRStmtParser::parseRefRead(Value &result) {
4074 auto startTok = consumeToken(FIRToken::lp_read);
4077 if (parseRefExp(ref,
"expected reference expression in 'read'") ||
4078 parseToken(FIRToken::r_paren,
"expected ')' in 'read'"))
4081 locationProcessor.setLoc(startTok.getLoc());
4084 if (!type_isa<RefType>(ref.getType()))
4085 return emitError(startTok.getLoc(),
4086 "expected reference-type expression in 'read', got ")
4089 result = RefResolveOp::create(builder, ref);
4095ParseResult FIRStmtParser::parseProbe(Value &result) {
4096 auto startTok = consumeToken(FIRToken::lp_probe);
4099 if (parseStaticRefExp(staticRef,
4100 "expected static reference expression in 'probe'") ||
4101 parseToken(FIRToken::r_paren,
"expected ')' in 'probe'"))
4104 locationProcessor.setLoc(startTok.getLoc());
4107 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4108 return emitError(startTok.getLoc(),
4109 "expected base-type expression in 'probe', got ")
4110 << staticRef.getType();
4114 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4115 MemoryDebugPortOp, MemoryPortAccessOp>(
4116 staticRef.getDefiningOp()))
4117 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4119 result = RefSendOp::create(builder, staticRef);
4125ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4126 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4129 Type parsedTargetType;
4130 if (parseRWProbeStaticRefExp(
4131 staticRef, parsedTargetType,
4132 "expected static reference expression in 'rwprobe'") ||
4133 parseToken(FIRToken::r_paren,
"expected ')' in 'rwprobe'"))
4136 locationProcessor.setLoc(startTok.getLoc());
4142 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4144 return emitError(startTok.getLoc(),
4145 "expected base-type expression in 'rwprobe', got ")
4146 << parsedTargetType;
4149 auto *definingOp = root.getDefiningOp();
4151 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4152 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4153 return emitError(startTok.getLoc(),
"cannot probe memories or their ports");
4157 return emitError(startTok.getLoc(),
"cannot force target of type ")
4161 auto op = RWProbeOp::create(builder, forceableType,
4162 getConstants().placeholderInnerRef);
4169ParseResult FIRStmtParser::parseRefForce() {
4170 auto startTok = consumeToken(FIRToken::lp_force);
4172 Value clock, pred, dest, src;
4173 if (parseExp(clock,
"expected clock expression in force") ||
4174 parseToken(FIRToken::comma,
"expected ','") ||
4175 parseExp(pred,
"expected predicate expression in force") ||
4176 parseToken(FIRToken::comma,
"expected ','") ||
4177 parseRefExp(dest,
"expected destination reference expression in force") ||
4178 parseToken(FIRToken::comma,
"expected ','") ||
4179 parseExp(src,
"expected source expression in force") ||
4180 parseToken(FIRToken::r_paren,
"expected ')' in force") ||
4181 parseOptionalInfo())
4185 auto ref = type_dyn_cast<RefType>(dest.getType());
4186 if (!ref || !ref.getForceable())
4189 "expected rwprobe-type expression for force destination, got ")
4191 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4193 return emitError(startTok.getLoc(),
4194 "expected base-type for force source, got ")
4196 if (!srcBaseType.isPassive())
4197 return emitError(startTok.getLoc(),
4198 "expected passive value for force source, got ")
4201 locationProcessor.setLoc(startTok.getLoc());
4204 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4205 if (noConstSrcType != ref.getType()) {
4207 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4209 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4211 return emitError(startTok.getLoc(),
"incompatible force source of type ")
4212 << src.getType() <<
" cannot target destination "
4216 RefForceOp::create(builder, clock, pred, dest, src);
4222ParseResult FIRStmtParser::parseRefForceInitial() {
4223 auto startTok = consumeToken(FIRToken::lp_force_initial);
4227 dest,
"expected destination reference expression in force_initial") ||
4228 parseToken(FIRToken::comma,
"expected ','") ||
4229 parseExp(src,
"expected source expression in force_initial") ||
4230 parseToken(FIRToken::r_paren,
"expected ')' in force_initial") ||
4231 parseOptionalInfo())
4235 auto ref = type_dyn_cast<RefType>(dest.getType());
4236 if (!ref || !ref.getForceable())
4237 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4238 "force_initial destination, got ")
4240 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4242 return emitError(startTok.getLoc(),
4243 "expected base-type expression for force_initial "
4246 if (!srcBaseType.isPassive())
4247 return emitError(startTok.getLoc(),
4248 "expected passive value for force_initial source, got ")
4251 locationProcessor.setLoc(startTok.getLoc());
4254 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4255 if (noConstSrcType != ref.getType()) {
4257 auto compatibleRWProbe = RefType::get(noConstSrcType,
true, ref.getLayer());
4259 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4261 return emitError(startTok.getLoc(),
4262 "incompatible force_initial source of type ")
4263 << src.getType() <<
" cannot target destination "
4267 auto value = APInt::getAllOnes(1);
4268 auto type = UIntType::get(builder.getContext(), 1);
4269 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4270 value.getBitWidth(),
4271 IntegerType::Unsigned),
4273 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4274 RefForceInitialOp::create(builder, pred, dest, src);
4280ParseResult FIRStmtParser::parseRefRelease() {
4281 auto startTok = consumeToken(FIRToken::lp_release);
4283 Value clock, pred, dest;
4284 if (parseExp(clock,
"expected clock expression in release") ||
4285 parseToken(FIRToken::comma,
"expected ','") ||
4286 parseExp(pred,
"expected predicate expression in release") ||
4287 parseToken(FIRToken::comma,
"expected ','") ||
4289 "expected destination reference expression in release") ||
4290 parseToken(FIRToken::r_paren,
"expected ')' in release") ||
4291 parseOptionalInfo())
4295 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4296 !ref || !ref.getForceable())
4299 "expected rwprobe-type expression for release destination, got ")
4302 locationProcessor.setLoc(startTok.getLoc());
4304 RefReleaseOp::create(builder, clock, pred, dest);
4310ParseResult FIRStmtParser::parseRefReleaseInitial() {
4311 auto startTok = consumeToken(FIRToken::lp_release_initial);
4316 "expected destination reference expression in release_initial") ||
4317 parseToken(FIRToken::r_paren,
"expected ')' in release_initial") ||
4318 parseOptionalInfo())
4322 if (
auto ref = type_dyn_cast<RefType>(dest.getType());
4323 !ref || !ref.getForceable())
4324 return emitError(startTok.getLoc(),
"expected rwprobe-type expression for "
4325 "release_initial destination, got ")
4328 locationProcessor.setLoc(startTok.getLoc());
4330 auto value = APInt::getAllOnes(1);
4331 auto type = UIntType::get(builder.getContext(), 1);
4332 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4333 value.getBitWidth(),
4334 IntegerType::Unsigned),
4336 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4337 RefReleaseInitialOp::create(builder, pred, dest);
4343ParseResult FIRStmtParser::parseConnect() {
4344 auto startTok = consumeToken(FIRToken::kw_connect);
4345 auto loc = startTok.getLoc();
4348 if (parseExp(lhs,
"expected connect expression") ||
4349 parseToken(FIRToken::comma,
"expected ','") ||
4350 parseExp(rhs,
"expected connect expression") || parseOptionalInfo())
4353 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4354 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4355 if (!lhsType || !rhsType)
4356 return emitError(loc,
"cannot connect reference or property types");
4358 if (lhsType.containsReference() || rhsType.containsReference())
4359 return emitError(loc,
"cannot connect types containing references");
4362 return emitError(loc,
"cannot connect non-equivalent type ")
4363 << rhsType <<
" to " << lhsType;
4365 locationProcessor.setLoc(loc);
4371ParseResult FIRStmtParser::parsePropAssign() {
4372 auto startTok = consumeToken(FIRToken::kw_propassign);
4373 auto loc = startTok.getLoc();
4376 if (parseExp(lhs,
"expected propassign expression") ||
4377 parseToken(FIRToken::comma,
"expected ','") ||
4378 parseExp(rhs,
"expected propassign expression") || parseOptionalInfo())
4381 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4382 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4383 if (!lhsType || !rhsType)
4384 return emitError(loc,
"can only propassign property types");
4385 locationProcessor.setLoc(loc);
4386 if (lhsType != rhsType) {
4388 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4389 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4391 return emitError(loc,
"cannot propassign non-equivalent type ")
4392 << rhsType <<
" to " << lhsType;
4394 PropAssignOp::create(builder, lhs, rhs);
4399ParseResult FIRStmtParser::parseInvalidate() {
4400 auto startTok = consumeToken(FIRToken::kw_invalidate);
4405 auto loc = getToken().getLoc();
4407 if (parseId(
id,
"expected static reference expression") ||
4408 moduleContext.lookupSymbolEntry(symtabEntry,
id, loc))
4413 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc,
false)) {
4414 if (parseOptionalExpPostscript(lhs,
false) ||
4415 parseOptionalInfo())
4418 locationProcessor.setLoc(startTok.getLoc());
4419 emitInvalidate(lhs);
4426 assert(isa<UnbundledID>(symtabEntry) &&
"should be an instance");
4428 if (getToken().isNot(FIRToken::period)) {
4429 locationProcessor.setLoc(loc);
4431 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4433 for (
auto elt : ubEntry)
4434 emitInvalidate(elt.second);
4440 StringRef fieldName;
4441 if (parseToken(FIRToken::period,
"expected '.' in field reference") ||
4442 parseFieldId(fieldName,
"expected field name") ||
4443 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4447 if (parseOptionalExpPostscript(lhs,
false) ||
4448 parseOptionalInfo())
4451 locationProcessor.setLoc(startTok.getLoc());
4452 emitInvalidate(lhs);
4456ParseResult FIRStmtParser::parseLayerBlockOrGroup(
unsigned indent) {
4458 auto startTok = consumeToken();
4459 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4460 "consumed an unexpected token");
4461 auto loc = startTok.getLoc();
4464 if (parseId(
id,
"expected layer identifer") ||
4465 parseToken(FIRToken::colon,
"expected ':' at end of layer block") ||
4466 parseOptionalInfo())
4469 locationProcessor.setLoc(loc);
4471 StringRef rootLayer;
4472 SmallVector<FlatSymbolRefAttr> nestedLayers;
4476 rootLayer = layerSym.getRootReference();
4477 auto nestedRefs = layerSym.getNestedReferences();
4478 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4479 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(),
id));
4482 auto layerBlockOp = LayerBlockOp::create(
4484 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4485 layerBlockOp->getRegion(0).push_back(
new Block());
4487 if (getIndentation() > indent)
4488 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4489 layerBlockOp.getLayerName()))
4497ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4498 auto loc = getToken().getLoc();
4501 if (consumeIf(FIRToken::kw_is)) {
4502 if (parseToken(FIRToken::kw_invalid,
"expected 'invalid'") ||
4503 parseOptionalInfo())
4506 if (removedFeature({3, 0, 0},
"'is invalid' statements", loc))
4509 locationProcessor.setLoc(loc);
4510 emitInvalidate(lhs);
4514 if (parseToken(FIRToken::less_equal,
"expected '<=' in statement"))
4517 if (removedFeature({3, 0, 0},
"'<=' connections", loc))
4521 if (parseExp(rhs,
"unexpected token in statement") || parseOptionalInfo())
4524 locationProcessor.setLoc(loc);
4526 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4527 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4528 if (!lhsType || !rhsType)
4529 return emitError(loc,
"cannot connect reference or property types");
4531 if (lhsType.containsReference() || rhsType.containsReference())
4532 return emitError(loc,
"cannot connect types containing references");
4535 return emitError(loc,
"cannot connect non-equivalent type ")
4536 << rhsType <<
" to " << lhsType;
4545ParseResult FIRStmtParser::parseInstance() {
4546 auto startTok = consumeToken(FIRToken::kw_inst);
4550 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4554 StringRef moduleName;
4555 if (parseId(
id,
"expected instance name") ||
4556 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4557 parseId(moduleName,
"expected module name") || parseOptionalInfo())
4560 locationProcessor.setLoc(startTok.getLoc());
4563 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4564 if (!referencedModule)
4567 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4569 auto annotations = getConstants().emptyArrayAttr;
4570 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4572 hw::InnerSymAttr sym = {};
4573 auto result = InstanceOp::create(
4574 builder, referencedModule,
id, NameKindEnum::InterestingName,
4575 annotations.getValue(), portAnnotations,
false,
false, sym);
4581 unbundledValueEntry.reserve(modulePorts.size());
4582 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4583 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4587 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4588 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4589 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4594ParseResult FIRStmtParser::parseInstanceChoice() {
4595 auto startTok = consumeToken(FIRToken::kw_instchoice);
4596 SMLoc loc = startTok.getLoc();
4599 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4606 StringRef defaultModuleName;
4607 StringRef optionGroupName;
4608 if (parseId(
id,
"expected instance name") ||
4609 parseToken(FIRToken::kw_of,
"expected 'of' in instance") ||
4610 parseId(defaultModuleName,
"expected module name") ||
4611 parseToken(FIRToken::comma,
"expected ','") ||
4612 parseId(optionGroupName,
"expected option group name") ||
4613 parseToken(FIRToken::colon,
"expected ':' after instchoice") ||
4614 parseOptionalInfo())
4617 locationProcessor.setLoc(startTok.getLoc());
4621 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4625 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4628 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4630 return emitError(loc,
4631 "use of undefined option group '" + optionGroupName +
"'");
4633 auto baseIndent = getIndentation();
4634 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4635 while (getIndentation() == baseIndent) {
4637 StringRef caseModuleName;
4638 if (parseId(caseId,
"expected a case identifier") ||
4639 parseToken(FIRToken::equal_greater,
4640 "expected '=> in instance choice definition") ||
4641 parseId(caseModuleName,
"expected module name"))
4644 auto caseModule = getReferencedModule(loc, caseModuleName);
4648 for (
const auto &[defaultPort, casePort] :
4649 llvm::zip(modulePorts, caseModule.getPorts())) {
4650 if (defaultPort.name != casePort.name)
4651 return emitError(loc,
"instance case module port '")
4652 << casePort.name.getValue()
4653 <<
"' does not match the default module port '"
4654 << defaultPort.name.getValue() <<
"'";
4655 if (defaultPort.type != casePort.type)
4656 return emitError(loc,
"instance case port '")
4657 << casePort.name.getValue()
4658 <<
"' type does not match the default module port";
4662 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4664 return emitError(loc,
"use of undefined option case '" + caseId +
"'");
4665 caseModules.emplace_back(optionCase, caseModule);
4668 auto annotations = getConstants().emptyArrayAttr;
4669 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4673 auto result = InstanceChoiceOp::create(
4674 builder, defaultModule, caseModules,
id, NameKindEnum::InterestingName,
4675 annotations.getValue(), portAnnotations, sym);
4679 unbundledValueEntry.reserve(modulePorts.size());
4680 for (
size_t i = 0, e = modulePorts.size(); i != e; ++i)
4681 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4683 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4684 auto entryId =
UnbundledID(moduleContext.unbundledValues.size());
4685 return moduleContext.addSymbolEntry(
id, entryId, startTok.getLoc());
4688FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4689 StringRef moduleName) {
4690 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4691 if (!referencedModule) {
4693 "use of undefined module name '" + moduleName +
"' in instance");
4696 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4697 emitError(loc,
"cannot create instance of class '" + moduleName +
4698 "', did you mean object?");
4701 return referencedModule;
4705ParseResult FIRStmtParser::parseObject() {
4706 auto startTok = consumeToken(FIRToken::kw_object);
4710 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4717 StringRef className;
4718 if (parseId(
id,
"expected object name") ||
4719 parseToken(FIRToken::kw_of,
"expected 'of' in object") ||
4720 parseId(className,
"expected class name") || parseOptionalInfo())
4723 locationProcessor.setLoc(startTok.getLoc());
4726 const auto &classMap = getConstants().classMap;
4727 auto lookup = classMap.find(className);
4728 if (lookup == classMap.end())
4729 return emitError(startTok.getLoc(),
"use of undefined class name '" +
4730 className +
"' in object");
4731 auto referencedClass = lookup->getSecond();
4732 auto result = ObjectOp::create(builder, referencedClass,
id);
4733 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4737ParseResult FIRStmtParser::parseCombMem() {
4739 auto startTok = consumeToken(FIRToken::kw_cmem);
4743 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4748 if (parseId(
id,
"expected cmem name") ||
4749 parseToken(FIRToken::colon,
"expected ':' in cmem") ||
4750 parseType(type,
"expected cmem type") || parseOptionalInfo())
4753 locationProcessor.setLoc(startTok.getLoc());
4756 auto vectorType = type_dyn_cast<FVectorType>(type);
4758 return emitError(
"cmem requires vector type");
4760 auto annotations = getConstants().emptyArrayAttr;
4761 StringAttr sym = {};
4762 auto result = CombMemOp::create(
4763 builder, vectorType.getElementType(), vectorType.getNumElements(),
id,
4764 NameKindEnum::InterestingName, annotations, sym);
4765 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4769ParseResult FIRStmtParser::parseSeqMem() {
4771 auto startTok = consumeToken(FIRToken::kw_smem);
4775 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4780 RUWBehavior ruw = RUWBehavior::Undefined;
4782 if (parseId(
id,
"expected smem name") ||
4783 parseToken(FIRToken::colon,
"expected ':' in smem") ||
4787 if (consumeIf(FIRToken::comma)) {
4792 if (parseOptionalInfo()) {
4796 locationProcessor.setLoc(startTok.getLoc());
4799 auto vectorType = type_dyn_cast<FVectorType>(type);
4801 return emitError(
"smem requires vector type");
4803 auto annotations = getConstants().emptyArrayAttr;
4804 StringAttr sym = {};
4805 auto result = SeqMemOp::create(
4806 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4807 id, NameKindEnum::InterestingName, annotations, sym);
4808 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
4820ParseResult FIRStmtParser::parseMem(
unsigned memIndent) {
4821 auto startTok = consumeToken(FIRToken::kw_mem);
4825 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4829 if (parseId(
id,
"expected mem name") ||
4830 parseToken(FIRToken::colon,
"expected ':' in mem") || parseOptionalInfo())
4834 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4835 RUWBehavior ruw = RUWBehavior::Undefined;
4837 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4841 auto nextIndent = getIndentation();
4842 if (!nextIndent || *nextIndent <= memIndent)
4845 auto spelling = getTokenSpelling();
4846 if (parseToken(FIRToken::identifier,
"unexpected token in 'mem'") ||
4847 parseToken(FIRToken::equal_greater,
"expected '=>' in 'mem'"))
4850 if (spelling ==
"data-type") {
4852 return emitError(
"'mem' type specified multiple times"), failure();
4854 if (
parseType(type,
"expected type in data-type declaration"))
4858 if (spelling ==
"depth") {
4859 if (parseIntLit(depth,
"expected integer in depth specification"))
4863 if (spelling ==
"read-latency") {
4864 if (parseIntLit(readLatency,
"expected integer latency"))
4868 if (spelling ==
"write-latency") {
4869 if (parseIntLit(writeLatency,
"expected integer latency"))
4873 if (spelling ==
"read-under-write") {
4874 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4875 FIRToken::kw_undefined))
4876 return emitError(
"expected specifier"), failure();
4878 if (parseOptionalRUW(ruw))
4883 MemOp::PortKind portKind;
4884 if (spelling ==
"reader")
4885 portKind = MemOp::PortKind::Read;
4886 else if (spelling ==
"writer")
4887 portKind = MemOp::PortKind::Write;
4888 else if (spelling ==
"readwriter")
4889 portKind = MemOp::PortKind::ReadWrite;
4891 return emitError(
"unexpected field in 'mem' declaration"), failure();
4894 if (parseId(portName,
"expected port name"))
4896 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4898 return emitError(
"unexpected type, must be base type");
4899 ports.push_back({builder.getStringAttr(portName),
4900 MemOp::getTypeForPort(depth, baseType, portKind)});
4902 while (!getIndentation().has_value()) {
4903 if (parseId(portName,
"expected port name"))
4905 ports.push_back({builder.getStringAttr(portName),
4906 MemOp::getTypeForPort(depth, baseType, portKind)});
4917 llvm::array_pod_sort(ports.begin(), ports.end(),
4918 [](
const std::pair<StringAttr, Type> *lhs,
4919 const std::pair<StringAttr, Type> *rhs) ->
int {
4920 return lhs->first.getValue().compare(
4921 rhs->first.getValue());
4924 auto annotations = getConstants().emptyArrayAttr;
4925 SmallVector<Attribute, 4> resultNames;
4926 SmallVector<Type, 4> resultTypes;
4927 SmallVector<Attribute, 4> resultAnnotations;
4928 for (
auto p : ports) {
4929 resultNames.push_back(p.first);
4930 resultTypes.push_back(p.second);
4931 resultAnnotations.push_back(annotations);
4934 locationProcessor.setLoc(startTok.getLoc());
4936 auto result = MemOp::create(
4937 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4938 builder.getArrayAttr(resultNames),
id, NameKindEnum::InterestingName,
4939 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4940 MemoryInitAttr(), StringAttr());
4943 unbundledValueEntry.reserve(result.getNumResults());
4944 for (
size_t i = 0, e = result.getNumResults(); i != e; ++i)
4945 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4947 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4948 auto entryID =
UnbundledID(moduleContext.unbundledValues.size());
4949 return moduleContext.addSymbolEntry(
id, entryID, startTok.getLoc());
4953ParseResult FIRStmtParser::parseNode() {
4954 auto startTok = consumeToken(FIRToken::kw_node);
4958 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
4963 if (parseId(
id,
"expected node name") ||
4964 parseToken(FIRToken::equal,
"expected '=' in node") ||
4965 parseExp(initializer,
"expected expression for node") ||
4966 parseOptionalInfo())
4969 locationProcessor.setLoc(startTok.getLoc());
4981 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4982 auto initializerBaseType =
4983 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4984 if (type_isa<AnalogType>(initializerType) ||
4985 !(initializerBaseType && initializerBaseType.isPassive())) {
4986 emitError(startTok.getLoc())
4987 <<
"Node cannot be analog and must be passive or passive under a flip "
4988 << initializer.getType();
4992 auto annotations = getConstants().emptyArrayAttr;
4993 StringAttr sym = {};
4995 auto result = NodeOp::create(builder, initializer,
id,
4996 NameKindEnum::InterestingName, annotations, sym);
4997 return moduleContext.addSymbolEntry(
id, result.getResult(),
5002ParseResult FIRStmtParser::parseWire() {
5003 auto startTok = consumeToken(FIRToken::kw_wire);
5007 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5012 if (parseId(
id,
"expected wire name") ||
5013 parseToken(FIRToken::colon,
"expected ':' in wire") ||
5014 parseType(type,
"expected wire type") || parseOptionalInfo())
5017 locationProcessor.setLoc(startTok.getLoc());
5019 auto annotations = getConstants().emptyArrayAttr;
5020 StringAttr sym = {};
5023 auto namekind = isa<PropertyType, RefType>(type)
5024 ? NameKindEnum::DroppableName
5025 : NameKindEnum::InterestingName;
5027 auto result = WireOp::create(builder, type,
id, namekind, annotations, sym);
5028 return moduleContext.addSymbolEntry(
id, result.getResult(),
5042ParseResult FIRStmtParser::parseRegister(
unsigned regIndent) {
5043 auto startTok = consumeToken(FIRToken::kw_reg);
5047 if (
auto isExpr = parseExpWithLeadingKeyword(startTok))
5056 if (parseId(
id,
"expected reg name") ||
5057 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5059 parseToken(FIRToken::comma,
"expected ','") ||
5060 parseExp(clock,
"expected expression for register clock"))
5063 if (!type_isa<FIRRTLBaseType>(type))
5064 return emitError(startTok.getLoc(),
"register must have base type");
5067 Value resetSignal, resetValue;
5068 if (consumeIf(FIRToken::kw_with)) {
5069 if (removedFeature({3, 0, 0},
"'reg with' registers"))
5072 if (parseToken(FIRToken::colon,
"expected ':' in reg"))
5080 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5082 auto indent = getIndentation();
5083 if (!indent || *indent <= regIndent)
5084 if (!hasExtraLParen)
5085 return emitError(
"expected indented reset specifier in reg"), failure();
5087 if (parseToken(FIRToken::kw_reset,
"expected 'reset' in reg") ||
5088 parseToken(FIRToken::equal_greater,
"expected => in reset specifier") ||
5089 parseToken(FIRToken::l_paren,
"expected '(' in reset specifier") ||
5090 parseExp(resetSignal,
"expected expression for reset signal") ||
5091 parseToken(FIRToken::comma,
"expected ','"))
5099 if (getTokenSpelling() ==
id) {
5101 if (parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5103 resetSignal = Value();
5105 if (parseExp(resetValue,
"expected expression for reset value") ||
5106 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5110 if (hasExtraLParen &&
5111 parseToken(FIRToken::r_paren,
"expected ')' in reset specifier"))
5117 if (parseOptionalInfo())
5120 locationProcessor.setLoc(startTok.getLoc());
5122 ArrayAttr annotations = getConstants().emptyArrayAttr;
5124 StringAttr sym = {};
5127 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5128 NameKindEnum::InterestingName, annotations, sym)
5131 result = RegOp::create(builder, type, clock,
id,
5132 NameKindEnum::InterestingName, annotations, sym)
5134 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5142ParseResult FIRStmtParser::parseRegisterWithReset() {
5143 auto startTok = consumeToken(FIRToken::kw_regreset);
5147 Value clock, resetSignal, resetValue;
5149 if (parseId(
id,
"expected reg name") ||
5150 parseToken(FIRToken::colon,
"expected ':' in reg") ||
5152 parseToken(FIRToken::comma,
"expected ','") ||
5153 parseExp(clock,
"expected expression for register clock") ||
5154 parseToken(FIRToken::comma,
"expected ','") ||
5155 parseExp(resetSignal,
"expected expression for register reset") ||
5156 parseToken(FIRToken::comma,
"expected ','") ||
5157 parseExp(resetValue,
"expected expression for register reset value") ||
5158 parseOptionalInfo())
5161 if (!type_isa<FIRRTLBaseType>(type))
5162 return emitError(startTok.getLoc(),
"register must have base type");
5164 locationProcessor.setLoc(startTok.getLoc());
5167 RegResetOp::create(builder, type, clock, resetSignal, resetValue,
id,
5168 NameKindEnum::InterestingName,
5169 getConstants().emptyArrayAttr, StringAttr{})
5172 return moduleContext.addSymbolEntry(
id, result, startTok.getLoc());
5177ParseResult FIRStmtParser::parseContract(
unsigned blockIndent) {
5181 auto startTok = consumeToken(FIRToken::kw_contract);
5184 SmallVector<StringRef> ids;
5185 SmallVector<SMLoc> locs;
5186 SmallVector<Value> values;
5187 SmallVector<Type> types;
5188 if (!consumeIf(FIRToken::colon)) {
5189 auto parseContractId = [&] {
5191 locs.push_back(getToken().
getLoc());
5192 if (parseId(
id,
"expected contract result name"))
5197 auto parseContractValue = [&] {
5199 if (parseExp(value,
"expected expression for contract result"))
5201 values.push_back(value);
5202 types.push_back(value.getType());
5205 if (parseListUntil(FIRToken::equal, parseContractId) ||
5206 parseListUntil(FIRToken::colon, parseContractValue))
5209 if (parseOptionalInfo())
5213 if (ids.size() != values.size())
5214 return emitError(startTok.getLoc())
5215 <<
"contract requires same number of results and expressions; got "
5216 << ids.size() <<
" results and " << values.size()
5217 <<
" expressions instead";
5219 locationProcessor.setLoc(startTok.getLoc());
5223 auto contract = ContractOp::create(builder, types, values);
5224 auto &block = contract.getBody().emplaceBlock();
5228 FIRModuleContext::ContextScope scope(moduleContext, &block);
5229 for (
auto [
id, loc, type] :
llvm::zip(ids, locs, types)) {
5230 auto arg = block.addArgument(type, LocWithInfo(loc,
this).
getLoc());
5231 if (failed(moduleContext.addSymbolEntry(
id, arg, loc)))
5234 if (getIndentation() > blockIndent)
5235 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5240 for (
auto [
id, loc, value, result] :
5241 llvm::zip(ids, locs, values, contract.getResults())) {
5243 moduleContext.removeSymbolEntry(
id);
5244 if (failed(moduleContext.addSymbolEntry(
id, result, loc)))
5257struct FIRCircuitParser :
public FIRParser {
5258 explicit FIRCircuitParser(SharedParserConstants &state,
FIRLexer &lexer,
5260 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5263 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5264 mlir::TimingScope &ts);
5269 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5270 SmallVectorImpl<Attribute> &attrs);
5272 ParseResult parseToplevelDefinition(CircuitOp circuit,
unsigned indent);
5274 ParseResult parseClass(CircuitOp circuit,
unsigned indent);
5275 ParseResult parseDomain(CircuitOp circuit,
unsigned indent);
5276 ParseResult parseExtClass(CircuitOp circuit,
unsigned indent);
5277 ParseResult parseExtModule(CircuitOp circuit,
unsigned indent);
5278 ParseResult parseIntModule(CircuitOp circuit,
unsigned indent);
5279 ParseResult parseModule(CircuitOp circuit,
bool isPublic,
unsigned indent);
5280 ParseResult parseFormal(CircuitOp circuit,
unsigned indent);
5281 ParseResult parseSimulation(CircuitOp circuit,
unsigned indent);
5283 ParseResult parseFormalLike(CircuitOp circuit,
unsigned indent);
5285 ParseResult parseLayerName(SymbolRefAttr &result);
5286 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5287 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5288 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5289 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5290 ParseResult parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5291 ArrayAttr &knownLayers);
5293 ParseResult
parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5294 SmallVectorImpl<SMLoc> &resultPortLocs,
5297 ParseResult parseRefList(ArrayRef<PortInfo> portList,
5298 ArrayAttr &internalPathsResult);
5300 ParseResult skipToModuleEnd(
unsigned indent);
5302 ParseResult parseTypeDecl();
5304 ParseResult parseOptionDecl(CircuitOp circuit);
5306 ParseResult parseLayer(CircuitOp circuit);
5308 ParseResult parseDomains(SmallVectorImpl<Attribute> &domains,
5309 const DenseMap<Attribute, size_t> &nameToIndex);
5311 struct DeferredModuleToParse {
5312 FModuleLike moduleOp;
5313 SmallVector<SMLoc> portLocs;
5318 ParseResult parseModuleBody(
const SymbolTable &circuitSymTbl,
5319 DeferredModuleToParse &deferredModule,
5320 InnerSymFixups &fixups);
5322 SmallVector<DeferredModuleToParse, 0> deferredModules;
5324 SmallVector<InnerSymFixups, 0> moduleFixups;
5328 ModuleOp mlirModule;
5333FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5334 SmallVectorImpl<Attribute> &attrs) {
5336 auto annotations = json::parse(annotationsStr);
5337 if (
auto err = annotations.takeError()) {
5338 handleAllErrors(std::move(err), [&](
const json::ParseError &a) {
5339 auto diag = emitError(loc,
"Failed to parse JSON Annotations");
5340 diag.attachNote() << a.message();
5345 json::Path::Root root;
5346 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5349 auto diag = emitError(loc,
"Invalid/unsupported annotation format");
5350 std::string jsonErrorMessage =
5351 "See inline comments for problem area in JSON:\n";
5352 llvm::raw_string_ostream s(jsonErrorMessage);
5353 root.printErrorContext(annotations.get(), s);
5354 diag.attachNote() << jsonErrorMessage;
5361ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5362 auto *context = getContext();
5363 SmallVector<StringRef> strings;
5366 if (parseId(name,
"expected layer name"))
5368 strings.push_back(name);
5369 }
while (consumeIf(FIRToken::period));
5371 SmallVector<FlatSymbolRefAttr> nested;
5372 nested.reserve(strings.size() - 1);
5373 for (
unsigned i = 1, e = strings.size(); i < e; ++i)
5374 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5376 result = SymbolRefAttr::get(context, strings[0], nested);
5380ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5381 SmallVector<Attribute> enabledLayersBuffer;
5383 auto tokenKind = getToken().getKind();
5385 if (tokenKind == FIRToken::kw_enablelayer) {
5386 if (parseEnableLayerSpec(enabledLayersBuffer))
5394 if (enabledLayersBuffer.size() != 0)
5395 if (requireFeature({4, 0, 0},
"modules with layers enabled"))
5398 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5402ParseResult FIRCircuitParser::parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5403 ArrayAttr &knownLayers) {
5404 SmallVector<Attribute> enabledLayersBuffer;
5405 SmallVector<Attribute> knownLayersBuffer;
5407 auto tokenKind = getToken().getKind();
5409 if (tokenKind == FIRToken::kw_enablelayer) {
5410 if (parseEnableLayerSpec(enabledLayersBuffer))
5415 if (tokenKind == FIRToken::kw_knownlayer) {
5416 if (parseKnownLayerSpec(knownLayersBuffer))
5424 if (enabledLayersBuffer.size() != 0)
5425 if (requireFeature({4, 0, 0},
"extmodules with layers enabled"))
5428 if (knownLayersBuffer.size() != 0)
5429 if (requireFeature(
nextFIRVersion,
"extmodules with known layers"))
5432 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5433 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5438FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5440 SymbolRefAttr layer;
5441 if (parseLayerName(layer))
5443 result.push_back(layer);
5444 }
while (consumeIf(FIRToken::comma));
5449FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5450 consumeToken(FIRToken::kw_enablelayer);
5451 return parseLayerList(result);
5455FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5456 consumeToken(FIRToken::kw_knownlayer);
5457 return parseLayerList(result);
5464FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5465 SmallVectorImpl<SMLoc> &resultPortLocs,
5468 DenseMap<Attribute, size_t> nameToIndex;
5471 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5473 getIndentation() > indent) {
5479 auto backtrackState = getLexer().getCursor();
5481 bool isOutput = getToken().is(FIRToken::kw_output);
5486 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5487 !getToken().isKeyword()) {
5488 backtrackState.restore(getLexer());
5495 if (parseId(name,
"expected port name") ||
5496 parseToken(FIRToken::colon,
"expected ':' in port definition") ||
5497 parseType(type,
"expected a type in port declaration"))
5499 Attribute domainInfoElement;
5500 if (isa<DomainType>(type)) {
5501 StringAttr domainKind;
5502 if (parseToken(FIRToken::kw_of,
"expected 'of' after Domain type port") ||
5503 parseId(domainKind,
"expected domain kind"))
5505 domainInfoElement = FlatSymbolRefAttr::get(domainKind);
5507 SmallVector<Attribute, 4> domains;
5508 if (getToken().is(FIRToken::kw_domains))
5509 if (parseDomains(domains, nameToIndex))
5511 domainInfoElement = ArrayAttr::get(getContext(), domains);
5514 if (
info.parseOptionalInfo())
5517 StringAttr innerSym = {};
5518 resultPorts.push_back(
PortInfo{name,
5524 domainInfoElement});
5525 resultPortLocs.push_back(
info.getFIRLoc());
5526 nameToIndex.insert({name, resultPorts.size() - 1});
5531 for (
auto portAndLoc :
llvm::zip(resultPorts, resultPortLocs)) {
5532 PortInfo &port = std::get<0>(portAndLoc);
5533 auto &entry = portIds[port.
name];
5534 if (!entry.isValid()) {
5535 entry = std::get<1>(portAndLoc);
5539 emitError(std::get<1>(portAndLoc),
5540 "redefinition of name '" + port.
getName() +
"'")
5541 .attachNote(translateLocation(entry))
5542 <<
"previous definition here";
5551ParseResult FIRCircuitParser::parseRefList(ArrayRef<PortInfo> portList,
5552 ArrayAttr &internalPathsResult) {
5553 struct RefStatementInfo {
5555 InternalPathAttr resolvedPath;
5559 SmallVector<RefStatementInfo> refStatements;
5560 SmallPtrSet<StringAttr, 8> seenNames;
5561 SmallPtrSet<StringAttr, 8> seenRefs;
5564 if (getToken().is(FIRToken::kw_ref) &&
5565 (requireFeature({2, 0, 0},
"ref statements") ||
5566 removedFeature({4, 0, 0},
"ref statements")))
5570 while (consumeIf(FIRToken::kw_ref)) {
5571 auto loc = getToken().getLoc();
5575 if (parseId(refName,
"expected ref name"))
5577 if (consumeIf(FIRToken::period) || consumeIf(FIRToken::l_square))
5579 loc,
"ref statements for aggregate elements not yet supported");
5580 if (parseToken(FIRToken::kw_is,
"expected 'is' in ref statement"))
5583 if (!seenRefs.insert(refName).second)
5584 return emitError(loc,
"duplicate ref statement for '" + refName.strref() +
5587 auto kind = getToken().getKind();
5588 if (kind != FIRToken::string)
5589 return emitError(loc,
"expected string in ref statement");
5590 auto resolved = InternalPathAttr::get(
5592 StringAttr::get(getContext(), getToken().getStringValue()));
5593 consumeToken(FIRToken::string);
5595 refStatements.push_back(RefStatementInfo{refName, resolved, loc});
5599 SmallVector<Attribute> internalPaths(portList.size(),
5600 InternalPathAttr::get(getContext()));
5602 llvm::SmallBitVector usedRefs(refStatements.size());
5603 size_t matchedPaths = 0;
5604 for (
auto [idx, port] :
llvm::enumerate(portList)) {
5605 if (!type_isa<RefType>(port.
type))
5611 return mlir::emitError(
5613 "references in ports must be output on extmodule and intmodule");
5615 llvm::find_if(refStatements, [pname = port.
name](
const auto &r) {
5616 return r.refName == pname;
5619 if (refStmtIt == refStatements.end()) {
5620 if (!refStatements.empty())
5621 return mlir::emitError(port.
loc,
"no ref statement found for ref port ")
5626 usedRefs.set(std::distance(refStatements.begin(), refStmtIt));
5627 internalPaths[idx] = refStmtIt->resolvedPath;
5631 if (!refStatements.empty() && matchedPaths != refStatements.size()) {
5632 assert(matchedPaths < refStatements.size());
5634 auto idx = usedRefs.find_first_unset();
5636 return emitError(refStatements[idx].loc,
"unused ref statement");
5640 internalPathsResult = ArrayAttr::get(getContext(), internalPaths);
5646ParseResult FIRCircuitParser::skipToModuleEnd(
unsigned indent) {
5648 switch (getToken().getKind()) {
5652 case FIRToken::error:
5656 case FIRToken::kw_class:
5657 case FIRToken::kw_domain:
5658 case FIRToken::kw_declgroup:
5659 case FIRToken::kw_extclass:
5660 case FIRToken::kw_extmodule:
5661 case FIRToken::kw_intmodule:
5662 case FIRToken::kw_formal:
5663 case FIRToken::kw_module:
5664 case FIRToken::kw_public:
5665 case FIRToken::kw_layer:
5666 case FIRToken::kw_option:
5667 case FIRToken::kw_simulation:
5668 case FIRToken::kw_type:
5672 if (getIndentation() == indent)
5684ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5685 SmallVector<Attribute, 8> parameters;
5686 SmallPtrSet<StringAttr, 8> seen;
5687 while (consumeIf(FIRToken::kw_parameter)) {
5691 if (parseParameter(name, value, loc))
5693 auto typedValue = dyn_cast<TypedAttr>(value);
5695 return emitError(loc)
5696 <<
"invalid value for parameter '" << name.getValue() <<
"'";
5697 if (!seen.insert(name).second)
5698 return emitError(loc,
5699 "redefinition of parameter '" + name.getValue() +
"'");
5700 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5702 resultParameters = ArrayAttr::get(getContext(), parameters);
5707ParseResult FIRCircuitParser::parseClass(CircuitOp circuit,
unsigned indent) {
5709 SmallVector<PortInfo, 8> portList;
5710 SmallVector<SMLoc> portLocs;
5716 consumeToken(FIRToken::kw_class);
5717 if (parseId(name,
"expected class name") ||
5718 parseToken(FIRToken::colon,
"expected ':' in class definition") ||
5722 if (name == circuit.getName())
5723 return mlir::emitError(
info.getLoc(),
5724 "class cannot be the top of a circuit");
5726 for (
auto &portInfo : portList)
5728 return
mlir::emitError(portInfo.loc,
5729 "ports on classes must be properties");
5732 auto builder = circuit.getBodyBuilder();
5733 auto classOp = ClassOp::create(builder,
info.getLoc(), name, portList);
5734 classOp.setPrivate();
5735 deferredModules.emplace_back(
5736 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5739 getConstants().classMap[name.getValue()] = classOp;
5740 return skipToModuleEnd(indent);
5744ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit,
unsigned indent) {
5745 consumeToken(FIRToken::kw_domain);
5749 if (parseId(name,
"domain name") ||
5750 parseToken(FIRToken::colon,
"expected ':' after domain definition") ||
5751 info.parseOptionalInfo())
5754 auto builder = circuit.getBodyBuilder();
5755 DomainOp::create(builder,
info.getLoc(), name)
5757 .push_back(
new Block());
5763ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5766 SmallVector<PortInfo, 8> portList;
5767 SmallVector<SMLoc> portLocs;
5773 consumeToken(FIRToken::kw_extclass);
5774 if (parseId(name,
"expected extclass name") ||
5775 parseToken(FIRToken::colon,
"expected ':' in extclass definition") ||
5779 if (name == circuit.getName())
5780 return mlir::emitError(
info.getLoc(),
5781 "extclass cannot be the top of a circuit");
5783 for (
auto &portInfo : portList)
5785 return
mlir::emitError(portInfo.loc,
5786 "ports on extclasses must be properties");
5789 auto builder = circuit.getBodyBuilder();
5790 auto extClassOp = ExtClassOp::create(builder,
info.getLoc(), name, portList);
5793 getConstants().classMap[name.getValue()] = extClassOp;
5794 return skipToModuleEnd(indent);
5801ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5804 ArrayAttr enabledLayers;
5805 ArrayAttr knownLayers;
5806 SmallVector<PortInfo, 8> portList;
5807 SmallVector<SMLoc> portLocs;
5809 consumeToken(FIRToken::kw_extmodule);
5810 if (parseId(name,
"expected extmodule name") ||
5811 parseExtModuleLayerSpec(enabledLayers, knownLayers) ||
5812 parseToken(FIRToken::colon,
"expected ':' in extmodule definition") ||
5817 if (consumeIf(FIRToken::kw_defname)) {
5818 if (parseToken(FIRToken::equal,
"expected '=' in defname") ||
5819 parseId(defName,
"expected defname name"))
5823 ArrayAttr parameters;
5824 ArrayAttr internalPaths;
5829 for (
auto [pi, loc] :
llvm::zip_equal(portList, portLocs)) {
5830 if (
auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5831 if (ftype.hasUninferredWidth())
5832 return emitError(loc,
"extmodule port must have known width");
5837 auto builder = circuit.getBodyBuilder();
5838 auto isMainModule = (name == circuit.getName());
5840 (isMainModule && getConstants().options.scalarizePublicModules) ||
5841 getConstants().options.scalarizeExtModules
5842 ? Convention::Scalarized
5843 : Convention::Internal;
5844 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5845 auto annotations = ArrayAttr::get(getContext(), {});
5846 auto extModuleOp = FExtModuleOp::create(
5847 builder,
info.getLoc(), name, conventionAttr, portList, knownLayers,
5848 defName, annotations, parameters, internalPaths, enabledLayers);
5849 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5850 : SymbolTable::Visibility::Private;
5851 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5859ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5863 ArrayAttr enabledLayers;
5864 SmallVector<PortInfo, 8> portList;
5865 SmallVector<SMLoc> portLocs;
5867 consumeToken(FIRToken::kw_intmodule);
5868 if (parseId(name,
"expected intmodule name") ||
5869 parseModuleLayerSpec(enabledLayers) ||
5870 parseToken(FIRToken::colon,
"expected ':' in intmodule definition") ||
5872 parseToken(FIRToken::kw_intrinsic,
"expected 'intrinsic'") ||
5873 parseToken(FIRToken::equal,
"expected '=' in intrinsic") ||
5874 parseId(intName,
"expected intrinsic name"))
5877 ArrayAttr parameters;
5878 ArrayAttr internalPaths;
5882 ArrayAttr annotations = getConstants().emptyArrayAttr;
5883 auto builder = circuit.getBodyBuilder();
5884 FIntModuleOp::create(builder,
info.getLoc(), name, portList, intName,
5885 annotations, parameters, internalPaths, enabledLayers)
5891ParseResult FIRCircuitParser::parseModule(CircuitOp circuit,
bool isPublic,
5894 SmallVector<PortInfo, 8> portList;
5895 SmallVector<SMLoc> portLocs;
5896 ArrayAttr enabledLayers;
5897 auto modLoc = getToken().getLoc();
5898 LocWithInfo
info(modLoc,
this);
5899 consumeToken(FIRToken::kw_module);
5900 if (parseId(name,
"expected module name") ||
5901 parseModuleLayerSpec(enabledLayers) ||
5902 parseToken(FIRToken::colon,
"expected ':' in module definition") ||
5907 if (name == circuit.getName()) {
5908 if (!isPublic && removedFeature({4, 0, 0},
"private main modules", modLoc))
5913 if (isPublic && version >=
FIRVersion({4, 0, 0})) {
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,
"public module port must have known width");
5918 if (ftype.hasUninferredReset())
5919 return emitError(loc,
5920 "public module port must have concrete reset type");
5925 ArrayAttr annotations = getConstants().emptyArrayAttr;
5926 auto convention = Convention::Internal;
5927 if (isPublic && getConstants().options.scalarizePublicModules)
5928 convention = Convention::Scalarized;
5929 if (!isPublic && getConstants().options.scalarizeInternalModules)
5930 convention = Convention::Scalarized;
5931 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5932 auto builder = circuit.getBodyBuilder();
5934 FModuleOp::create(builder,
info.getLoc(), name, conventionAttr, portList,
5935 annotations, enabledLayers);
5937 auto visibility = isPublic ? SymbolTable::Visibility::Public
5938 : SymbolTable::Visibility::Private;
5939 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5943 deferredModules.emplace_back(DeferredModuleToParse{
5944 moduleOp, portLocs, getLexer().getCursor(), indent});
5946 if (skipToModuleEnd(indent))
5952ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit,
unsigned indent) {
5953 consumeToken(FIRToken::kw_formal);
5954 return parseFormalLike<FormalOp>(circuit, indent);
5958ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5960 consumeToken(FIRToken::kw_simulation);
5961 return parseFormalLike<SimulationOp>(circuit, indent);
5968ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5970 StringRef id, moduleName;
5973 auto builder = circuit.getBodyBuilder();
5976 if (parseId(
id,
"expected test name") ||
5977 parseToken(FIRToken::kw_of,
"expected 'of' in test") ||
5978 parseId(moduleName,
"expected module name"))
5982 NamedAttrList params;
5983 if (consumeIf(FIRToken::comma)) {
5985 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() !=
"bound")
5986 return emitError(
"expected 'bound' after ','");
5988 if (parseToken(FIRToken::equal,
"expected '=' after 'bound'") ||
5989 parseIntLit(bound,
"expected integer bound after '='"))
5992 return emitError(
"bound must be a positive integer");
5993 if (
info.parseOptionalInfo())
5995 params.set(
"bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5998 if (parseToken(FIRToken::colon,
"expected ':' in test") ||
5999 info.parseOptionalInfo())
6001 while (getIndentation() > indent) {
6002 StringAttr paramName;
6003 Attribute paramValue;
6005 if (parseParameter(paramName, paramValue, paramLoc,
6008 if (params.set(paramName, paramValue))
6009 return emitError(paramLoc,
"redefinition of parameter '" +
6010 paramName.getValue() +
"'");
6014 Op::create(builder,
info.getLoc(),
id, moduleName,
6015 params.getDictionary(getContext()));
6019ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6021 switch (getToken().getKind()) {
6022 case FIRToken::kw_class:
6023 return parseClass(circuit, indent);
6024 case FIRToken::kw_declgroup:
6025 if (requireFeature({3, 2, 0},
"optional groups") ||
6026 removedFeature({3, 3, 0},
"optional groups"))
6028 return parseLayer(circuit);
6029 case FIRToken::kw_domain:
6032 return parseDomain(circuit, indent);
6033 case FIRToken::kw_extclass:
6034 return parseExtClass(circuit, indent);
6035 case FIRToken::kw_extmodule:
6036 return parseExtModule(circuit, indent);
6037 case FIRToken::kw_formal:
6038 if (requireFeature({4, 0, 0},
"formal tests"))
6040 return parseFormal(circuit, indent);
6041 case FIRToken::kw_intmodule:
6042 if (requireFeature({1, 2, 0},
"intrinsic modules") ||
6043 removedFeature({4, 0, 0},
"intrinsic modules"))
6045 return parseIntModule(circuit, indent);
6046 case FIRToken::kw_layer:
6047 if (requireFeature({3, 3, 0},
"layers"))
6049 return parseLayer(circuit);
6050 case FIRToken::kw_module:
6051 return parseModule(circuit,
false, indent);
6052 case FIRToken::kw_public:
6053 if (requireFeature({3, 3, 0},
"public modules"))
6056 if (getToken().getKind() == FIRToken::kw_module)
6057 return parseModule(circuit,
true, indent);
6058 return emitError(getToken().
getLoc(),
"only modules may be public");
6059 case FIRToken::kw_simulation:
6062 return parseSimulation(circuit, indent);
6063 case FIRToken::kw_type:
6064 return parseTypeDecl();
6065 case FIRToken::kw_option:
6068 return parseOptionDecl(circuit);
6070 return emitError(getToken().
getLoc(),
"unknown toplevel definition");
6075ParseResult FIRCircuitParser::parseTypeDecl() {
6079 auto loc = getToken().getLoc();
6081 if (getToken().isKeyword())
6082 return emitError(loc) <<
"cannot use keyword '" << getToken().getSpelling()
6083 <<
"' for type alias name";
6085 if (parseId(
id,
"expected type name") ||
6086 parseToken(FIRToken::equal,
"expected '=' in type decl") ||
6089 auto name = StringAttr::get(type.getContext(),
id);
6092 if (
auto base = type_dyn_cast<FIRRTLBaseType>(type))
6093 type = BaseTypeAliasType::get(name, base);
6096 <<
"type alias for non-base type " << type
6097 <<
" is currently not supported. Type alias is stripped immediately";
6099 if (!getConstants().aliasMap.insert({id, type}).second)
6100 return emitError(loc) <<
"type alias `" << name.getValue()
6101 <<
"` is already defined";
6106ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6109 auto loc = getToken().getLoc();
6112 if (parseId(
id,
"expected an option group name") ||
6113 parseToken(FIRToken::colon,
6114 "expected ':' after option group definition") ||
6115 info.parseOptionalInfo())
6118 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6119 auto optionOp = OptionOp::create(builder,
info.getLoc(),
id);
6120 auto *block =
new Block;
6121 optionOp.getBody().push_back(block);
6122 builder.setInsertionPointToEnd(block);
6124 auto baseIndent = getIndentation();
6126 while (getIndentation() == baseIndent) {
6128 LocWithInfo caseInfo(getToken().
getLoc(),
this);
6129 if (parseId(
id,
"expected an option case ID") ||
6130 caseInfo.parseOptionalInfo())
6133 if (!cases.insert(
id).second)
6134 return emitError(loc)
6135 <<
"duplicate option case definition '" <<
id <<
"'";
6137 OptionCaseOp::create(builder, caseInfo.getLoc(),
id);
6144ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6145 auto baseIndent = getIndentation();
6148 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6151 auto parseOne = [&](
Block *block) -> ParseResult {
6152 auto indent = getIndentation();
6153 StringRef id, convention;
6156 if (parseId(
id,
"expected layer name") ||
6157 parseToken(FIRToken::comma,
"expected ','") ||
6158 parseGetSpelling(convention))
6161 auto layerConvention = symbolizeLayerConvention(convention);
6162 if (!layerConvention) {
6163 emitError() <<
"unknown convention '" << convention
6164 <<
"' (did you misspell it?)";
6167 if (layerConvention == LayerConvention::Inline &&
6168 requireFeature({4, 1, 0},
"inline layers"))
6172 hw::OutputFileAttr outputDir;
6173 if (consumeIf(FIRToken::comma)) {
6174 if (getToken().getKind() == FIRToken::string) {
6175 auto text = getToken().getStringValue();
6177 return emitError() <<
"output directory must not be blank";
6178 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6179 consumeToken(FIRToken::string);
6183 if (parseToken(FIRToken::colon,
"expected ':' after layer definition") ||
6184 info.parseOptionalInfo())
6186 auto builder = OpBuilder::atBlockEnd(block);
6189 LayerOp::create(builder,
info.getLoc(),
id, *layerConvention);
6190 layerOp->getRegion(0).push_back(
new Block());
6192 layerOp->setAttr(
"output_file", outputDir);
6193 layerStack.push_back({indent, layerOp});
6197 if (parseOne(circuit.getBodyBlock()))
6201 while (getIndentation() > baseIndent) {
6202 switch (getToken().getKind()) {
6203 case FIRToken::kw_declgroup:
6204 case FIRToken::kw_layer: {
6207 while (layerStack.back().first >= getIndentation())
6208 layerStack.pop_back();
6209 auto parentLayer = layerStack.back().second;
6210 if (parseOne(&parentLayer.getBody().front()))
6215 return emitError(
"expected 'layer'"), failure();
6223FIRCircuitParser::parseDomains(SmallVectorImpl<Attribute> &domains,
6224 const DenseMap<Attribute, size_t> &nameToIndex) {
6227 if (parseToken(FIRToken::kw_domains,
"expected 'domains'") ||
6228 parseToken(FIRToken::l_square,
"expected '['"))
6231 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6233 auto domainLoc = getToken().getLoc();
6234 if (parseId(domain,
"expected domain name"))
6236 auto indexItr = nameToIndex.find(domain);
6237 if (indexItr == nameToIndex.end()) {
6238 emitError(domainLoc)
6239 <<
"unknown domain name '" << domain.getValue() <<
"'";
6242 return domains.push_back(IntegerAttr::get(
6243 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6254FIRCircuitParser::parseModuleBody(
const SymbolTable &circuitSymTbl,
6255 DeferredModuleToParse &deferredModule,
6256 InnerSymFixups &fixups) {
6257 FModuleLike moduleOp = deferredModule.moduleOp;
6258 auto &body = moduleOp->getRegion(0).front();
6259 auto &portLocs = deferredModule.portLocs;
6263 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6266 deferredModule.lexerCursor.restore(moduleBodyLexer);
6268 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6273 auto portList = moduleOp.getPorts();
6274 auto portArgs = body.getArguments();
6275 for (
auto tuple :
llvm::zip(portList, portLocs, portArgs)) {
6276 PortInfo &port = std::get<0>(tuple);
6277 llvm::SMLoc loc = std::get<1>(tuple);
6278 BlockArgument portArg = std::get<2>(tuple);
6280 if (moduleContext.addSymbolEntry(port.
getName(), portArg, loc))
6284 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6287 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6293 size_t numVerifPrintfs = 0;
6294 std::optional<Location> printfLoc;
6296 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6301 printfLoc = printFOp.getLoc();
6304 if (numVerifPrintfs > 0) {
6306 mlir::emitError(deferredModule.moduleOp.getLoc(),
"module contains ")
6308 <<
" printf-encoded verification operation(s), which are no longer "
6310 diag.attachNote(*printfLoc)
6311 <<
"example printf here, this is now just a printf and nothing more";
6312 diag.attachNote() <<
"For more information, see "
6313 "https://github.com/llvm/circt/issues/6970";
6327ParseResult FIRCircuitParser::parseCircuit(
6328 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6329 mlir::TimingScope &ts) {
6331 auto indent = getIndentation();
6332 if (parseToken(FIRToken::kw_FIRRTL,
"expected 'FIRRTL'"))
6334 if (!indent.has_value())
6335 return emitError(
"'FIRRTL' must be first token on its line");
6336 if (parseToken(FIRToken::kw_version,
"expected version after 'FIRRTL'") ||
6337 parseVersionLit(
"expected version literal"))
6339 indent = getIndentation();
6341 if (!indent.has_value())
6342 return emitError(
"'circuit' must be first token on its line");
6343 unsigned circuitIndent = *indent;
6347 SMLoc inlineAnnotationsLoc;
6348 StringRef inlineAnnotations;
6351 if (parseToken(FIRToken::kw_circuit,
6352 "expected a top-level 'circuit' definition") ||
6353 parseId(name,
"expected circuit name") ||
6354 parseToken(FIRToken::colon,
"expected ':' in circuit definition") ||
6355 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6356 info.parseOptionalInfo())
6360 OpBuilder b(mlirModule.getBodyRegion());
6361 auto circuit = CircuitOp::create(b,
info.getLoc(), name);
6364 auto parseAnnotationTimer = ts.nest(
"Parse annotations");
6370 SmallVector<Attribute> annos;
6371 if (!inlineAnnotations.empty())
6372 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6376 for (
auto *annotationsBuf : annotationsBufs)
6377 if (importAnnotationsRaw(
info.getFIRLoc(), annotationsBuf->getBuffer(),
6381 parseAnnotationTimer.stop();
6389 auto parseTimer = ts.nest(
"Parse modules");
6390 deferredModules.reserve(16);
6394 switch (getToken().getKind()) {
6402 case FIRToken::error:
6406 emitError(
"unexpected token in circuit");
6409 case FIRToken::kw_class:
6410 case FIRToken::kw_declgroup:
6411 case FIRToken::kw_domain:
6412 case FIRToken::kw_extclass:
6413 case FIRToken::kw_extmodule:
6414 case FIRToken::kw_intmodule:
6415 case FIRToken::kw_layer:
6416 case FIRToken::kw_formal:
6417 case FIRToken::kw_module:
6418 case FIRToken::kw_option:
6419 case FIRToken::kw_public:
6420 case FIRToken::kw_simulation:
6421 case FIRToken::kw_type: {
6422 auto indent = getIndentation();
6423 if (!indent.has_value())
6424 return emitError(
"'module' must be first token on its line"), failure();
6425 unsigned definitionIndent = *indent;
6427 if (definitionIndent <= circuitIndent)
6428 return emitError(
"module should be indented more"), failure();
6430 if (parseToplevelDefinition(circuit, definitionIndent))
6444 (void)getLexer().translateLocation(
info.getFIRLoc());
6450 DenseMap<Attribute, Location> nameToOrigLoc;
6454 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6459 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6462 .append(
"redefinition of symbol named '", nameAttr.getValue(),
"'")
6463 .attachNote(it.first->second)
6464 .append(
"see existing symbol definition here");
6470 SymbolTable circuitSymTbl(circuit);
6472 moduleFixups.resize(deferredModules.size());
6477 for (
auto &d : deferredModules)
6478 innerSymbolNamespaces.
get(d.moduleOp.getOperation());
6481 auto anyFailed = mlir::failableParallelForEachN(
6482 getContext(), 0, deferredModules.size(), [&](
size_t index) {
6483 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6484 moduleFixups[index]))
6488 if (failed(anyFailed))
6493 for (
auto &fixups : moduleFixups) {
6494 if (failed(fixups.resolve(innerSymbolNamespaces)))
6500 auto parseLayerName = [&](StringRef name) -> Attribute {
6502 auto [head, rest] = name.split(
".");
6503 SmallVector<FlatSymbolRefAttr> nestedRefs;
6504 while (!rest.empty()) {
6506 std::tie(next, rest) = rest.split(
".");
6507 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6509 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6512 auto getArrayAttr = [&](ArrayRef<std::string> strArray,
auto getAttr) {
6513 SmallVector<Attribute> attrArray;
6514 auto *context = getContext();
6515 for (
const auto &str : strArray)
6516 attrArray.push_back(getAttr(str));
6517 if (attrArray.empty())
6519 return ArrayAttr::get(context, attrArray);
6522 if (
auto enableLayers =
6523 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6524 circuit.setEnableLayersAttr(enableLayers);
6525 if (
auto disableLayers =
6526 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6527 circuit.setDisableLayersAttr(disableLayers);
6529 auto getStrAttr = [&](StringRef str) -> Attribute {
6530 return StringAttr::get(getContext(), str);
6533 if (
auto selectInstChoice =
6534 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6535 circuit.setSelectInstChoiceAttr(selectInstChoice);
6537 circuit.setDefaultLayerSpecialization(
6538 getConstants().options.defaultLayerSpecialization);
6551 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6552 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6553 unsigned fileID = 1;
6555 annotationsBufs.push_back(
6556 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6558 context->loadDialect<CHIRRTLDialect>();
6559 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6563 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6566 SharedParserConstants state(context, options);
6567 FIRLexer lexer(sourceMgr, context);
6569 .parseCircuit(annotationsBufs, ts))
6574 auto circuitVerificationTimer = ts.nest(
"Verify circuit");
6575 if (failed(verify(*module)))
6582 static mlir::TranslateToMLIRRegistration fromFIR(
6583 "import-firrtl",
"import .fir",
6584 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6585 mlir::TimingScope ts;
assert(baseType &&"element must be base type")
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > ¶meters)
Parse an parameter list if present.
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Value getValue() const
Get the Value which created this location.
Location getLoc() const
Get the location associated with the value of this field ref.
This is the state captured for a lexer cursor.
This implements a lexer for .fir files.
std::optional< unsigned > getIndentation(const FIRToken &tok) const
Return the indentation level of the specified token or None if this token is preceded by another toke...
This represents a specific token for .fir files.
StringRef getSpelling() const
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
llvm::SMLoc getLoc() const
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
bool isRecognizedPrintfEncodedVerif(PrintFOp printOp)
Classifier for legacy verif intent captured in printf + when's.
constexpr FIRVersion nextFIRVersion(5, 1, 0)
The next version of FIRRTL that is not yet released.
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
InfoLocHandling
Specify how @info locators should be handled.
The FIRRTL specification version.
This holds the name and type that describes the module's ports.
bool isOutput() const
Return true if this is a simple output-only port.
StringRef getName() const