CIRCT 24.0.0git
Loading...
Searching...
No Matches
FIRParser.cpp
Go to the documentation of this file.
1//===- FIRParser.cpp - .fir to FIRRTL dialect parser ----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This implements a .fir file parser.
10//
11//===----------------------------------------------------------------------===//
12
14#include "FIRLexer.h"
24#include "circt/Support/LLVM.h"
25#include "mlir/IR/BuiltinOps.h"
26#include "mlir/IR/BuiltinTypes.h"
27#include "mlir/IR/Diagnostics.h"
28#include "mlir/IR/ImplicitLocOpBuilder.h"
29#include "mlir/IR/PatternMatch.h"
30#include "mlir/IR/Threading.h"
31#include "mlir/IR/Verifier.h"
32#include "mlir/Support/Timing.h"
33#include "mlir/Tools/mlir-translate/Translation.h"
34#include "llvm/ADT/PointerEmbeddedInt.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/SmallPtrSet.h"
37#include "llvm/ADT/StringExtras.h"
38#include "llvm/ADT/StringSet.h"
39#include "llvm/ADT/StringSwitch.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/JSON.h"
42#include "llvm/Support/LogicalResult.h"
43#include "llvm/Support/SourceMgr.h"
44#include "llvm/Support/raw_ostream.h"
45#include <memory>
46#include <utility>
47
48using namespace circt;
49using namespace firrtl;
50using namespace chirrtl;
51
52using llvm::SMLoc;
53using llvm::SourceMgr;
54using mlir::LocationAttr;
55
56namespace json = llvm::json;
57
58//===----------------------------------------------------------------------===//
59// SharedParserConstants
60//===----------------------------------------------------------------------===//
61
62namespace {
63
64/// This class refers to immutable values and annotations maintained globally by
65/// the parser which can be referred to by any active parser, even those running
66/// in parallel. This is shared by all active parsers.
67struct SharedParserConstants {
68 SharedParserConstants(MLIRContext *context, FIRParserOptions options)
69 : context(context), options(options),
70 emptyArrayAttr(ArrayAttr::get(context, {})),
71 loIdentifier(StringAttr::get(context, "lo")),
72 hiIdentifier(StringAttr::get(context, "hi")),
73 amountIdentifier(StringAttr::get(context, "amount")),
74 placeholderInnerRef(
75 hw::InnerRefAttr::get(StringAttr::get(context, "module"),
76 StringAttr::get(context, "placeholder"))) {}
77
78 /// The context we're parsing into.
79 MLIRContext *const context;
80
81 // Options that control the behavior of the parser.
82 const FIRParserOptions options;
83
84 /// A map from identifiers to type aliases.
85 llvm::StringMap<FIRRTLType> aliasMap;
86
87 /// A map from identifiers to class ops.
88 llvm::DenseMap<StringRef, ClassLike> classMap;
89
90 /// A map from identifiers to domain ops.
91 llvm::DenseMap<StringRef, DomainOp> domainMap;
92
93 /// An empty array attribute.
94 const ArrayAttr emptyArrayAttr;
95
96 /// Cached identifiers used in primitives.
97 const StringAttr loIdentifier, hiIdentifier, amountIdentifier;
98
99 /// Cached placeholder inner-ref used until fixed up.
100 const hw::InnerRefAttr placeholderInnerRef;
101
102private:
103 SharedParserConstants(const SharedParserConstants &) = delete;
104 void operator=(const SharedParserConstants &) = delete;
105};
106
107} // end anonymous namespace
108
109//===----------------------------------------------------------------------===//
110// FIRParser
111//===----------------------------------------------------------------------===//
112
113namespace {
114/// This class implements logic common to all levels of the parser, including
115/// things like types and helper logic.
116struct FIRParser {
117 FIRParser(SharedParserConstants &constants, FIRLexer &lexer,
118 FIRVersion version)
119 : version(version), constants(constants), lexer(lexer),
120 locatorFilenameCache(constants.loIdentifier /*arbitrary non-null id*/) {
121 }
122
123 // Helper methods to get stuff from the shared parser constants.
124 SharedParserConstants &getConstants() const { return constants; }
125 MLIRContext *getContext() const { return constants.context; }
126
127 FIRLexer &getLexer() { return lexer; }
128
129 /// Return the indentation level of the specified token.
130 std::optional<unsigned> getIndentation() const {
131 return lexer.getIndentation(getToken());
132 }
133
134 /// Return the current token the parser is inspecting.
135 const FIRToken &getToken() const { return lexer.getToken(); }
136 StringRef getTokenSpelling() const { return getToken().getSpelling(); }
137
138 //===--------------------------------------------------------------------===//
139 // Error Handling
140 //===--------------------------------------------------------------------===//
141
142 /// Emit an error and return failure.
143 InFlightDiagnostic emitError(const Twine &message = {}) {
144 return emitError(getToken().getLoc(), message);
145 }
146 InFlightDiagnostic emitError(SMLoc loc, const Twine &message = {});
147
148 /// Emit a warning.
149 InFlightDiagnostic emitWarning(const Twine &message = {}) {
150 return emitWarning(getToken().getLoc(), message);
151 }
152
153 InFlightDiagnostic emitWarning(SMLoc loc, const Twine &message = {});
154
155 //===--------------------------------------------------------------------===//
156 // Location Handling
157 //===--------------------------------------------------------------------===//
158
159 class LocWithInfo;
160
161 /// Encode the specified source location information into an attribute for
162 /// attachment to the IR.
163 Location translateLocation(llvm::SMLoc loc) {
164 return lexer.translateLocation(loc);
165 }
166
167 /// Parse an @info marker if present. If so, fill in the specified Location,
168 /// if not, ignore it.
169 ParseResult parseOptionalInfoLocator(LocationAttr &result);
170
171 /// Parse an optional name that may appear in Stop, Printf, or Verification
172 /// statements.
173 ParseResult parseOptionalName(StringAttr &name);
174
175 //===--------------------------------------------------------------------===//
176 // Version and Feature Checking
177 //===--------------------------------------------------------------------===//
178
179 ParseResult requireFeature(FIRVersion minimum, StringRef feature) {
180 return requireFeature(minimum, feature, getToken().getLoc());
181 }
182
183 ParseResult requireFeature(FIRVersion minimum, StringRef feature, SMLoc loc) {
184 if (version < minimum)
185 return emitError(loc)
186 << feature << " are a FIRRTL " << minimum
187 << "+ feature, but the specified FIRRTL version was " << version;
188 return success();
189 }
190
191 ParseResult removedFeature(FIRVersion removedVersion, StringRef feature) {
192 return removedFeature(removedVersion, feature, getToken().getLoc());
193 }
194
195 ParseResult removedFeature(FIRVersion removedVersion, StringRef feature,
196 SMLoc loc) {
197 if (version >= removedVersion)
198 return emitError(loc)
199 << feature << " were removed in FIRRTL " << removedVersion
200 << ", but the specified FIRRTL version was " << version;
201 return success();
202 }
203
204 //===--------------------------------------------------------------------===//
205 // Annotation Parsing
206 //===--------------------------------------------------------------------===//
207
208 /// Parse a non-standard inline Annotation JSON blob if present. This uses
209 /// the info-like encoding of %[<JSON Blob>].
210 ParseResult parseOptionalAnnotations(SMLoc &loc, StringRef &result);
211
212 //===--------------------------------------------------------------------===//
213 // Token Parsing
214 //===--------------------------------------------------------------------===//
215
216 /// If the current token has the specified kind, consume it and return true.
217 /// If not, return false.
218 bool consumeIf(FIRToken::Kind kind) {
219 if (getToken().isNot(kind))
220 return false;
221 consumeToken(kind);
222 return true;
223 }
224
225 /// Advance the current lexer onto the next token.
226 ///
227 /// This returns the consumed token.
228 FIRToken consumeToken() {
229 FIRToken consumedToken = getToken();
230 assert(consumedToken.isNot(FIRToken::eof, FIRToken::error) &&
231 "shouldn't advance past EOF or errors");
232 lexer.lexToken();
233 return consumedToken;
234 }
235
236 /// Advance the current lexer onto the next token, asserting what the expected
237 /// current token is. This is preferred to the above method because it leads
238 /// to more self-documenting code with better checking.
239 ///
240 /// This returns the consumed token.
241 FIRToken consumeToken(FIRToken::Kind kind) {
242 FIRToken consumedToken = getToken();
243 assert(consumedToken.is(kind) && "consumed an unexpected token");
244 consumeToken();
245 return consumedToken;
246 }
247
248 /// Capture the current token's spelling into the specified value. This
249 /// always succeeds.
250 ParseResult parseGetSpelling(StringRef &spelling) {
251 spelling = getTokenSpelling();
252 return success();
253 }
254
255 /// Consume the specified token if present and return success. On failure,
256 /// output a diagnostic and return failure.
257 ParseResult parseToken(FIRToken::Kind expectedToken, const Twine &message);
258
259 /// Parse a comma-separated list of elements, terminated with an arbitrary
260 /// token.
261 ParseResult parseListUntil(FIRToken::Kind rightToken,
262 const std::function<ParseResult()> &parseElement);
263
264 //===--------------------------------------------------------------------===//
265 // Common Parser Rules
266 //===--------------------------------------------------------------------===//
267
268 /// Parse 'intLit' into the specified value.
269 ParseResult parseIntLit(APInt &result, const Twine &message);
270 ParseResult parseIntLit(int64_t &result, const Twine &message);
271 ParseResult parseIntLit(int32_t &result, const Twine &message);
272
273 // Parse 'verLit' into specified value
274 ParseResult parseVersionLit(const Twine &message);
275
276 // Parse 'intLit' '>' assuming '<' was already consumed.
277 ParseResult parseWidth(int32_t &result);
278
279 // Parse the 'id' grammar, which is an identifier or an allowed keyword.
280 ParseResult parseId(StringRef &result, const Twine &message);
281 ParseResult parseId(StringAttr &result, const Twine &message);
282 ParseResult parseFieldId(StringRef &result, const Twine &message);
283 ParseResult parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
284 const Twine &message);
285 ParseResult parseEnumType(FIRRTLType &result);
286 ParseResult parseListType(FIRRTLType &result);
287 ParseResult parseRegistryType(FIRRTLType &result);
288 ParseResult parseType(FIRRTLType &result, const Twine &message);
289 // Parse a property type specifically.
290 ParseResult parsePropertyType(PropertyType &result, const Twine &message);
291
292 ParseResult parseRUW(RUWBehavior &result);
293 ParseResult parseOptionalRUW(RUWBehavior &result);
294
295 ParseResult parseParameter(StringAttr &resultName, Attribute &resultValue,
296 SMLoc &resultLoc, bool allowAggregates = false);
297 ParseResult parseParameterValue(Attribute &resultValue,
298 bool allowAggregates = false);
299
300 /// The version of FIRRTL to use for this parser.
301 FIRVersion version;
302
303private:
304 FIRParser(const FIRParser &) = delete;
305 void operator=(const FIRParser &) = delete;
306
307 /// FIRParser is subclassed and reinstantiated. Do not add additional
308 /// non-trivial state here, add it to SharedParserConstants.
309 SharedParserConstants &constants;
310 FIRLexer &lexer;
311
312 /// This is a single-entry cache for filenames in locators.
313 StringAttr locatorFilenameCache;
314 /// This is a single-entry cache for FileLineCol locations.
315 FileLineColLoc fileLineColLocCache;
316};
317
318} // end anonymous namespace
319
320//===----------------------------------------------------------------------===//
321// Error Handling
322//===----------------------------------------------------------------------===//
323
324InFlightDiagnostic FIRParser::emitError(SMLoc loc, const Twine &message) {
325 auto diag = mlir::emitError(translateLocation(loc), message);
326
327 // If we hit a parse error in response to a lexer error, then the lexer
328 // already reported the error.
329 if (getToken().is(FIRToken::error))
330 diag.abandon();
331 return diag;
332}
333
334InFlightDiagnostic FIRParser::emitWarning(SMLoc loc, const Twine &message) {
335 return mlir::emitWarning(translateLocation(loc), message);
336}
337
338//===----------------------------------------------------------------------===//
339// Token Parsing
340//===----------------------------------------------------------------------===//
341
342/// Consume the specified token if present and return success. On failure,
343/// output a diagnostic and return failure.
344ParseResult FIRParser::parseToken(FIRToken::Kind expectedToken,
345 const Twine &message) {
346 if (consumeIf(expectedToken))
347 return success();
348 return emitError(message);
349}
350
351/// Parse a comma-separated list of zero or more elements, terminated with an
352/// arbitrary token.
353ParseResult
354FIRParser::parseListUntil(FIRToken::Kind rightToken,
355 const std::function<ParseResult()> &parseElement) {
356 if (consumeIf(rightToken))
357 return success();
358
359 if (parseElement())
360 return failure();
361
362 while (consumeIf(FIRToken::comma)) {
363 if (parseElement())
364 return failure();
365 }
366
367 if (parseToken(rightToken, "expected ','"))
368 return failure();
369
370 return success();
371}
372
373//===--------------------------------------------------------------------===//
374// Location Processing
375//===--------------------------------------------------------------------===//
376
377/// This helper class is used to handle Info records, which specify higher level
378/// symbolic source location, that may be missing from the file. If the higher
379/// level source information is missing, we fall back to the location in the
380/// .fir file.
382public:
383 explicit LocWithInfo(SMLoc firLoc, FIRParser *parser)
384 : parser(parser), firLoc(firLoc) {}
385
386 SMLoc getFIRLoc() const { return firLoc; }
387
388 Location getLoc() {
389 if (infoLoc)
390 return *infoLoc;
391 auto result = parser->translateLocation(firLoc);
392 infoLoc = result;
393 return result;
394 }
395
396 /// Parse an @info marker if present and update our location.
397 ParseResult parseOptionalInfo() {
398 LocationAttr loc;
399 if (failed(parser->parseOptionalInfoLocator(loc)))
400 return failure();
401 if (loc) {
403 switch (parser->constants.options.infoLocatorHandling) {
404 case ILH::IgnoreInfo:
405 assert(0 && "Should not return info locations if ignoring");
406 break;
407 case ILH::PreferInfo:
408 infoLoc = loc;
409 break;
410 case ILH::FusedInfo:
411 infoLoc = FusedLoc::get(loc.getContext(),
412 {loc, parser->translateLocation(firLoc)});
413 break;
414 }
415 }
416 return success();
417 }
418
419 /// If we didn't parse an info locator for the specified value, this sets a
420 /// default, overriding a fall back to a location in the .fir file.
421 void setDefaultLoc(Location loc) {
422 if (!infoLoc)
423 infoLoc = loc;
424 }
425
426private:
427 FIRParser *const parser;
428
429 /// This is the designated location in the .fir file for use when there is no
430 /// @ info marker.
431 SMLoc firLoc;
432
433 /// This is the location specified by the @ marker if present.
434 std::optional<Location> infoLoc;
435};
436
437/// Parse an @info marker if present. If so, fill in the specified Location,
438/// if not, ignore it.
439ParseResult FIRParser::parseOptionalInfoLocator(LocationAttr &result) {
440 if (getToken().isNot(FIRToken::fileinfo))
441 return success();
442
443 auto loc = getToken().getLoc();
444
445 auto spelling = getTokenSpelling();
446 consumeToken(FIRToken::fileinfo);
447
448 auto locationPair = maybeStringToLocation(
449 spelling,
450 constants.options.infoLocatorHandling ==
452 locatorFilenameCache, fileLineColLocCache, getContext());
453
454 // If parsing failed, then indicate that a weird info was found.
455 if (!locationPair.first) {
456 mlir::emitWarning(translateLocation(loc),
457 "ignoring unknown @ info record format");
458 return success();
459 }
460
461 // If the parsing succeeded, but we are supposed to drop locators, then just
462 // return.
463 if (locationPair.first && constants.options.infoLocatorHandling ==
464 FIRParserOptions::InfoLocHandling::IgnoreInfo)
465 return success();
466
467 // Otherwise, set the location attribute and return.
468 result = *locationPair.second;
469 return success();
470}
471
472/// Parse an optional trailing name that may show up on assert, assume, cover,
473/// stop, or printf.
474///
475/// optional_name ::= ( ':' id )?
476ParseResult FIRParser::parseOptionalName(StringAttr &name) {
477
478 if (getToken().isNot(FIRToken::colon)) {
479 name = StringAttr::get(getContext(), "");
480 return success();
481 }
482
483 consumeToken(FIRToken::colon);
484 StringRef nameRef;
485 if (parseId(nameRef, "expected result name"))
486 return failure();
487
488 name = StringAttr::get(getContext(), nameRef);
489
490 return success();
491}
492
493//===--------------------------------------------------------------------===//
494// Annotation Handling
495//===--------------------------------------------------------------------===//
496
497/// Parse a non-standard inline Annotation JSON blob if present. This uses
498/// the info-like encoding of %[<JSON Blob>].
499ParseResult FIRParser::parseOptionalAnnotations(SMLoc &loc, StringRef &result) {
500
501 if (getToken().isNot(FIRToken::inlineannotation))
502 return success();
503
504 loc = getToken().getLoc();
505
506 result = getTokenSpelling().drop_front(2).drop_back(1);
507 consumeToken(FIRToken::inlineannotation);
508
509 return success();
510}
511
512//===--------------------------------------------------------------------===//
513// Common Parser Rules
514//===--------------------------------------------------------------------===//
515
516/// intLit ::= UnsignedInt
517/// ::= SignedInt
518/// ::= HexLit
519/// ::= OctalLit
520/// ::= BinaryLit
521/// HexLit ::= '"' 'h' ( '+' | '-' )? ( HexDigit )+ '"'
522/// OctalLit ::= '"' 'o' ( '+' | '-' )? ( OctalDigit )+ '"'
523/// BinaryLit ::= '"' 'b' ( '+' | '-' )? ( BinaryDigit )+ '"'
524///
525ParseResult FIRParser::parseIntLit(APInt &result, const Twine &message) {
526 auto spelling = getTokenSpelling();
527 bool isNegative = false;
528 switch (getToken().getKind()) {
529 case FIRToken::signed_integer:
530 isNegative = spelling[0] == '-';
531 assert(spelling[0] == '+' || spelling[0] == '-');
532 spelling = spelling.drop_front();
533 [[fallthrough]];
534 case FIRToken::integer:
535 if (spelling.getAsInteger(10, result))
536 return emitError(message), failure();
537
538 // Make sure that the returned APInt has a zero at the top so clients don't
539 // confuse it with a negative number.
540 if (result.isNegative())
541 result = result.zext(result.getBitWidth() + 1);
542
543 if (isNegative)
544 result = -result;
545
546 // If this was parsed as >32 bits, but can be represented in 32 bits,
547 // truncate off the extra width. This is important for extmodules which
548 // like parameters to be 32-bits, and insulates us from some arbitraryness
549 // in StringRef::getAsInteger.
550 if (result.getBitWidth() > 32 && result.getSignificantBits() <= 32)
551 result = result.trunc(32);
552
553 consumeToken();
554 return success();
555 case FIRToken::radix_specified_integer: {
556 if (requireFeature({2, 4, 0}, "radix-specified integer literals"))
557 return failure();
558 if (spelling[0] == '-') {
559 isNegative = true;
560 spelling = spelling.drop_front();
561 }
562 unsigned base = llvm::StringSwitch<unsigned>(spelling.take_front(2))
563 .Case("0b", 2)
564 .Case("0o", 8)
565 .Case("0d", 10)
566 .Case("0h", 16);
567 spelling = spelling.drop_front(2);
568 if (spelling.getAsInteger(base, result))
569 return emitError("invalid character in integer literal"), failure();
570 if (result.isNegative())
571 result = result.zext(result.getBitWidth() + 1);
572 if (isNegative)
573 result = -result;
574 consumeToken();
575 return success();
576 }
577 case FIRToken::string: {
578 if (FIRVersion(3, 0, 0) <= version)
579 return emitError(
580 "String-encoded integer literals are unsupported after FIRRTL 3.0.0");
581
582 // Drop the quotes.
583 assert(spelling.front() == '"' && spelling.back() == '"');
584 spelling = spelling.drop_back().drop_front();
585
586 // Decode the base.
587 unsigned base;
588 switch (spelling.empty() ? ' ' : spelling.front()) {
589 case 'h':
590 base = 16;
591 break;
592 case 'o':
593 base = 8;
594 break;
595 case 'b':
596 base = 2;
597 break;
598 default:
599 return emitError("expected base specifier (h/o/b) in integer literal"),
600 failure();
601 }
602 spelling = spelling.drop_front();
603
604 // Handle the optional sign.
605 bool isNegative = false;
606 if (!spelling.empty() && spelling.front() == '+')
607 spelling = spelling.drop_front();
608 else if (!spelling.empty() && spelling.front() == '-') {
609 isNegative = true;
610 spelling = spelling.drop_front();
611 }
612
613 // Parse the digits.
614 if (spelling.empty())
615 return emitError("expected digits in integer literal"), failure();
616
617 if (spelling.getAsInteger(base, result))
618 return emitError("invalid character in integer literal"), failure();
619
620 // We just parsed the positive version of this number. Make sure it has
621 // a zero at the top so clients don't confuse it with a negative number and
622 // so the negation (in the case of a negative sign) doesn't overflow.
623 if (result.isNegative())
624 result = result.zext(result.getBitWidth() + 1);
625
626 if (isNegative)
627 result = -result;
628
629 consumeToken(FIRToken::string);
630 return success();
631 }
632
633 default:
634 return emitError("expected integer literal"), failure();
635 }
636}
637
638ParseResult FIRParser::parseIntLit(int64_t &result, const Twine &message) {
639 APInt value;
640 auto loc = getToken().getLoc();
641 if (parseIntLit(value, message))
642 return failure();
643
644 result = (int64_t)value.getLimitedValue(INT64_MAX);
645 if (result != value)
646 return emitError(loc, "value is too big to handle"), failure();
647 return success();
648}
649
650ParseResult FIRParser::parseIntLit(int32_t &result, const Twine &message) {
651 APInt value;
652 auto loc = getToken().getLoc();
653 if (parseIntLit(value, message))
654 return failure();
655
656 result = (int32_t)value.getLimitedValue(INT32_MAX);
657 if (result != value)
658 return emitError(loc, "value is too big to handle"), failure();
659 return success();
660}
661
662/// versionLit ::= version
663/// deconstruct a version literal into parts and returns those.
664ParseResult FIRParser::parseVersionLit(const Twine &message) {
665 auto spelling = getTokenSpelling();
666 if (getToken().getKind() != FIRToken::version)
667 return emitError(message), failure();
668 auto ver = FIRVersion::fromString(spelling);
669 if (!ver)
670 return emitError("failed to parse version string"), failure();
671 version = *ver;
672 if (version < minimumFIRVersion)
673 return emitError() << "FIRRTL version must be >=" << minimumFIRVersion,
674 failure();
675 consumeToken(FIRToken::version);
676 return success();
677}
678
679/// Parse a width specifier: intLit '>'
680/// This is used when the '<' has already been consumed.
681ParseResult FIRParser::parseWidth(int32_t &result) {
682 auto widthLoc = getToken().getLoc();
683 if (parseIntLit(result, "expected width") ||
684 parseToken(FIRToken::greater, "expected '>'"))
685 return failure();
686 if (result < 0)
687 return emitError(widthLoc, "invalid width specifier"), failure();
688 return success();
689}
690
691/// id ::= Id | keywordAsId
692///
693/// Parse the 'id' grammar, which is an identifier or an allowed keyword. On
694/// success, this returns the identifier in the result attribute.
695ParseResult FIRParser::parseId(StringRef &result, const Twine &message) {
696 switch (getToken().getKind()) {
697 // The most common case is an identifier.
698 case FIRToken::identifier:
699 case FIRToken::literal_identifier:
700// Otherwise it may be a keyword that we're allowing in an id position.
701#define TOK_KEYWORD(spelling) case FIRToken::kw_##spelling:
702#include "FIRTokenKinds.def"
703
704 // Yep, this is a valid identifier or literal identifier. Turn it into an
705 // attribute. If it is a literal identifier, then drop the leading and
706 // trailing '`' (backticks).
707 if (getToken().getKind() == FIRToken::literal_identifier)
708 result = getTokenSpelling().drop_front().drop_back();
709 else
710 result = getTokenSpelling();
711 consumeToken();
712 return success();
713
714 default:
715 emitError(message);
716 return failure();
717 }
718}
719
720ParseResult FIRParser::parseId(StringAttr &result, const Twine &message) {
721 StringRef name;
722 if (parseId(name, message))
723 return failure();
724
725 result = StringAttr::get(getContext(), name);
726 return success();
727}
728
729/// fieldId ::= Id
730/// ::= RelaxedId
731/// ::= UnsignedInt
732/// ::= keywordAsId
733///
734ParseResult FIRParser::parseFieldId(StringRef &result, const Twine &message) {
735 // Handle the UnsignedInt case.
736 result = getTokenSpelling();
737 if (consumeIf(FIRToken::integer))
738 return success();
739
740 // FIXME: Handle RelaxedId
741
742 // Otherwise, it must be Id or keywordAsId.
743 if (parseId(result, message))
744 return failure();
745
746 return success();
747}
748
749/// fieldId ::= Id
750/// ::= Float
751/// ::= version
752/// ::= UnsignedInt
753/// ::= keywordAsId
754///
755ParseResult FIRParser::parseFieldIdSeq(SmallVectorImpl<StringRef> &result,
756 const Twine &message) {
757 // Handle the UnsignedInt case.
758 StringRef tmp = getTokenSpelling();
759
760 if (consumeIf(FIRToken::integer)) {
761 result.push_back(tmp);
762 return success();
763 }
764
765 if (consumeIf(FIRToken::floatingpoint)) {
766 // form a.b
767 // Both a and b could have more floating point stuff, but just ignore that
768 // for now.
769 auto [a, b] = tmp.split(".");
770 result.push_back(a);
771 result.push_back(b);
772 return success();
773 }
774
775 if (consumeIf(FIRToken::version)) {
776 // form a.b.c
777 auto [a, d] = tmp.split(".");
778 auto [b, c] = d.split(".");
779 result.push_back(a);
780 result.push_back(b);
781 result.push_back(c);
782 return success();
783 }
784
785 // Otherwise, it must be Id or keywordAsId.
786 if (parseId(tmp, message))
787 return failure();
788 result.push_back(tmp);
789 return success();
790}
791
792/// enum-field ::= Id ( '=' int )? ( ':' type )? ;
793/// enum-type ::= '{|' enum-field* '|}'
794ParseResult FIRParser::parseEnumType(FIRRTLType &result) {
795 if (parseToken(FIRToken::l_brace_bar,
796 "expected leading '{|' in enumeration type"))
797 return failure();
798 SmallVector<StringAttr> names;
799 SmallVector<APInt> values;
800 SmallVector<FIRRTLBaseType> types;
801 SmallVector<SMLoc> locs;
802 if (parseListUntil(FIRToken::r_brace_bar, [&]() -> ParseResult {
803 auto fieldLoc = getToken().getLoc();
804 locs.push_back(fieldLoc);
805
806 // Parse the name of the tag.
807 StringRef nameStr;
808 if (parseId(nameStr, "expected valid identifier for enumeration tag"))
809 return failure();
810 auto name = StringAttr::get(getContext(), nameStr);
811 names.push_back(name);
812
813 // Parse the integer value if it exists. If its the first element of the
814 // enum, it implicitly has a value of 0, otherwise it has the previous
815 // value + 1.
816 APInt value;
817 if (consumeIf(FIRToken::equal)) {
818 if (parseIntLit(value, "expected integer value for enumeration tag"))
819 return failure();
820 if (value.isNegative())
821 return emitError(fieldLoc, "enum tag value must be non-negative");
822 } else if (values.empty()) {
823 // This is the first enum variant, so it defaults to 0.
824 value = APInt(1, 0);
825 } else {
826 // This value is not specified, so it defaults to the previous value
827 // + 1.
828 auto &prev = values.back();
829 if (prev.isMaxValue())
830 value = prev.zext(prev.getBitWidth() + 1);
831 else
832 value = prev;
833 ++value;
834 }
835 values.push_back(std::move(value));
836
837 // Parse an optional type ascription.
838 FIRRTLBaseType type;
839 if (consumeIf(FIRToken::colon)) {
840 FIRRTLType parsedType;
841 if (parseType(parsedType, "expected enumeration type"))
842 return failure();
843 type = type_dyn_cast<FIRRTLBaseType>(parsedType);
844 if (!type)
845 return emitError(fieldLoc, "field must be a base type");
846 } else {
847 // If there is no type specified, default to UInt<0>.
848 type = UIntType::get(getContext(), 0);
849 }
850 types.push_back(type);
851
852 auto r = type.getRecursiveTypeProperties();
853 if (!r.isPassive)
854 return emitError(fieldLoc) << "enum field " << name << " not passive";
855 if (r.containsAnalog)
856 return emitError(fieldLoc)
857 << "enum field " << name << " contains analog";
858 if (r.hasUninferredWidth)
859 return emitError(fieldLoc)
860 << "enum field " << name << " has uninferred width";
861 if (r.hasUninferredReset)
862 return emitError(fieldLoc)
863 << "enum field " << name << " has uninferred reset";
864 return success();
865 }))
866 return failure();
867
868 // Verify that the names of each variant are unique.
869 SmallPtrSet<StringAttr, 4> nameSet;
870 for (auto [name, loc] : llvm::zip(names, locs))
871 if (!nameSet.insert(name).second)
872 return emitError(loc,
873 "duplicate variant name in enum: " + name.getValue());
874
875 // Find the bitwidth of the enum.
876 unsigned bitwidth = 0;
877 for (auto &value : values)
878 bitwidth = std::max(bitwidth, value.getActiveBits());
879 auto tagType =
880 IntegerType::get(getContext(), bitwidth, IntegerType::Unsigned);
881
882 // Extend all tag values to the same width, and check that they are all
883 // unique.
884 SmallPtrSet<IntegerAttr, 4> valueSet;
885 SmallVector<FEnumType::EnumElement, 4> elements;
886 for (auto [name, value, type, loc] : llvm::zip(names, values, types, locs)) {
887 auto tagValue = value.zextOrTrunc(bitwidth);
888 auto attr = IntegerAttr::get(tagType, tagValue);
889 // Verify that the names of each variant are unique.
890 if (!valueSet.insert(attr).second)
891 return emitError(loc, "duplicate variant value in enum: ") << attr;
892 elements.push_back({name, attr, type});
893 }
894
895 llvm::sort(elements);
896 result = FEnumType::get(getContext(), elements);
897 return success();
898}
899
900ParseResult FIRParser::parsePropertyType(PropertyType &result,
901 const Twine &message) {
902 auto loc = getToken().getLoc();
903
904 FIRRTLType type;
905 if (parseType(type, message))
906 return failure();
907 auto prop = type_dyn_cast<PropertyType>(type);
908 if (!prop)
909 return emitError(loc, "expected property type");
910 result = prop;
911 return success();
912}
913
914/// list-type ::= 'List' '<' type '>'
915ParseResult FIRParser::parseListType(FIRRTLType &result) {
916 consumeToken(FIRToken::kw_List);
917
918 PropertyType elementType;
919 if (parseToken(FIRToken::less, "expected '<' in List type") ||
920 parsePropertyType(elementType, "expected List element type") ||
921 parseToken(FIRToken::greater, "expected '>' in List type"))
922 return failure();
923
924 result = ListType::get(getContext(), elementType);
925 return success();
926}
927
928/// registry-type ::= 'Registry' '<' type '>'
929ParseResult FIRParser::parseRegistryType(FIRRTLType &result) {
930 consumeToken(FIRToken::kw_Registry);
931
932 PropertyType elementType;
933 if (parseToken(FIRToken::less, "expected '<' in Registry type") ||
934 parsePropertyType(elementType, "expected Registry element type") ||
935 parseToken(FIRToken::greater, "expected '>' in Registry type"))
936 return failure();
937
938 result = RegistryType::get(getContext(), elementType);
939 return success();
940}
941
942/// type ::= 'Clock'
943/// ::= 'Reset'
944/// ::= 'AsyncReset'
945/// ::= 'UInt' optional-width
946/// ::= 'SInt' optional-width
947/// ::= 'Analog' optional-width
948/// ::= 'Domain'
949/// ::= {' field* '}'
950/// ::= type '[' intLit ']'
951/// ::= 'Probe' '<' type '>'
952/// ::= 'RWProbe' '<' type '>'
953/// ::= 'const' type
954/// ::= 'String'
955/// ::= list-type
956/// ::= registry-type
957/// ::= id
958///
959/// field: 'flip'? fieldId ':' type
960///
961// NOLINTNEXTLINE(misc-no-recursion)
962ParseResult FIRParser::parseType(FIRRTLType &result, const Twine &message) {
963 auto typeLoc = getToken().getLoc();
964 switch (getToken().getKind()) {
965 default:
966 return emitError(message), failure();
967
968 case FIRToken::kw_Clock:
969 consumeToken(FIRToken::kw_Clock);
970 result = ClockType::get(getContext());
971 break;
972
973 case FIRToken::kw_Inst: {
974 if (requireFeature({6, 0, 0}, "Inst types"))
975 return failure();
976
977 consumeToken(FIRToken::kw_Inst);
978 if (parseToken(FIRToken::less, "expected < in Inst type"))
979 return failure();
980
981 auto loc = getToken().getLoc();
982 StringRef id;
983 if (parseId(id, "expected class name in Inst type"))
984 return failure();
985
986 // Look up the class that is being referenced.
987 const auto &classMap = getConstants().classMap;
988 auto lookup = classMap.find(id);
989 if (lookup == classMap.end())
990 return emitError(loc) << "unknown class '" << id << "'";
991
992 auto classOp = lookup->second;
993
994 if (parseToken(FIRToken::greater, "expected > in Inst type"))
995 return failure();
996
997 result = classOp.getInstanceType();
998 break;
999 }
1000
1001 case FIRToken::kw_AnyRef: {
1002 if (requireFeature({6, 0, 0}, "AnyRef types"))
1003 return failure();
1004
1005 consumeToken(FIRToken::kw_AnyRef);
1006 result = AnyRefType::get(getContext());
1007 break;
1008 }
1009
1010 case FIRToken::kw_Reset:
1011 consumeToken(FIRToken::kw_Reset);
1012 result = ResetType::get(getContext());
1013 break;
1014
1015 case FIRToken::kw_AsyncReset:
1016 consumeToken(FIRToken::kw_AsyncReset);
1017 result = AsyncResetType::get(getContext());
1018 break;
1019
1020 case FIRToken::kw_UInt:
1021 consumeToken(FIRToken::kw_UInt);
1022 // Width is not present since langle_UInt would have been lexed instead.
1023 result = UIntType::get(getContext(), -1);
1024 break;
1025
1026 case FIRToken::kw_SInt:
1027 consumeToken(FIRToken::kw_SInt);
1028 // Width is not present since langle_SInt would have been lexed instead.
1029 result = SIntType::get(getContext(), -1);
1030 break;
1031
1032 case FIRToken::kw_Analog:
1033 consumeToken(FIRToken::kw_Analog);
1034 // Width is not present since langle_Analog would have been lexed instead.
1035 result = AnalogType::get(getContext(), -1);
1036 break;
1037
1038 case FIRToken::langle_UInt:
1039 case FIRToken::langle_SInt:
1040 case FIRToken::langle_Analog: {
1041 // The '<' has already been consumed by the lexer, so we need to parse
1042 // the mandatory width and the trailing '>'.
1043 auto kind = getToken().getKind();
1044 consumeToken();
1045
1046 int32_t width;
1047 if (parseWidth(width))
1048 return failure();
1049
1050 if (kind == FIRToken::langle_SInt)
1051 result = SIntType::get(getContext(), width);
1052 else if (kind == FIRToken::langle_UInt)
1053 result = UIntType::get(getContext(), width);
1054 else {
1055 assert(kind == FIRToken::langle_Analog);
1056 result = AnalogType::get(getContext(), width);
1057 }
1058 break;
1059 }
1060
1061 case FIRToken::kw_Domain: {
1062 if (requireFeature(missingSpecFIRVersion, "domains"))
1063 return failure();
1064 consumeToken();
1065
1066 // Parse: Domain of SymbolName
1067 auto loc = getToken().getLoc();
1068 StringRef domainKindStr;
1069 if (parseToken(FIRToken::kw_of, "expected 'of' after Domain type") ||
1070 parseId(domainKindStr, "expected domain kind"))
1071 return failure();
1072
1073 // Look up the domain to get its fields
1074 const auto &domainMap = getConstants().domainMap;
1075 auto lookup = domainMap.find(domainKindStr);
1076 if (lookup == domainMap.end())
1077 return emitError(loc) << "unknown domain '" << domainKindStr << "'";
1078
1079 result = DomainType::getFromDomainOp(lookup->second);
1080 break;
1081 }
1082
1083 case FIRToken::kw_Probe:
1084 case FIRToken::kw_RWProbe: {
1085 auto kind = getToken().getKind();
1086 auto loc = getToken().getLoc();
1087 consumeToken();
1088
1089 // Inner Type
1090 FIRRTLType type;
1091 if (parseToken(FIRToken::less, "expected '<' in reference type") ||
1092 parseType(type, "expected probe data type"))
1093 return failure();
1094
1095 SmallVector<StringRef> layers;
1096 if (consumeIf(FIRToken::comma)) {
1097 if (requireFeature({4, 0, 0}, "colored probes"))
1098 return failure();
1099 // Probe Color
1100 do {
1101 StringRef layer;
1102 loc = getToken().getLoc();
1103 if (parseId(layer, "expected layer name"))
1104 return failure();
1105 layers.push_back(layer);
1106 } while (consumeIf(FIRToken::period));
1107 }
1108
1109 if (!consumeIf(FIRToken::greater))
1110 return emitError(loc, "expected '>' to end reference type");
1111
1112 bool forceable = kind == FIRToken::kw_RWProbe;
1113
1115 if (!innerType)
1116 return emitError(loc, "invalid probe inner type, must be base-type");
1117
1118 if (!innerType.isPassive())
1119 return emitError(loc, "probe inner type must be passive");
1120
1121 if (forceable && innerType.containsConst())
1122 return emitError(loc, "rwprobe cannot contain const");
1123
1124 SymbolRefAttr layer;
1125 if (!layers.empty()) {
1126 auto nestedLayers =
1127 llvm::map_range(ArrayRef(layers).drop_front(), [&](StringRef a) {
1128 return FlatSymbolRefAttr::get(getContext(), a);
1129 });
1130 layer = SymbolRefAttr::get(getContext(), layers.front(),
1131 llvm::to_vector(nestedLayers));
1132 }
1133
1134 result = RefType::get(innerType, forceable, layer);
1135 break;
1136 }
1137
1138 case FIRToken::l_brace: {
1139 consumeToken(FIRToken::l_brace);
1140
1141 SmallVector<OpenBundleType::BundleElement, 4> elements;
1142 SmallPtrSet<StringAttr, 4> nameSet;
1143 bool bundleCompatible = true;
1144 if (parseListUntil(FIRToken::r_brace, [&]() -> ParseResult {
1145 bool isFlipped = consumeIf(FIRToken::kw_flip);
1146
1147 auto loc = getToken().getLoc();
1148 StringRef fieldNameStr;
1149 if (parseFieldId(fieldNameStr, "expected bundle field name") ||
1150 parseToken(FIRToken::colon, "expected ':' in bundle"))
1151 return failure();
1152 auto fieldName = StringAttr::get(getContext(), fieldNameStr);
1153
1154 // Verify that the names of each field are unique.
1155 if (!nameSet.insert(fieldName).second)
1156 return emitError(loc, "duplicate field name in bundle: " +
1157 fieldName.getValue());
1158
1159 FIRRTLType type;
1160 if (parseType(type, "expected bundle field type"))
1161 return failure();
1162
1163 elements.push_back({fieldName, isFlipped, type});
1164 bundleCompatible &= isa<BundleType::ElementType>(type);
1165
1166 return success();
1167 }))
1168 return failure();
1169
1170 // Try to emit base-only bundle.
1171 if (bundleCompatible) {
1172 auto bundleElements = llvm::map_range(elements, [](auto element) {
1173 return BundleType::BundleElement{
1174 element.name, element.isFlip,
1175 cast<BundleType::ElementType>(element.type)};
1176 });
1177 result = BundleType::get(getContext(), llvm::to_vector(bundleElements));
1178 } else {
1179 result = OpenBundleType::getChecked(
1180 [&]() { return emitError(typeLoc); }, getContext(),
1181 ArrayRef<OpenBundleType::BundleElement>(elements));
1182 if (!result)
1183 return failure();
1184 }
1185 break;
1186 }
1187
1188 case FIRToken::l_brace_bar: {
1189 if (parseEnumType(result))
1190 return failure();
1191 break;
1192 }
1193
1194 case FIRToken::identifier: {
1195 StringRef id;
1196 auto loc = getToken().getLoc();
1197 if (parseId(id, "expected a type alias name"))
1198 return failure();
1199 auto it = constants.aliasMap.find(id);
1200 if (it == constants.aliasMap.end()) {
1201 emitError(loc) << "type identifier `" << id << "` is not declared";
1202 return failure();
1203 }
1204 result = it->second;
1205 break;
1206 }
1207
1208 case FIRToken::kw_const: {
1209 consumeToken(FIRToken::kw_const);
1210 auto nextToken = getToken();
1211 auto loc = nextToken.getLoc();
1212
1213 // Guard against multiple 'const' specifications
1214 if (nextToken.is(FIRToken::kw_const))
1215 return emitError(loc, "'const' can only be specified once on a type");
1216
1217 if (failed(parseType(result, message)))
1218 return failure();
1219
1220 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1221 if (!baseType)
1222 return emitError(loc, "only hardware types can be 'const'");
1223
1224 result = baseType.getConstType(true);
1225 return success();
1226 }
1227
1228 case FIRToken::kw_String:
1229 if (requireFeature({3, 1, 0}, "Strings"))
1230 return failure();
1231 consumeToken(FIRToken::kw_String);
1232 result = StringType::get(getContext());
1233 break;
1234 case FIRToken::kw_Integer:
1235 if (requireFeature({3, 1, 0}, "Integers"))
1236 return failure();
1237 consumeToken(FIRToken::kw_Integer);
1238 result = FIntegerType::get(getContext());
1239 break;
1240 case FIRToken::kw_Bool:
1241 if (requireFeature({6, 0, 0}, "Bools"))
1242 return failure();
1243 consumeToken(FIRToken::kw_Bool);
1244 result = BoolType::get(getContext());
1245 break;
1246 case FIRToken::kw_Double:
1247 if (requireFeature({6, 0, 0}, "Doubles"))
1248 return failure();
1249 consumeToken(FIRToken::kw_Double);
1250 result = DoubleType::get(getContext());
1251 break;
1252 case FIRToken::kw_Path:
1253 if (requireFeature({6, 0, 0}, "Paths"))
1254 return failure();
1255 consumeToken(FIRToken::kw_Path);
1256 result = PathType::get(getContext());
1257 break;
1258 case FIRToken::kw_List:
1259 if (requireFeature({4, 0, 0}, "Lists") || parseListType(result))
1260 return failure();
1261 break;
1262
1263 case FIRToken::langle_List: {
1264 // The '<' has already been consumed by the lexer, so we need to parse
1265 // the element type and the trailing '>'.
1266 if (requireFeature({4, 0, 0}, "Lists"))
1267 return failure();
1268 consumeToken();
1269
1270 PropertyType elementType;
1271 if (parsePropertyType(elementType, "expected List element type") ||
1272 parseToken(FIRToken::greater, "expected '>' in List type"))
1273 return failure();
1274
1275 result = ListType::get(getContext(), elementType);
1276 break;
1277 }
1278
1279 case FIRToken::kw_Registry:
1280 if (requireFeature(missingSpecFIRVersion, "Registries") ||
1281 parseRegistryType(result))
1282 return failure();
1283 break;
1284
1285 case FIRToken::langle_Registry: {
1286 // The '<' has already been consumed by the lexer, so we need to parse
1287 // the element type and the trailing '>'.
1288 if (requireFeature(missingSpecFIRVersion, "Registries"))
1289 return failure();
1290 consumeToken();
1291
1292 PropertyType elementType;
1293 if (parsePropertyType(elementType, "expected Registry element type") ||
1294 parseToken(FIRToken::greater, "expected '>' in Registry type"))
1295 return failure();
1296
1297 result = RegistryType::get(getContext(), elementType);
1298 break;
1299 }
1300 }
1301
1302 // Handle postfix vector sizes.
1303 while (consumeIf(FIRToken::l_square)) {
1304 auto sizeLoc = getToken().getLoc();
1305 int64_t size;
1306 if (parseIntLit(size, "expected width") ||
1307 parseToken(FIRToken::r_square, "expected ]"))
1308 return failure();
1309
1310 if (size < 0)
1311 return emitError(sizeLoc, "invalid size specifier"), failure();
1312
1313 auto baseType = type_dyn_cast<FIRRTLBaseType>(result);
1314 if (baseType)
1315 result = FVectorType::get(baseType, size);
1316 else {
1317 result = OpenVectorType::getChecked([&]() { return emitError(typeLoc); },
1318 result, size);
1319 if (!result)
1320 return failure();
1321 }
1322 }
1323
1324 return success();
1325}
1326
1327/// ruw ::= 'old' | 'new' | 'undefined'
1328ParseResult FIRParser::parseRUW(RUWBehavior &result) {
1329 switch (getToken().getKind()) {
1330
1331 case FIRToken::kw_old:
1332 result = RUWBehavior::Old;
1333 consumeToken(FIRToken::kw_old);
1334 break;
1335 case FIRToken::kw_new:
1336 result = RUWBehavior::New;
1337 consumeToken(FIRToken::kw_new);
1338 break;
1339 case FIRToken::kw_undefined:
1340 result = RUWBehavior::Undefined;
1341 consumeToken(FIRToken::kw_undefined);
1342 break;
1343 default:
1344 return failure();
1345 }
1346
1347 return success();
1348}
1349
1350/// ruw ::= 'old' | 'new' | 'undefined'
1351ParseResult FIRParser::parseOptionalRUW(RUWBehavior &result) {
1352 switch (getToken().getKind()) {
1353 default:
1354 break;
1355
1356 case FIRToken::kw_old:
1357 result = RUWBehavior::Old;
1358 consumeToken(FIRToken::kw_old);
1359 break;
1360 case FIRToken::kw_new:
1361 result = RUWBehavior::New;
1362 consumeToken(FIRToken::kw_new);
1363 break;
1364 case FIRToken::kw_undefined:
1365 result = RUWBehavior::Undefined;
1366 consumeToken(FIRToken::kw_undefined);
1367 break;
1368 }
1369
1370 return success();
1371}
1372
1373/// param ::= id '=' param-value
1374ParseResult FIRParser::parseParameter(StringAttr &resultName,
1375 Attribute &resultValue, SMLoc &resultLoc,
1376 bool allowAggregates) {
1377 auto loc = getToken().getLoc();
1378
1379 // Parse the name of the parameter.
1380 StringRef name;
1381 if (parseId(name, "expected parameter name") ||
1382 parseToken(FIRToken::equal, "expected '=' in parameter"))
1383 return failure();
1384
1385 // Parse the value of the parameter.
1386 Attribute value;
1387 if (parseParameterValue(value, allowAggregates))
1388 return failure();
1389
1390 resultName = StringAttr::get(getContext(), name);
1391 resultValue = value;
1392 resultLoc = loc;
1393 return success();
1394}
1395
1396/// param-value ::= intLit
1397/// ::= StringLit
1398/// ::= floatingpoint
1399/// ::= VerbatimStringLit
1400/// ::= '[' (param-value)','* ']' (if allowAggregates)
1401/// ::= '{' (id '=' param)','* '}' (if allowAggregates)
1402ParseResult FIRParser::parseParameterValue(Attribute &value,
1403 bool allowAggregates) {
1404 mlir::Builder builder(getContext());
1405 switch (getToken().getKind()) {
1406
1407 // param-value ::= intLit
1408 case FIRToken::integer:
1409 case FIRToken::signed_integer: {
1410 APInt result;
1411 if (parseIntLit(result, "invalid integer parameter"))
1412 return failure();
1413
1414 // If the integer parameter is less than 32-bits, sign extend this to a
1415 // 32-bit value. This needs to eventually emit as a 32-bit value in
1416 // Verilog and we want to get the size correct immediately.
1417 if (result.getBitWidth() < 32)
1418 result = result.sext(32);
1419
1420 value = builder.getIntegerAttr(
1421 builder.getIntegerType(result.getBitWidth(), result.isSignBitSet()),
1422 result);
1423 return success();
1424 }
1425
1426 // param-value ::= StringLit
1427 case FIRToken::string: {
1428 // Drop the double quotes and unescape.
1429 value = builder.getStringAttr(getToken().getStringValue());
1430 consumeToken(FIRToken::string);
1431 return success();
1432 }
1433
1434 // param-value ::= VerbatimStringLit
1435 case FIRToken::verbatim_string: {
1436 // Drop the single quotes and unescape the ones inside.
1437 auto text = builder.getStringAttr(getToken().getVerbatimStringValue());
1438 value = hw::ParamVerbatimAttr::get(text);
1439 consumeToken(FIRToken::verbatim_string);
1440 return success();
1441 }
1442
1443 // param-value ::= floatingpoint
1444 case FIRToken::floatingpoint: {
1445 double v;
1446 if (!llvm::to_float(getTokenSpelling(), v))
1447 return emitError("invalid float parameter syntax"), failure();
1448
1449 value = builder.getF64FloatAttr(v);
1450 consumeToken(FIRToken::floatingpoint);
1451 return success();
1452 }
1453
1454 // param-value ::= '[' (param)','* ']'
1455 case FIRToken::l_square: {
1456 if (!allowAggregates)
1457 return emitError("expected non-aggregate parameter value");
1458 consumeToken();
1459
1460 SmallVector<Attribute> elements;
1461 auto parseElement = [&] {
1462 return parseParameterValue(elements.emplace_back(),
1463 /*allowAggregates=*/true);
1464 };
1465 if (parseListUntil(FIRToken::r_square, parseElement))
1466 return failure();
1467
1468 value = builder.getArrayAttr(elements);
1469 return success();
1470 }
1471
1472 // param-value ::= '{' (id '=' param)','* '}'
1473 case FIRToken::l_brace: {
1474 if (!allowAggregates)
1475 return emitError("expected non-aggregate parameter value");
1476 consumeToken();
1477
1478 NamedAttrList fields;
1479 auto parseField = [&]() -> ParseResult {
1480 StringAttr fieldName;
1481 Attribute fieldValue;
1482 SMLoc fieldLoc;
1483 if (parseParameter(fieldName, fieldValue, fieldLoc,
1484 /*allowAggregates=*/true))
1485 return failure();
1486 if (fields.set(fieldName, fieldValue))
1487 return emitError(fieldLoc)
1488 << "redefinition of parameter '" << fieldName.getValue() << "'";
1489 return success();
1490 };
1491 if (parseListUntil(FIRToken::r_brace, parseField))
1492 return failure();
1493
1494 value = fields.getDictionary(getContext());
1495 return success();
1496 }
1497
1498 default:
1499 return emitError("expected parameter value");
1500 }
1501}
1502
1503//===----------------------------------------------------------------------===//
1504// FIRModuleContext
1505//===----------------------------------------------------------------------===//
1506
1507// Entries in a symbol table are either an mlir::Value for the operation that
1508// defines the value or an unbundled ID tracking the index in the
1509// UnbundledValues list.
1510using UnbundledID = llvm::PointerEmbeddedInt<unsigned, 31>;
1511using SymbolValueEntry = llvm::PointerUnion<Value, UnbundledID>;
1512
1514 llvm::StringMap<std::pair<SMLoc, SymbolValueEntry>, llvm::BumpPtrAllocator>;
1515using ModuleSymbolTableEntry = ModuleSymbolTable::MapEntryTy;
1516
1517using UnbundledValueEntry = SmallVector<std::pair<Attribute, Value>>;
1518using UnbundledValuesList = std::vector<UnbundledValueEntry>;
1519namespace {
1520/// This structure is used to track which entries are added while inside a scope
1521/// and remove them upon exiting the scope.
1522struct UnbundledValueRestorer {
1523 UnbundledValuesList &list;
1524 size_t startingSize;
1525 UnbundledValueRestorer(UnbundledValuesList &list) : list(list) {
1526 startingSize = list.size();
1527 }
1528 ~UnbundledValueRestorer() { list.resize(startingSize); }
1529};
1530} // namespace
1531
1532using SubaccessCache = llvm::DenseMap<std::pair<Value, unsigned>, Value>;
1533
1534namespace {
1535/// This struct provides context information that is global to the module we're
1536/// currently parsing into.
1537struct FIRModuleContext : public FIRParser {
1538 explicit FIRModuleContext(Block *topLevelBlock,
1539 SharedParserConstants &constants, FIRLexer &lexer,
1540 FIRVersion version)
1541 : FIRParser(constants, lexer, version), topLevelBlock(topLevelBlock) {}
1542
1543 /// Get a cached constant.
1544 template <typename OpTy = ConstantOp, typename... Args>
1545 Value getCachedConstant(ImplicitLocOpBuilder &builder, Attribute attr,
1546 Type type, Args &&...args) {
1547 auto &result = constantCache[{attr, type}];
1548 if (result)
1549 return result;
1550
1551 // Make sure to insert constants at the top level of the module to maintain
1552 // dominance.
1553 OpBuilder::InsertPoint savedIP;
1554
1555 // Find the insertion point.
1556 if (builder.getInsertionBlock() != topLevelBlock) {
1557 savedIP = builder.saveInsertionPoint();
1558 auto *block = builder.getInsertionBlock();
1559 while (true) {
1560 auto *op = block->getParentOp();
1561 if (!op || !op->getBlock()) {
1562 // We are inserting into an unknown region.
1563 builder.setInsertionPointToEnd(topLevelBlock);
1564 break;
1565 }
1566 if (op->getBlock() == topLevelBlock) {
1567 builder.setInsertionPoint(op);
1568 break;
1569 }
1570 block = op->getBlock();
1571 }
1572 }
1573
1574 result = OpTy::create(builder, type, std::forward<Args>(args)...);
1575
1576 if (savedIP.isSet())
1577 builder.setInsertionPoint(savedIP.getBlock(), savedIP.getPoint());
1578
1579 return result;
1580 }
1581
1582 //===--------------------------------------------------------------------===//
1583 // SubaccessCache
1584
1585 /// This returns a reference with the assumption that the caller will fill in
1586 /// the cached value. We keep track of inserted subaccesses so that we can
1587 /// remove them when we exit a scope.
1588 Value &getCachedSubaccess(Value value, unsigned index) {
1589 auto &result = subaccessCache[{value, index}];
1590 if (!result) {
1591 // The outer most block won't be in the map.
1592 auto it = scopeMap.find(value.getParentBlock());
1593 if (it != scopeMap.end())
1594 it->second->scopedSubaccesses.push_back({result, index});
1595 }
1596 return result;
1597 }
1598
1599 //===--------------------------------------------------------------------===//
1600 // SymbolTable
1601
1602 /// Add a symbol entry with the specified name, returning failure if the name
1603 /// is already defined.
1604 ParseResult addSymbolEntry(StringRef name, SymbolValueEntry entry, SMLoc loc,
1605 bool insertNameIntoGlobalScope = false);
1606 ParseResult addSymbolEntry(StringRef name, Value value, SMLoc loc,
1607 bool insertNameIntoGlobalScope = false) {
1608 return addSymbolEntry(name, SymbolValueEntry(value), loc,
1609 insertNameIntoGlobalScope);
1610 }
1611
1612 // Removes a symbol from symbolTable (Workaround since symbolTable is private)
1613 void removeSymbolEntry(StringRef name);
1614
1615 /// Resolved a symbol table entry to a value. Emission of error is optional.
1616 ParseResult resolveSymbolEntry(Value &result, SymbolValueEntry &entry,
1617 SMLoc loc, bool fatal = true);
1618
1619 /// Resolved a symbol table entry if it is an expanded bundle e.g. from an
1620 /// instance. Emission of error is optional.
1621 ParseResult resolveSymbolEntry(Value &result, SymbolValueEntry &entry,
1622 StringRef field, SMLoc loc);
1623
1624 /// Look up the specified name, emitting an error and returning failure if the
1625 /// name is unknown.
1626 ParseResult lookupSymbolEntry(SymbolValueEntry &result, StringRef name,
1627 SMLoc loc);
1628
1629 UnbundledValueEntry &getUnbundledEntry(unsigned index) {
1630 assert(index < unbundledValues.size());
1631 return unbundledValues[index];
1632 }
1633
1634 /// This contains one entry for each value in FIRRTL that is represented as a
1635 /// bundle type in the FIRRTL spec but for which we represent as an exploded
1636 /// set of elements in the FIRRTL dialect.
1637 UnbundledValuesList unbundledValues;
1638
1639 /// Provide a symbol table scope that automatically pops all the entries off
1640 /// the symbol table when the scope is exited.
1641 struct ContextScope {
1642 friend struct FIRModuleContext;
1643 ContextScope(FIRModuleContext &moduleContext, Block *block)
1644 : moduleContext(moduleContext), block(block),
1645 previousScope(moduleContext.currentScope) {
1646 moduleContext.currentScope = this;
1647 moduleContext.scopeMap[block] = this;
1648 }
1649 ~ContextScope() {
1650 // Mark all entries in this scope as being invalid. We track validity
1651 // through the SMLoc field instead of deleting entries.
1652 for (auto *entryPtr : scopedDecls)
1653 entryPtr->second.first = SMLoc();
1654 // Erase the scoped subacceses from the cache. If the block is deleted we
1655 // could resuse the memory, although the chances are quite small.
1656 for (auto subaccess : scopedSubaccesses)
1657 moduleContext.subaccessCache.erase(subaccess);
1658 // Erase this context from the map.
1659 moduleContext.scopeMap.erase(block);
1660 // Reset to the previous scope.
1661 moduleContext.currentScope = previousScope;
1662 }
1663
1664 private:
1665 void operator=(const ContextScope &) = delete;
1666 ContextScope(const ContextScope &) = delete;
1667
1668 FIRModuleContext &moduleContext;
1669 Block *block;
1670 ContextScope *previousScope;
1671 std::vector<ModuleSymbolTableEntry *> scopedDecls;
1672 std::vector<std::pair<Value, unsigned>> scopedSubaccesses;
1673 };
1674
1675private:
1676 /// The top level block in which we insert cached constants.
1677 Block *topLevelBlock;
1678
1679 /// The expression-oriented nature of firrtl syntax produces tons of constant
1680 /// nodes which are obviously redundant. Instead of literally producing them
1681 /// in the parser, do an implicit CSE to reduce parse time and silliness in
1682 /// the resulting IR.
1683 llvm::DenseMap<std::pair<Attribute, Type>, Value> constantCache;
1684
1685 /// This symbol table holds the names of ports, wires, and other local decls.
1686 /// This is scoped because conditional statements introduce subscopes.
1687 ModuleSymbolTable symbolTable;
1688
1689 /// This is a cache of subindex and subfield operations so we don't constantly
1690 /// recreate large chains of them. This maps a bundle value + index to the
1691 /// subaccess result.
1692 SubaccessCache subaccessCache;
1693
1694 /// This maps a block to related ContextScope.
1695 DenseMap<Block *, ContextScope *> scopeMap;
1696
1697 /// If non-null, all new entries added to the symbol table are added to this
1698 /// list. This allows us to "pop" the entries by resetting them to null when
1699 /// scope is exited.
1700 ContextScope *currentScope = nullptr;
1701};
1702
1703} // end anonymous namespace
1704
1705// Removes a symbol from symbolTable (Workaround since symbolTable is private)
1706void FIRModuleContext::removeSymbolEntry(StringRef name) {
1707 symbolTable.erase(name);
1708}
1709
1710/// Add a symbol entry with the specified name, returning failure if the name
1711/// is already defined.
1712///
1713/// When 'insertNameIntoGlobalScope' is true, we don't allow the name to be
1714/// popped. This is a workaround for (firrtl scala bug) that should eventually
1715/// be fixed.
1716ParseResult FIRModuleContext::addSymbolEntry(StringRef name,
1717 SymbolValueEntry entry, SMLoc loc,
1718 bool insertNameIntoGlobalScope) {
1719 // Do a lookup by trying to do an insertion. Do so in a way that we can tell
1720 // if we hit a missing element (SMLoc is null).
1721 auto [entryIt, inserted] =
1722 symbolTable.try_emplace(name, SMLoc(), SymbolValueEntry());
1723
1724 // If insertion failed, the name already exists
1725 if (!inserted) {
1726 if (entryIt->second.first.isValid()) {
1727 // Valid activeSMLoc: active symbol in current scope redeclared
1728 emitError(loc, "redefinition of name '" + name + "' ")
1729 .attachNote(translateLocation(entryIt->second.first))
1730 << "previous definition here.";
1731 } else {
1732 // Invalid activeSMLoc: symbol from a completed scope redeclared
1733 emitError(loc, "redefinition of name '" + name + "' ")
1734 << "- FIRRTL has flat namespace and requires all "
1735 << "declarations in a module to have unique names.";
1736 }
1737 return failure();
1738 }
1739
1740 // If we didn't have a hit, then record the location, and remember that this
1741 // was new to this scope.
1742 entryIt->second = {loc, entry};
1743 if (currentScope && !insertNameIntoGlobalScope)
1744 currentScope->scopedDecls.push_back(&*entryIt);
1745 return success();
1746}
1747
1748/// Look up the specified name, emitting an error and returning null if the
1749/// name is unknown.
1750ParseResult FIRModuleContext::lookupSymbolEntry(SymbolValueEntry &result,
1751 StringRef name, SMLoc loc) {
1752 auto &entry = symbolTable[name];
1753 if (!entry.first.isValid())
1754 return emitError(loc, "use of unknown declaration '" + name + "'");
1755 result = entry.second;
1756 assert(result && "name in symbol table without definition");
1757 return success();
1758}
1759
1760ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1761 SymbolValueEntry &entry,
1762 SMLoc loc, bool fatal) {
1763 if (!isa<Value>(entry)) {
1764 if (fatal)
1765 emitError(loc, "bundle value should only be used from subfield");
1766 return failure();
1767 }
1768 result = cast<Value>(entry);
1769 return success();
1770}
1771
1772ParseResult FIRModuleContext::resolveSymbolEntry(Value &result,
1773 SymbolValueEntry &entry,
1774 StringRef fieldName,
1775 SMLoc loc) {
1776 if (!isa<UnbundledID>(entry)) {
1777 emitError(loc, "value should not be used from subfield");
1778 return failure();
1779 }
1780
1781 auto fieldAttr = StringAttr::get(getContext(), fieldName);
1782
1783 unsigned unbundledId = cast<UnbundledID>(entry) - 1;
1784 assert(unbundledId < unbundledValues.size());
1785 UnbundledValueEntry &ubEntry = unbundledValues[unbundledId];
1786 for (auto elt : ubEntry) {
1787 if (elt.first == fieldAttr) {
1788 result = elt.second;
1789 break;
1790 }
1791 }
1792 if (!result) {
1793 emitError(loc, "use of invalid field name '")
1794 << fieldName << "' on bundle value";
1795 return failure();
1796 }
1797
1798 return success();
1799}
1800
1801//===----------------------------------------------------------------------===//
1802// FIRStmtParser
1803//===----------------------------------------------------------------------===//
1804
1805namespace {
1806/// This class is used when building expression nodes for a statement: we need
1807/// to parse a bunch of expressions and build MLIR operations for them, and then
1808/// we see the locator that specifies the location for those operations
1809/// afterward.
1810///
1811/// It is wasteful in time and memory to create a bunch of temporary FileLineCol
1812/// location's that point into the .fir file when they're destined to get
1813/// overwritten by a location specified by a Locator. To avoid this, we create
1814/// all of the operations with a temporary location on them, then remember the
1815/// [Operation*, SMLoc] pair for the newly created operation.
1816///
1817/// At the end of the operation we'll see a Locator (or not). If we see a
1818/// locator, we apply it to all the operations we've parsed and we're done. If
1819/// not, we lazily create the locators in the .fir file.
1820struct LazyLocationListener : public OpBuilder::Listener {
1821 LazyLocationListener(OpBuilder &builder) : builder(builder) {
1822 assert(builder.getListener() == nullptr);
1823 builder.setListener(this);
1824 }
1825
1826 ~LazyLocationListener() {
1827 assert(subOps.empty() && "didn't process parsed operations");
1828 assert(builder.getListener() == this);
1829 builder.setListener(nullptr);
1830 }
1831
1832 void startStatement() {
1833 assert(!isActive && "Already processing a statement");
1834 isActive = true;
1835 }
1836
1837 /// Compute the location an operation created at `loc` should be given,
1838 /// or that a diagnostic about it should be emitted on, honoring the
1839 /// the @info handling policy. This will only translate the SMLoc when the
1840 /// policy actually needs it, since that will intern a location into the
1841 /// context permanently.
1842 Location getLoc(FIRParser &parser, SMLoc loc) {
1844 switch (parser.getConstants().options.infoLocatorHandling) {
1845 case ILH::IgnoreInfo:
1846 // Shouldn't have an infoLoc, but if we do ignore it.
1847 break;
1848 case ILH::PreferInfo:
1849 if (infoLoc)
1850 return infoLoc;
1851 break;
1852 case ILH::FusedInfo:
1853 if (infoLoc)
1854 return FusedLoc::get(infoLoc.getContext(),
1855 {infoLoc, parser.translateLocation(loc)});
1856 break;
1857 }
1858 return parser.translateLocation(loc);
1859 }
1860
1861 /// This is called when done with each statement. This applies the locations
1862 /// to each statement.
1863 void endStatement(FIRParser &parser) {
1864 assert(isActive && "Not parsing a statement");
1865
1866 // Apply a location to each subop, following user preference to use the
1867 // @info location, a fused location, or the location in the .fir file.
1868 for (auto opAndSMLoc : subOps)
1869 opAndSMLoc.first->setLoc(getLoc(parser, opAndSMLoc.second));
1870
1871 // Reset our state.
1872 isActive = false;
1873 infoLoc = LocationAttr();
1874 currentSMLoc = SMLoc();
1875 subOps.clear();
1876 }
1877
1878 /// Specify the location to be used for the next operations that are created.
1879 void setLoc(SMLoc loc) { currentSMLoc = loc; }
1880
1881 /// When a @Info locator is parsed, this method captures it.
1882 void setInfoLoc(LocationAttr loc) {
1883 assert(!infoLoc && "Info location multiply specified");
1884 infoLoc = loc;
1885 }
1886
1887 // Notification handler for when an operation is inserted into the builder.
1888 /// `op` is the operation that was inserted.
1889 void notifyOperationInserted(Operation *op,
1890 mlir::IRRewriter::InsertPoint) override {
1891 assert(currentSMLoc != SMLoc() && "No .fir file location specified");
1892 assert(isActive && "Not parsing a statement");
1893 subOps.push_back({op, currentSMLoc});
1894 }
1895
1896private:
1897 /// This is set to true while parsing a statement. It is used for assertions.
1898 bool isActive = false;
1899
1900 /// This is the current position in the source file that the next operation
1901 /// will be parsed into.
1902 SMLoc currentSMLoc;
1903
1904 /// This is the @ location attribute for the current statement, or null if
1905 /// not set.
1906 LocationAttr infoLoc;
1907
1908 /// This is the builder we're installed into.
1909 OpBuilder &builder;
1910
1911 /// This is the set of operations we've enqueued along with their location in
1912 /// the source file.
1913 SmallVector<std::pair<Operation *, SMLoc>, 8> subOps;
1914
1915 void operator=(const LazyLocationListener &) = delete;
1916 LazyLocationListener(const LazyLocationListener &) = delete;
1917};
1918} // end anonymous namespace
1919
1920namespace {
1921/// This class tracks inner-ref users and their intended targets,
1922/// (presently there must be just one) for post-processing at a point
1923/// where adding the symbols is safe without risk of races.
1924struct InnerSymFixups {
1925 /// Add a fixup to be processed later.
1926 void add(hw::InnerRefUserOpInterface user, hw::InnerSymTarget target) {
1927 fixups.push_back({user, target});
1928 }
1929
1930 /// Resolve all stored fixups, if any. Not expected to fail,
1931 /// as checking should primarily occur during original parsing.
1932 LogicalResult resolve(hw::InnerSymbolNamespaceCollection &isnc);
1933
1934private:
1935 struct Fixup {
1936 hw::InnerRefUserOpInterface innerRefUser;
1937 hw::InnerSymTarget target;
1938 };
1939 SmallVector<Fixup, 0> fixups;
1940};
1941} // end anonymous namespace
1942
1943LogicalResult
1944InnerSymFixups::resolve(hw::InnerSymbolNamespaceCollection &isnc) {
1945 for (auto &f : fixups) {
1946 auto ref = getInnerRefTo(
1947 f.target, [&isnc](FModuleLike module) -> hw::InnerSymbolNamespace & {
1948 return isnc.get(module);
1949 });
1950 assert(ref && "unable to resolve inner symbol target");
1951
1952 // Per-op fixup logic. Only RWProbeOp's presently.
1953 auto result =
1954 TypeSwitch<Operation *, LogicalResult>(f.innerRefUser.getOperation())
1955 .Case<RWProbeOp>([ref](RWProbeOp op) {
1956 op.setTargetAttr(ref);
1957 return success();
1958 })
1959 .Default([](auto *op) {
1960 return op->emitError("unknown inner-ref user requiring fixup");
1961 });
1962 if (failed(result))
1963 return failure();
1964 }
1965 return success();
1966}
1967
1968namespace {
1969/// This class implements logic and state for parsing statements, suites, and
1970/// similar module body constructs.
1971struct FIRStmtParser : public FIRParser {
1972 explicit FIRStmtParser(Block &blockToInsertInto,
1973 FIRModuleContext &moduleContext,
1974 InnerSymFixups &innerSymFixups,
1975 const SymbolTable &circuitSymTbl, FIRVersion version,
1976 SymbolRefAttr layerSym = {})
1977 : FIRParser(moduleContext.getConstants(), moduleContext.getLexer(),
1978 version),
1979 builder(UnknownLoc::get(getContext()), getContext()),
1980 locationProcessor(this->builder), moduleContext(moduleContext),
1981 innerSymFixups(innerSymFixups), layerSym(layerSym),
1982 circuitSymTbl(circuitSymTbl) {
1983 builder.setInsertionPointToEnd(&blockToInsertInto);
1984 }
1985
1986 ParseResult parseSimpleStmt(unsigned stmtIndent);
1987 ParseResult parseSimpleStmtBlock(unsigned indent);
1988
1989private:
1990 ParseResult parseSimpleStmtImpl(unsigned stmtIndent);
1991
1992 /// Attach invalid values to every element of the value.
1993 void emitInvalidate(Value val, Flow flow);
1994
1995 // The FIRRTL specification describes Invalidates as a statement with
1996 // implicit connect semantics. The FIRRTL dialect models it as a primitive
1997 // that returns an "Invalid Value", followed by an explicit connect to make
1998 // the representation simpler and more consistent.
1999 void emitInvalidate(Value val) { emitInvalidate(val, foldFlow(val)); }
2000
2001 /// Parse an @info marker if present and inform locationProcessor about it.
2002 ParseResult parseOptionalInfo() {
2003 LocationAttr loc;
2004 if (failed(parseOptionalInfoLocator(loc)))
2005 return failure();
2006 locationProcessor.setInfoLoc(loc);
2007 return success();
2008 }
2009
2010 // Exp Parsing
2011 ParseResult parseExpImpl(Value &result, const Twine &message,
2012 bool isLeadingStmt);
2013 ParseResult parseExp(Value &result, const Twine &message) {
2014 return parseExpImpl(result, message, /*isLeadingStmt:*/ false);
2015 }
2016 ParseResult parseExpLeadingStmt(Value &result, const Twine &message) {
2017 return parseExpImpl(result, message, /*isLeadingStmt:*/ true);
2018 }
2019 /// Insert an implicit object- or domain-to-AnyRef cast if required by the
2020 /// expected type. Leave other values unchanged for the caller to type-check.
2021 Value emitImplicitAnyRefCast(Value value, Type expectedType) {
2022 if (!isa<AnyRefType>(expectedType))
2023 return value;
2024 if (isa<ClassType>(value.getType()))
2025 return ObjectAnyRefCastOp::create(builder, value);
2026 if (isa<DomainType>(value.getType()))
2027 return DomainAnyRefCastOp::create(builder, value);
2028 return value;
2029 }
2030
2031 ParseResult parseEnumExp(Value &result);
2032 ParseResult parsePathExp(Value &result);
2033 ParseResult parseDomainExp(Value &result);
2034 ParseResult parseRefExp(Value &result, const Twine &message);
2035 ParseResult parseStaticRefExp(Value &result, const Twine &message);
2036 ParseResult parseRWProbeStaticRefExp(FieldRef &refResult, Type &type,
2037 const Twine &message);
2038
2039 // Generic intrinsic parsing.
2040 ParseResult parseIntrinsic(Value &result, bool isStatement);
2041 ParseResult parseIntrinsicStmt() {
2042 Value unused;
2043 return parseIntrinsic(unused, /*isStatement=*/true);
2044 }
2045 ParseResult parseIntrinsicExp(Value &result) {
2046 return parseIntrinsic(result, /*isStatement=*/false);
2047 }
2048 ParseResult parseOptionalParams(ArrayAttr &resultParameters);
2049
2050 template <typename subop>
2051 FailureOr<Value> emitCachedSubAccess(Value base, unsigned indexNo, SMLoc loc);
2052 ParseResult parseOptionalExpPostscript(Value &result,
2053 bool allowDynamic = true);
2054 ParseResult parsePostFixFieldId(Value &result);
2055 ParseResult parsePostFixIntSubscript(Value &result);
2056 ParseResult parsePostFixDynamicSubscript(Value &result);
2057 ParseResult
2058 parseIntegerLiteralExp(Value &result, bool isSigned,
2059 std::optional<int32_t> allocatedWidth = {});
2060 ParseResult parseListExp(Value &result);
2061 ParseResult parseListConcatExp(Value &result);
2062 ParseResult parseCatExp(Value &result);
2063 ParseResult parseStringConcatExp(Value &result);
2064 ParseResult parsePropEqExp(Value &result);
2065 ParseResult parseObjectEqExp(Value &result);
2066 ParseResult parseListContainsExp(Value &result);
2067 ParseResult parseUnsafeDomainCast(Value &result);
2068 ParseResult parseUnknownProperty(Value &result);
2069
2070 template <typename T, size_t M, size_t N, size_t... Ms, size_t... Ns>
2071 ParseResult parsePrim(std::index_sequence<Ms...>, std::index_sequence<Ns...>,
2072 Value &result) {
2073 auto loc = getToken().getLoc();
2074 locationProcessor.setLoc(loc);
2075 consumeToken();
2076
2077 auto vals = std::array<Value, M>();
2078 auto ints = std::array<int64_t, N>();
2079
2080 // Parse all the values.
2081 bool first = true;
2082 for (size_t i = 0; i < M; ++i) {
2083 if (!first)
2084 if (parseToken(FIRToken::comma, "expected ','"))
2085 return failure();
2086 if (parseExp(vals[i], "expected expression in primitive operand"))
2087 return failure();
2088 first = false;
2089 }
2090
2091 // Parse all the attributes.
2092 for (size_t i = 0; i < N; ++i) {
2093 if (!first)
2094 if (parseToken(FIRToken::comma, "expected ','"))
2095 return failure();
2096 if (parseIntLit(ints[i], "expected integer in primitive operand"))
2097 return failure();
2098 first = false;
2099 }
2100
2101 if (parseToken(FIRToken::r_paren, "expected ')'"))
2102 return failure();
2103
2104 // Infer the type.
2105 auto type = T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())...,
2106 ints[Ns]..., {});
2107 if (!type) {
2108 // Only call translateLocation on an error case, it is expensive.
2109 T::inferReturnType(cast<FIRRTLType>(vals[Ms].getType())..., ints[Ns]...,
2110 translateLocation(loc));
2111 return failure();
2112 }
2113
2114 // Create the operation.
2115 auto op = T::create(builder, type, vals[Ms]..., ints[Ns]...);
2116 result = op.getResult();
2117 return success();
2118 }
2119
2120 template <typename T, unsigned M, unsigned N>
2121 ParseResult parsePrimExp(Value &result) {
2122 auto ms = std::make_index_sequence<M>();
2123 auto ns = std::make_index_sequence<N>();
2124 return parsePrim<T, M, N>(ms, ns, result);
2125 }
2126
2127 std::optional<ParseResult> parseExpWithLeadingKeyword(FIRToken keyword);
2128
2129 // Stmt Parsing
2130 ParseResult parseSubBlock(Block &blockToInsertInto, unsigned indent,
2131 SymbolRefAttr layerSym);
2132 ParseResult parseAttach();
2133 ParseResult parseMemPort(MemDirAttr direction);
2134
2135 // Parse a format string and build operations for FIRRTL "special"
2136 // substitutions. Set `formatStringResult` to the validated format string and
2137 // `operands` to the list of actual operands.
2138 ParseResult parseFormatString(SMLoc formatStringLoc, StringRef formatString,
2139 ArrayRef<Value> specOperands,
2140 StringAttr &formatStringResult,
2141 SmallVectorImpl<Value> &operands);
2142 ParseResult parsePrintf();
2143 ParseResult parseFPrintf();
2144 ParseResult parseFFlush();
2145 ParseResult parseSkip();
2146 ParseResult parseStop();
2147 ParseResult parseAssert();
2148 ParseResult parseAssume();
2149 ParseResult parseCover();
2150 ParseResult parseWhen(unsigned whenIndent);
2151 ParseResult parseMatch(unsigned matchIndent);
2152 ParseResult parseDomainInstantiation();
2153 ParseResult parseDomainDefine();
2154 ParseResult parseRefDefine();
2155 ParseResult parseRefForce();
2156 ParseResult parseRefForceInitial();
2157 ParseResult parseRefRelease();
2158 ParseResult parseRefReleaseInitial();
2159 ParseResult parseRefRead(Value &result);
2160 ParseResult parseProbe(Value &result);
2161 ParseResult parsePropAssert();
2162 ParseResult parsePropAssign();
2163 ParseResult parseRWProbe(Value &result);
2164 ParseResult parseLeadingExpStmt(Value lhs);
2165 ParseResult parseConnect();
2166 ParseResult parseInvalidate();
2167 ParseResult parseLayerBlockOrGroup(unsigned indent);
2168
2169 // Declarations
2170 ParseResult parseInstance();
2171 ParseResult parseInstanceChoice();
2172 ParseResult parseObject();
2173 ParseResult parseCombMem();
2174 ParseResult parseSeqMem();
2175 ParseResult parseMem(unsigned memIndent);
2176 ParseResult parseNode();
2177 ParseResult parseWire();
2178 ParseResult parseRegister(unsigned regIndent);
2179 ParseResult parseRegisterWithReset();
2180 ParseResult parseContract(unsigned blockIndent);
2181
2182 // Helper to fetch a module referenced by an instance-like statement.
2183 FModuleLike getReferencedModule(SMLoc loc, StringRef moduleName);
2184
2185 // The builder to build into.
2186 ImplicitLocOpBuilder builder;
2187 LazyLocationListener locationProcessor;
2188
2189 // Extra information maintained across a module.
2190 FIRModuleContext &moduleContext;
2191
2192 /// Inner symbol users to fixup after parsing.
2193 InnerSymFixups &innerSymFixups;
2194
2195 // An optional symbol that contains the current layer block that we are in.
2196 // This is used to construct a nested symbol for a layer block operation.
2197 SymbolRefAttr layerSym;
2198
2199 const SymbolTable &circuitSymTbl;
2200};
2201
2202} // end anonymous namespace
2203
2204/// Attach invalid values to every element of the value.
2205// NOLINTNEXTLINE(misc-no-recursion)
2206void FIRStmtParser::emitInvalidate(Value val, Flow flow) {
2207 auto tpe = type_dyn_cast<FIRRTLBaseType>(val.getType());
2208 // Invalidate does nothing for non-base types.
2209 // When aggregates-of-refs are supported, instead check 'containsReference'
2210 // below.
2211 if (!tpe)
2212 return;
2213
2214 auto props = tpe.getRecursiveTypeProperties();
2215 if (props.isPassive && !props.containsAnalog) {
2216 if (flow == Flow::Source)
2217 return;
2218 emitConnect(builder, val, InvalidValueOp::create(builder, tpe),
2219 getConstants().options.warnOnTruncation);
2220 return;
2221 }
2222
2223 // Recurse until we hit passive leaves. Connect any leaves which have sink or
2224 // duplex flow.
2225 //
2226 // TODO: This is very similar to connect expansion in the LowerTypes pass
2227 // works. Find a way to unify this with methods common to LowerTypes or to
2228 // have LowerTypes to the actual work here, e.g., emitting a partial connect
2229 // to only the leaf sources.
2230 TypeSwitch<FIRRTLType>(tpe)
2231 .Case<BundleType>([&](auto tpe) {
2232 for (size_t i = 0, e = tpe.getNumElements(); i < e; ++i) {
2233 auto &subfield = moduleContext.getCachedSubaccess(val, i);
2234 if (!subfield) {
2235 OpBuilder::InsertionGuard guard(builder);
2236 builder.setInsertionPointAfterValue(val);
2237 subfield = SubfieldOp::create(builder, val, i);
2238 }
2239 emitInvalidate(subfield,
2240 tpe.getElement(i).isFlip ? swapFlow(flow) : flow);
2241 }
2242 })
2243 .Case<FVectorType>([&](auto tpe) {
2244 auto tpex = tpe.getElementType();
2245 for (size_t i = 0, e = tpe.getNumElements(); i != e; ++i) {
2246 auto &subindex = moduleContext.getCachedSubaccess(val, i);
2247 if (!subindex) {
2248 OpBuilder::InsertionGuard guard(builder);
2249 builder.setInsertionPointAfterValue(val);
2250 subindex = SubindexOp::create(builder, tpex, val, i);
2251 }
2252 emitInvalidate(subindex, flow);
2253 }
2254 });
2255}
2256
2257//===-------------------------------
2258// FIRStmtParser Expression Parsing.
2259
2260/// Parse the 'exp' grammar, returning all of the suboperations in the
2261/// specified vector, and the ultimate SSA value in value.
2262///
2263/// exp ::= id // Ref
2264/// ::= prim
2265/// ::= integer-literal-exp
2266/// ::= enum-exp
2267/// ::= list-exp
2268/// ::= 'String(' stringLit ')'
2269/// ::= exp '.' fieldId
2270/// ::= exp '[' intLit ']'
2271/// XX ::= exp '.' DoubleLit // TODO Workaround for #470
2272/// ::= exp '[' exp ']'
2273///
2274///
2275/// If 'isLeadingStmt' is true, then this is being called to parse the first
2276/// expression in a statement. We can handle some weird cases due to this if
2277/// we end up parsing the whole statement. In that case we return success, but
2278/// set the 'result' value to null.
2279// NOLINTNEXTLINE(misc-no-recursion)
2280ParseResult FIRStmtParser::parseExpImpl(Value &result, const Twine &message,
2281 bool isLeadingStmt) {
2282 auto token = getToken();
2283 auto kind = token.getKind();
2284 switch (kind) {
2285 case FIRToken::lp_integer_add:
2286 case FIRToken::lp_integer_mul:
2287 case FIRToken::lp_integer_shr:
2288 case FIRToken::lp_integer_shl:
2289 if (requireFeature({4, 0, 0}, "Integer arithmetic expressions"))
2290 return failure();
2291 break;
2292 default:
2293 break;
2294 }
2295
2296 switch (kind) {
2297 // Handle all primitive's.
2298#define TOK_LPKEYWORD_PRIM(SPELLING, CLASS, NUMOPERANDS, NUMATTRIBUTES, \
2299 VERSION, FEATURE) \
2300 case FIRToken::lp_##SPELLING: \
2301 if (requireFeature(VERSION, FEATURE)) \
2302 return failure(); \
2303 if (parsePrimExp<CLASS, NUMOPERANDS, NUMATTRIBUTES>(result)) \
2304 return failure(); \
2305 break;
2306#include "FIRTokenKinds.def"
2307
2308 case FIRToken::l_brace_bar:
2309 if (isLeadingStmt)
2310 return emitError("unexpected enumeration as start of statement");
2311 if (parseEnumExp(result))
2312 return failure();
2313 break;
2314 case FIRToken::lp_read:
2315 if (isLeadingStmt)
2316 return emitError("unexpected read() as start of statement");
2317 if (parseRefRead(result))
2318 return failure();
2319 break;
2320 case FIRToken::lp_probe:
2321 if (isLeadingStmt)
2322 return emitError("unexpected probe() as start of statement");
2323 if (parseProbe(result))
2324 return failure();
2325 break;
2326 case FIRToken::lp_rwprobe:
2327 if (isLeadingStmt)
2328 return emitError("unexpected rwprobe() as start of statement");
2329 if (parseRWProbe(result))
2330 return failure();
2331 break;
2332
2333 case FIRToken::langle_UInt:
2334 case FIRToken::langle_SInt: {
2335 // The '<' has already been consumed by the lexer, so we need to parse
2336 // the mandatory width and '>'.
2337 bool isSigned = getToken().is(FIRToken::langle_SInt);
2338 consumeToken();
2339 int32_t width;
2340 if (parseWidth(width))
2341 return failure();
2342
2343 // Now parse the '(' intLit ')' part.
2344 if (parseIntegerLiteralExp(result, isSigned, width))
2345 return failure();
2346 break;
2347 }
2348
2349 case FIRToken::lp_UInt:
2350 if (parseIntegerLiteralExp(result, /*isSigned=*/false))
2351 return failure();
2352 break;
2353 case FIRToken::lp_SInt:
2354 if (parseIntegerLiteralExp(result, /*isSigned=*/true))
2355 return failure();
2356 break;
2357 case FIRToken::lp_String: {
2358 if (requireFeature({3, 1, 0}, "Strings"))
2359 return failure();
2360 locationProcessor.setLoc(getToken().getLoc());
2361 consumeToken(FIRToken::lp_String);
2362 StringRef spelling;
2363 if (parseGetSpelling(spelling) ||
2364 parseToken(FIRToken::string,
2365 "expected string literal in String expression") ||
2366 parseToken(FIRToken::r_paren, "expected ')' in String expression"))
2367 return failure();
2368 auto attr = builder.getStringAttr(FIRToken::getStringValue(spelling));
2369 result = moduleContext.getCachedConstant<StringConstantOp>(
2370 builder, attr, builder.getType<StringType>(), attr);
2371 break;
2372 }
2373 case FIRToken::lp_Integer: {
2374 if (requireFeature({3, 1, 0}, "Integers"))
2375 return failure();
2376 locationProcessor.setLoc(getToken().getLoc());
2377 consumeToken(FIRToken::lp_Integer);
2378 APInt value;
2379 if (parseIntLit(value, "expected integer literal in Integer expression") ||
2380 parseToken(FIRToken::r_paren, "expected ')' in Integer expression"))
2381 return failure();
2382 APSInt apint(value, /*isUnsigned=*/false);
2383 result = moduleContext.getCachedConstant<FIntegerConstantOp>(
2384 builder, IntegerAttr::get(getContext(), apint),
2385 builder.getType<FIntegerType>(), apint);
2386 break;
2387 }
2388 case FIRToken::lp_Bool: {
2389 if (requireFeature({6, 0, 0}, "Bools"))
2390 return failure();
2391 locationProcessor.setLoc(getToken().getLoc());
2392 consumeToken(FIRToken::lp_Bool);
2393 bool value;
2394 if (consumeIf(FIRToken::kw_true))
2395 value = true;
2396 else if (consumeIf(FIRToken::kw_false))
2397 value = false;
2398 else
2399 return emitError("expected true or false in Bool expression");
2400 if (parseToken(FIRToken::r_paren, "expected ')' in Bool expression"))
2401 return failure();
2402 auto attr = builder.getBoolAttr(value);
2403 result = moduleContext.getCachedConstant<BoolConstantOp>(
2404 builder, attr, builder.getType<BoolType>(), value);
2405 break;
2406 }
2407 case FIRToken::lp_Double: {
2408 if (requireFeature({6, 0, 0}, "Doubles"))
2409 return failure();
2410 locationProcessor.setLoc(getToken().getLoc());
2411 consumeToken(FIRToken::lp_Double);
2412 auto spelling = getTokenSpelling();
2413 if (parseToken(FIRToken::floatingpoint,
2414 "expected floating point in Double expression") ||
2415 parseToken(FIRToken::r_paren, "expected ')' in Double expression"))
2416 return failure();
2417 // NaN, INF, exponent, hex, integer?
2418 // This uses `strtod` internally, FWIW. See `man 3 strtod`.
2419 double d;
2420 if (!llvm::to_float(spelling, d))
2421 return emitError("invalid double");
2422 auto attr = builder.getF64FloatAttr(d);
2423 result = moduleContext.getCachedConstant<DoubleConstantOp>(
2424 builder, attr, builder.getType<DoubleType>(), attr);
2425 break;
2426 }
2427 case FIRToken::lp_List:
2428 case FIRToken::langle_List: {
2429 if (requireFeature({4, 0, 0}, "Lists"))
2430 return failure();
2431 if (isLeadingStmt)
2432 return emitError("unexpected List<>() as start of statement");
2433 if (parseListExp(result))
2434 return failure();
2435 break;
2436 }
2437
2438 case FIRToken::lp_list_concat: {
2439 if (isLeadingStmt)
2440 return emitError("unexpected list_create() as start of statement");
2441 if (requireFeature({4, 0, 0}, "List concat") || parseListConcatExp(result))
2442 return failure();
2443 break;
2444 }
2445
2446 case FIRToken::lp_path:
2447 if (isLeadingStmt)
2448 return emitError("unexpected path() as start of statement");
2449 if (requireFeature({6, 0, 0}, "Paths") || parsePathExp(result))
2450 return failure();
2451 break;
2452
2453 case FIRToken::lp_intrinsic:
2454 if (requireFeature({4, 0, 0}, "generic intrinsics") ||
2455 parseIntrinsicExp(result))
2456 return failure();
2457 break;
2458
2459 case FIRToken::lp_cat:
2460 if (parseCatExp(result))
2461 return failure();
2462 break;
2463
2464 case FIRToken::lp_string_concat:
2465 if (parseStringConcatExp(result))
2466 return failure();
2467 break;
2468
2469 case FIRToken::lp_prop_eq:
2470 if (requireFeature({6, 0, 0}, "property equality") ||
2471 parsePropEqExp(result))
2472 return failure();
2473 break;
2474
2475 case FIRToken::lp_object_eq:
2476 if (requireFeature(nextFIRVersion, "object equality") ||
2477 parseObjectEqExp(result))
2478 return failure();
2479 break;
2480
2481 case FIRToken::lp_list_contains:
2482 if (requireFeature(missingSpecFIRVersion, "list contains") ||
2483 parseListContainsExp(result))
2484 return failure();
2485 break;
2486
2487 case FIRToken::lp_unsafe_domain_cast:
2488 if (requireFeature(nextFIRVersion, "unsafe_domain_cast") ||
2489 parseUnsafeDomainCast(result))
2490 return failure();
2491 break;
2492 case FIRToken::lp_Unknown:
2493 if (requireFeature(nextFIRVersion, "unknown property expressions") ||
2494 parseUnknownProperty(result))
2495 return failure();
2496 break;
2497
2498 // Otherwise there are a bunch of keywords that are treated as identifiers
2499 // try them.
2500 case FIRToken::identifier: // exp ::= id
2501 case FIRToken::literal_identifier:
2502 case FIRToken::kw_UInt:
2503 case FIRToken::kw_SInt:
2504 case FIRToken::kw_String:
2505 case FIRToken::kw_Integer:
2506 case FIRToken::kw_Bool:
2507 case FIRToken::kw_Double:
2508 case FIRToken::kw_List:
2509 default: {
2510 StringRef name;
2511 auto loc = getToken().getLoc();
2512 SymbolValueEntry symtabEntry;
2513 if (parseId(name, message) ||
2514 moduleContext.lookupSymbolEntry(symtabEntry, name, loc))
2515 return failure();
2516
2517 // If we looked up a normal value, then we're done.
2518 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
2519 break;
2520
2521 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
2522
2523 // Otherwise we referred to an implicitly bundled value. We *must* be in
2524 // the midst of processing a field ID reference or 'is invalid'. If not,
2525 // this is an error.
2526 if (isLeadingStmt && consumeIf(FIRToken::kw_is)) {
2527 if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
2528 parseOptionalInfo())
2529 return failure();
2530
2531 locationProcessor.setLoc(loc);
2532 // Invalidate all of the results of the bundled value.
2533 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
2534 UnbundledValueEntry &ubEntry =
2535 moduleContext.getUnbundledEntry(unbundledId);
2536 for (auto elt : ubEntry)
2537 emitInvalidate(elt.second);
2538
2539 // Signify that we parsed the whole statement.
2540 result = Value();
2541 return success();
2542 }
2543
2544 // Handle the normal "instance.x" reference.
2545 StringRef fieldName;
2546 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
2547 parseFieldId(fieldName, "expected field name") ||
2548 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc))
2549 return failure();
2550 break;
2551 }
2552 }
2553 // Don't add code here, the common cases of these switch statements will be
2554 // merged. This allows for fixing up primops after they have been created.
2555 switch (kind) {
2556 case FIRToken::lp_shr:
2557 // For FIRRTL versions earlier than 4.0.0, insert pad(_, 1) around any
2558 // unsigned shr This ensures the minimum width is 1 (but can be greater)
2559 if (version < FIRVersion(4, 0, 0) && type_isa<UIntType>(result.getType()))
2560 result = PadPrimOp::create(builder, result, 1);
2561 break;
2562 default:
2563 break;
2564 }
2565
2566 return parseOptionalExpPostscript(result);
2567}
2568
2569/// Parse the postfix productions of expression after the leading expression
2570/// has been parsed.
2571///
2572/// exp ::= exp '.' fieldId
2573/// ::= exp '[' intLit ']'
2574/// XX ::= exp '.' DoubleLit // TODO Workaround for #470
2575/// ::= exp '[' exp ']'
2576ParseResult FIRStmtParser::parseOptionalExpPostscript(Value &result,
2577 bool allowDynamic) {
2578
2579 // Handle postfix expressions.
2580 while (true) {
2581 // Subfield: exp ::= exp '.' fieldId
2582 if (consumeIf(FIRToken::period)) {
2583 if (parsePostFixFieldId(result))
2584 return failure();
2585
2586 continue;
2587 }
2588
2589 // Subindex: exp ::= exp '[' intLit ']' | exp '[' exp ']'
2590 if (consumeIf(FIRToken::l_square)) {
2591 if (getToken().isAny(FIRToken::integer, FIRToken::string)) {
2592 if (parsePostFixIntSubscript(result))
2593 return failure();
2594 continue;
2595 }
2596 if (!allowDynamic)
2597 return emitError("subaccess not allowed here");
2598 if (parsePostFixDynamicSubscript(result))
2599 return failure();
2600
2601 continue;
2602 }
2603
2604 return success();
2605 }
2606}
2607
2608template <typename subop>
2609FailureOr<Value>
2610FIRStmtParser::emitCachedSubAccess(Value base, unsigned indexNo, SMLoc loc) {
2611 // Check if we already have created this Subindex op.
2612 auto &value = moduleContext.getCachedSubaccess(base, indexNo);
2613 if (value)
2614 return value;
2615
2616 // Make sure the field name matches up with the input value's type and
2617 // compute the result type for the expression.
2618 auto baseType = cast<FIRRTLType>(base.getType());
2619 auto resultType = subop::inferReturnType(baseType, indexNo, {});
2620 if (!resultType) {
2621 // Emit the error at the right location. translateLocation is expensive.
2622 (void)subop::inferReturnType(baseType, indexNo, translateLocation(loc));
2623 return failure();
2624 }
2625
2626 // Create the result operation, inserting at the location of the declaration.
2627 // This will cache the subfield operation for further uses.
2628 locationProcessor.setLoc(loc);
2629 OpBuilder::InsertionGuard guard(builder);
2630 builder.setInsertionPointAfterValue(base);
2631 auto op = subop::create(builder, resultType, base, indexNo);
2632
2633 // Insert the newly created operation into the cache.
2634 return value = op.getResult();
2635}
2636
2637/// exp ::= exp '.' fieldId
2638///
2639/// The "exp '.'" part of the production has already been parsed.
2640///
2641ParseResult FIRStmtParser::parsePostFixFieldId(Value &result) {
2642 auto loc = getToken().getLoc();
2643 SmallVector<StringRef, 3> fields;
2644 if (parseFieldIdSeq(fields, "expected field name"))
2645 return failure();
2646 for (auto fieldName : fields) {
2647 std::optional<unsigned> indexV;
2648 auto type = result.getType();
2649 if (auto refTy = type_dyn_cast<RefType>(type))
2650 type = refTy.getType();
2651 if (auto bundle = type_dyn_cast<BundleType>(type))
2652 indexV = bundle.getElementIndex(fieldName);
2653 else if (auto bundle = type_dyn_cast<OpenBundleType>(type))
2654 indexV = bundle.getElementIndex(fieldName);
2655 else if (auto klass = type_dyn_cast<ClassType>(type))
2656 indexV = klass.getElementIndex(fieldName);
2657 else if (auto domain = type_dyn_cast<DomainType>(type))
2658 indexV = domain.getFieldIndex(fieldName);
2659 else
2660 return emitError(loc,
2661 "subfield requires bundle, object, or domain operand ");
2662 if (!indexV)
2663 return emitError(loc, "unknown field '" + fieldName + "' in type ")
2664 << result.getType();
2665 auto indexNo = *indexV;
2666
2667 FailureOr<Value> subResult;
2668 if (type_isa<RefType>(result.getType()))
2669 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2670 else if (type_isa<ClassType>(type))
2671 subResult = emitCachedSubAccess<ObjectSubfieldOp>(result, indexNo, loc);
2672 else if (type_isa<DomainType>(type))
2673 subResult = emitCachedSubAccess<DomainSubfieldOp>(result, indexNo, loc);
2674 else if (type_isa<BundleType>(type))
2675 subResult = emitCachedSubAccess<SubfieldOp>(result, indexNo, loc);
2676 else
2677 subResult = emitCachedSubAccess<OpenSubfieldOp>(result, indexNo, loc);
2678
2679 if (failed(subResult))
2680 return failure();
2681 result = *subResult;
2682 }
2683 return success();
2684}
2685
2686/// exp ::= exp '[' intLit ']'
2687///
2688/// The "exp '['" part of the production has already been parsed.
2689///
2690ParseResult FIRStmtParser::parsePostFixIntSubscript(Value &result) {
2691 auto loc = getToken().getLoc();
2692 int32_t indexNo;
2693 if (parseIntLit(indexNo, "expected index") ||
2694 parseToken(FIRToken::r_square, "expected ']'"))
2695 return failure();
2696
2697 if (indexNo < 0)
2698 return emitError(loc, "invalid index specifier"), failure();
2699
2700 FailureOr<Value> subResult;
2701 if (type_isa<RefType>(result.getType()))
2702 subResult = emitCachedSubAccess<RefSubOp>(result, indexNo, loc);
2703 else if (type_isa<FVectorType>(result.getType()))
2704 subResult = emitCachedSubAccess<SubindexOp>(result, indexNo, loc);
2705 else
2706 subResult = emitCachedSubAccess<OpenSubindexOp>(result, indexNo, loc);
2707
2708 if (failed(subResult))
2709 return failure();
2710 result = *subResult;
2711 return success();
2712}
2713
2714/// exp ::= exp '[' exp ']'
2715///
2716/// The "exp '['" part of the production has already been parsed.
2717///
2718ParseResult FIRStmtParser::parsePostFixDynamicSubscript(Value &result) {
2719 auto loc = getToken().getLoc();
2720 Value index;
2721 if (parseExp(index, "expected subscript index expression") ||
2722 parseToken(FIRToken::r_square, "expected ']' in subscript"))
2723 return failure();
2724
2725 // If the index expression is a flip type, strip it off.
2726 auto indexType = type_dyn_cast<FIRRTLBaseType>(index.getType());
2727 if (!indexType)
2728 return emitError("expected base type for index expression");
2729 indexType = indexType.getPassiveType();
2730 locationProcessor.setLoc(loc);
2731
2732 // Make sure the index expression is valid and compute the result type for the
2733 // expression.
2734 auto resultType =
2735 SubaccessOp::inferReturnType(result.getType(), index.getType(), {});
2736 if (!resultType) {
2737 // Emit the error at the right location. translateLocation is expensive.
2738 (void)SubaccessOp::inferReturnType(result.getType(), index.getType(),
2739 translateLocation(loc));
2740 return failure();
2741 }
2742
2743 // Create the result operation.
2744 auto op = SubaccessOp::create(builder, resultType, result, index);
2745 result = op.getResult();
2746 return success();
2747}
2748
2749/// integer-literal-exp ::= 'UInt' optional-width '(' intLit ')'
2750/// ::= 'SInt' optional-width '(' intLit ')'
2751///
2752/// If allocatedWidth is provided, it means the width was already parsed
2753/// (e.g., from a langle_UInt token) and should be used instead of parsing
2754/// it from the token stream.
2755ParseResult
2756FIRStmtParser::parseIntegerLiteralExp(Value &result, bool isSigned,
2757 std::optional<int32_t> allocatedWidth) {
2758 auto loc = getToken().getLoc();
2759
2760 // Determine if '(' was already consumed by the lexer.
2761 bool hasLParen = getToken().isAny(FIRToken::lp_UInt, FIRToken::lp_SInt);
2762 if (hasLParen)
2763 consumeToken();
2764
2765 // Parse a width specifier if not already provided.
2766 int32_t width = allocatedWidth.value_or(-1);
2767 APInt value;
2768
2769 // If we consumed an lp_ token, the '(' was already consumed by the lexer.
2770 // Otherwise, we need to parse it.
2771 if (!hasLParen &&
2772 parseToken(FIRToken::l_paren, "expected '(' in integer expression"))
2773 return failure();
2774
2775 if (parseIntLit(value, "expected integer value") ||
2776 parseToken(FIRToken::r_paren, "expected ')' in integer expression"))
2777 return failure();
2778
2779 // Construct an integer attribute of the right width.
2780 // Literals are parsed as 'const' types.
2781 auto type = IntType::get(builder.getContext(), isSigned, width, true);
2782
2783 IntegerType::SignednessSemantics signedness =
2784 isSigned ? IntegerType::Signed : IntegerType::Unsigned;
2785 if (width == 0) {
2786 if (!value.isZero())
2787 return emitError(loc, "zero bit constant must be zero");
2788 value = value.trunc(0);
2789 } else if (width != -1) {
2790 // Convert to the type's width, checking value fits in destination width.
2791 bool valueFits = isSigned ? value.isSignedIntN(width) : value.isIntN(width);
2792 if (!valueFits)
2793 return emitError(loc, "initializer too wide for declared width");
2794 value = isSigned ? value.sextOrTrunc(width) : value.zextOrTrunc(width);
2795 }
2796
2797 Type attrType =
2798 IntegerType::get(type.getContext(), value.getBitWidth(), signedness);
2799 auto attr = builder.getIntegerAttr(attrType, value);
2800
2801 locationProcessor.setLoc(loc);
2802 result = moduleContext.getCachedConstant(builder, attr, type, attr);
2803 return success();
2804}
2805
2806/// list-exp ::= list-type '(' exp* ')'
2807ParseResult FIRStmtParser::parseListExp(Value &result) {
2808 auto loc = getToken().getLoc();
2809 bool hasLAngle = getToken().is(FIRToken::langle_List);
2810 bool hasLParen = getToken().is(FIRToken::lp_List);
2811 consumeToken();
2812
2813 PropertyType elementType;
2814 // If we consumed a langle_ token, the '<' was already consumed by the lexer.
2815 if (!hasLAngle && parseToken(FIRToken::less, "expected '<' in List type"))
2816 return failure();
2817
2818 if (parsePropertyType(elementType, "expected List element type") ||
2819 parseToken(FIRToken::greater, "expected '>' in List type"))
2820 return failure();
2821
2822 auto listType = ListType::get(getContext(), elementType);
2823
2824 // If we consumed an lp_ token, the '(' was already consumed by the lexer.
2825 if (!hasLParen &&
2826 parseToken(FIRToken::l_paren, "expected '(' in List expression"))
2827 return failure();
2828
2829 SmallVector<Value, 3> operands;
2830 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2831 Value operand;
2832 locationProcessor.setLoc(loc);
2833 if (parseExp(operand, "expected expression in List expression"))
2834 return failure();
2835
2836 operand = emitImplicitAnyRefCast(operand, elementType);
2837 if (operand.getType() != elementType)
2838 return emitError(loc, "unexpected expression of type ")
2839 << operand.getType() << " in List expression of type "
2840 << elementType;
2841
2842 operands.push_back(operand);
2843 return success();
2844 }))
2845 return failure();
2846
2847 locationProcessor.setLoc(loc);
2848 result = ListCreateOp::create(builder, listType, operands);
2849 return success();
2850}
2851
2852/// list-concat-exp ::= 'list_concat' '(' exp* ')'
2853ParseResult FIRStmtParser::parseListConcatExp(Value &result) {
2854 consumeToken(FIRToken::lp_list_concat);
2855
2856 auto loc = getToken().getLoc();
2857 ListType type;
2858 SmallVector<Value, 3> operands;
2859 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2860 Value operand;
2861 locationProcessor.setLoc(loc);
2862 if (parseExp(operand, "expected expression in List concat expression"))
2863 return failure();
2864
2865 if (!type_isa<ListType>(operand.getType()))
2866 return emitError(loc, "unexpected expression of type ")
2867 << operand.getType() << " in List concat expression";
2868
2869 if (!type)
2870 type = type_cast<ListType>(operand.getType());
2871
2872 if (operand.getType() != type)
2873 return emitError(loc, "unexpected expression of type ")
2874 << operand.getType() << " in List concat expression of type "
2875 << type;
2876
2877 operands.push_back(operand);
2878 return success();
2879 }))
2880 return failure();
2881
2882 if (operands.empty())
2883 return emitError(loc, "need at least one List to concatenate");
2884
2885 locationProcessor.setLoc(loc);
2886 result = ListConcatOp::create(builder, type, operands);
2887 return success();
2888}
2889
2890/// cat-exp ::= 'cat(' exp* ')'
2891ParseResult FIRStmtParser::parseCatExp(Value &result) {
2892 consumeToken(FIRToken::lp_cat);
2893
2894 auto loc = getToken().getLoc();
2895 SmallVector<Value, 3> operands;
2896 std::optional<bool> isSigned;
2897 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2898 Value operand;
2899 locationProcessor.setLoc(loc);
2900 auto operandLoc = getToken().getLoc();
2901 if (parseExp(operand, "expected expression in cat expression"))
2902 return failure();
2903 if (!type_isa<IntType>(operand.getType())) {
2904 auto diag = emitError(loc, "all operands must be Int type");
2905 diag.attachNote(translateLocation(operandLoc))
2906 << "non-integer operand is here";
2907 return failure();
2908 }
2909 if (!isSigned)
2910 isSigned = type_isa<SIntType>(operand.getType());
2911 else if (type_isa<SIntType>(operand.getType()) != *isSigned) {
2912 auto diag = emitError(loc, "all operands must have same signedness");
2913 diag.attachNote(translateLocation(operandLoc))
2914 << "operand with different signedness is here";
2915 return failure();
2916 }
2917
2918 operands.push_back(operand);
2919 return success();
2920 }))
2921 return failure();
2922
2923 if (operands.size() != 2) {
2924 if (requireFeature({6, 0, 0}, "variadic cat", loc))
2925 return failure();
2926 }
2927
2928 locationProcessor.setLoc(loc);
2929 result = CatPrimOp::create(builder, operands);
2930 return success();
2931}
2932
2933/// string_concat-exp ::= 'string_concat(' exp* ')'
2934ParseResult FIRStmtParser::parseStringConcatExp(Value &result) {
2935 consumeToken(FIRToken::lp_string_concat);
2936
2937 auto loc = getToken().getLoc();
2938 SmallVector<Value, 3> operands;
2939 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
2940 Value operand;
2941 locationProcessor.setLoc(loc);
2942 if (parseExp(operand,
2943 "expected expression in string_concat expression"))
2944 return failure();
2945 if (!type_isa<StringType>(operand.getType()))
2946 return emitError(loc, "all operands must be String type");
2947 operands.push_back(operand);
2948 return success();
2949 }))
2950 return failure();
2951
2952 if (operands.empty())
2953 return emitError(loc, "need at least one String to concatenate");
2954
2955 locationProcessor.setLoc(loc);
2956 auto type = StringType::get(builder.getContext());
2957 result = builder.create<StringConcatOp>(type, operands);
2958 return success();
2959}
2960
2961/// prop_eq-exp ::= 'prop_eq(' expr ',' expr ')'
2962ParseResult FIRStmtParser::parsePropEqExp(Value &result) {
2963 consumeToken(FIRToken::lp_prop_eq);
2964
2965 auto loc = getToken().getLoc();
2966 Value lhs, rhs;
2967 locationProcessor.setLoc(loc);
2968 if (parseExp(lhs, "expected lhs expression in prop_eq expression") ||
2969 parseToken(FIRToken::comma, "expected ','") ||
2970 parseExp(rhs, "expected rhs expression in prop_eq expression") ||
2971 parseToken(FIRToken::r_paren, "expected ')'"))
2972 return failure();
2973
2974 auto isValidType = [](Type t) {
2975 return type_isa<StringType>(t) || type_isa<BoolType>(t) ||
2977 };
2978 if (!isValidType(lhs.getType()))
2979 return emitError(loc,
2980 "lhs of prop_eq must be String, Bool, or Integer type");
2981 if (!isValidType(rhs.getType()))
2982 return emitError(loc,
2983 "rhs of prop_eq must be String, Bool, or Integer type");
2984 if (lhs.getType() != rhs.getType())
2985 return emitError(loc, "prop_eq operands must have the same type");
2986
2987 locationProcessor.setLoc(loc);
2988 result = PropEqOp::create(builder, lhs, rhs);
2989 return success();
2990}
2991
2992/// object_eq-exp ::= 'object_eq(' expr ',' expr ')'
2993ParseResult FIRStmtParser::parseObjectEqExp(Value &result) {
2994 consumeToken(FIRToken::lp_object_eq);
2995
2996 auto loc = getToken().getLoc();
2997 Value lhs, rhs;
2998 locationProcessor.setLoc(loc);
2999 if (parseExp(lhs, "expected lhs expression in object_eq expression") ||
3000 parseToken(FIRToken::comma, "expected ','") ||
3001 parseExp(rhs, "expected rhs expression in object_eq expression") ||
3002 parseToken(FIRToken::r_paren, "expected ')'"))
3003 return failure();
3004
3005 if (!isa<ClassType, AnyRefType>(lhs.getType()))
3006 return emitError(loc, "lhs of object_eq must be Inst or AnyRef type");
3007 if (!isa<ClassType, AnyRefType>(rhs.getType()))
3008 return emitError(loc, "rhs of object_eq must be Inst or AnyRef type");
3009
3010 locationProcessor.setLoc(loc);
3011 result = ObjectEqOp::create(builder, lhs, rhs);
3012 return success();
3013}
3014
3015/// list-contains-exp ::= 'list_contains' '(' exp ',' exp ')'
3016ParseResult FIRStmtParser::parseListContainsExp(Value &result) {
3017 consumeToken(FIRToken::lp_list_contains);
3018
3019 auto loc = getToken().getLoc();
3020 Value list, element;
3021 locationProcessor.setLoc(loc);
3022 if (parseExp(list, "expected list expression in list_contains expression") ||
3023 parseToken(FIRToken::comma, "expected ','") ||
3024 parseExp(element,
3025 "expected element expression in list_contains expression") ||
3026 parseToken(FIRToken::r_paren, "expected ')'"))
3027 return failure();
3028
3029 auto listType = dyn_cast<ListType>(list.getType());
3030 if (!listType)
3031 return emitError(loc, "first operand of list_contains must be a List");
3032
3033 auto elementType = listType.getElementType();
3034 if (element.getType() != elementType)
3035 return emitError(loc, "list_contains element type ")
3036 << element.getType() << " does not match list element type "
3037 << elementType;
3038
3039 if (!isa<StringType, FIntegerType, BoolType>(elementType))
3040 return emitError(loc, "list_contains does not support elements of type ")
3041 << elementType;
3042
3043 locationProcessor.setLoc(loc);
3044 result = ListContainsOp::create(builder, list, element);
3045 return success();
3046}
3047
3048ParseResult FIRStmtParser::parseUnsafeDomainCast(Value &result) {
3049 consumeToken(FIRToken::lp_unsafe_domain_cast);
3050
3051 auto loc = getToken().getLoc();
3052 Value input;
3053 if (parseExp(input, "expected input"))
3054 return failure();
3055
3056 SmallVector<Value> domains;
3057 if (consumeIf(FIRToken::comma)) {
3058 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3059 Value domain;
3060 if (parseExp(domain, "expected domain"))
3061 return failure();
3062 domains.push_back(domain);
3063 return success();
3064 }))
3065 return failure();
3066 } else if (parseToken(FIRToken::r_paren, "expected closing parenthesis")) {
3067 return failure();
3068 }
3069
3070 locationProcessor.setLoc(loc);
3071 result = UnsafeDomainCastOp::create(builder, input, domains);
3072 return success();
3073}
3074
3075ParseResult FIRStmtParser::parseUnknownProperty(Value &result) {
3076 auto loc = getToken().getLoc();
3077 consumeToken(FIRToken::lp_Unknown);
3078 // The '(' has already been consumed by the lexer.
3079
3080 PropertyType type;
3081 if (parsePropertyType(type, "expected property type") ||
3082 parseToken(FIRToken::r_paren, "expected ')' in unknown property"))
3083 return failure();
3084
3085 locationProcessor.setLoc(loc);
3086 result = UnknownValueOp::create(builder, type);
3087 return success();
3088}
3089
3090/// The .fir grammar has the annoying property where:
3091/// 1) some statements start with keywords
3092/// 2) some start with an expression
3093/// 3) it allows the 'reference' expression to either be an identifier or a
3094/// keyword.
3095///
3096/// One example of this is something like, where this is not a register decl:
3097/// reg <- thing
3098///
3099/// Solving this requires lookahead to the second token. We handle it by
3100/// factoring the lookahead inline into the code to keep the parser fast.
3101///
3102/// As such, statements that start with a leading keyword call this method to
3103/// check to see if the keyword they consumed was actually the start of an
3104/// expression. If so, they parse the expression-based statement and return the
3105/// parser result. If not, they return None and the statement is parsed like
3106/// normal.
3107std::optional<ParseResult>
3108FIRStmtParser::parseExpWithLeadingKeyword(FIRToken keyword) {
3109 switch (getToken().getKind()) {
3110 default:
3111 // This isn't part of an expression, and isn't part of a statement.
3112 return std::nullopt;
3113
3114 case FIRToken::period: // exp `.` identifier
3115 case FIRToken::l_square: // exp `[` index `]`
3116 case FIRToken::kw_is: // exp is invalid
3117 case FIRToken::less_equal: // exp <= thing
3118 break;
3119 }
3120
3121 Value lhs;
3122 SymbolValueEntry symtabEntry;
3123 auto loc = keyword.getLoc();
3124
3125 if (moduleContext.lookupSymbolEntry(symtabEntry, keyword.getSpelling(), loc))
3126 return ParseResult(failure());
3127
3128 // If we have a '.', we might have a symbol or an expanded port. If we
3129 // resolve to a symbol, use that, otherwise check for expanded bundles of
3130 // other ops.
3131 // Non '.' ops take the plain symbol path.
3132 if (moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
3133 // Ok if the base name didn't resolve by itself, it might be part of an
3134 // expanded dot reference. That doesn't work then we fail.
3135 if (!consumeIf(FIRToken::period))
3136 return ParseResult(failure());
3137
3138 StringRef fieldName;
3139 if (parseFieldId(fieldName, "expected field name") ||
3140 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
3141 return ParseResult(failure());
3142 }
3143
3144 // Parse any further trailing things like "mem.x.y".
3145 if (parseOptionalExpPostscript(lhs))
3146 return ParseResult(failure());
3147
3148 return parseLeadingExpStmt(lhs);
3149}
3150//===-----------------------------
3151// FIRStmtParser Statement Parsing
3152
3153/// simple_stmt_block ::= simple_stmt*
3154ParseResult FIRStmtParser::parseSimpleStmtBlock(unsigned indent) {
3155 while (true) {
3156 // The outer level parser can handle these tokens.
3157 if (getToken().isAny(FIRToken::eof, FIRToken::error))
3158 return success();
3159
3160 auto subIndent = getIndentation();
3161 if (!subIndent.has_value())
3162 return emitError("expected statement to be on its own line"), failure();
3163
3164 if (*subIndent <= indent)
3165 return success();
3166
3167 // Let the statement parser handle this.
3168 if (parseSimpleStmt(*subIndent))
3169 return failure();
3170 }
3171}
3172
3173ParseResult FIRStmtParser::parseSimpleStmt(unsigned stmtIndent) {
3174 locationProcessor.startStatement();
3175 auto result = parseSimpleStmtImpl(stmtIndent);
3176 locationProcessor.endStatement(*this);
3177 return result;
3178}
3179
3180/// simple_stmt ::= stmt
3181///
3182/// stmt ::= attach
3183/// ::= memport
3184/// ::= printf
3185/// ::= skip
3186/// ::= stop
3187/// ::= when
3188/// ::= leading-exp-stmt
3189/// ::= define
3190/// ::= propassert
3191/// ::= propassign
3192///
3193/// stmt ::= instance
3194/// ::= cmem | smem | mem
3195/// ::= node | wire
3196/// ::= register
3197/// ::= contract
3198///
3199ParseResult FIRStmtParser::parseSimpleStmtImpl(unsigned stmtIndent) {
3200 auto kind = getToken().getKind();
3201 /// Massage the kind based on the FIRRTL Version.
3202 switch (kind) {
3203 case FIRToken::kw_invalidate:
3204 case FIRToken::kw_connect:
3205 case FIRToken::kw_regreset:
3206 /// The "invalidate", "connect", and "regreset" keywords were added
3207 /// in 3.0.0.
3208 if (version < FIRVersion(3, 0, 0))
3209 kind = FIRToken::identifier;
3210 break;
3211 default:
3212 break;
3213 };
3214 switch (kind) {
3215 // Statements.
3216 case FIRToken::kw_attach:
3217 return parseAttach();
3218 case FIRToken::kw_infer:
3219 return parseMemPort(MemDirAttr::Infer);
3220 case FIRToken::kw_read:
3221 return parseMemPort(MemDirAttr::Read);
3222 case FIRToken::kw_write:
3223 return parseMemPort(MemDirAttr::Write);
3224 case FIRToken::kw_rdwr:
3225 return parseMemPort(MemDirAttr::ReadWrite);
3226 case FIRToken::kw_connect:
3227 return parseConnect();
3228 case FIRToken::kw_propassert:
3229 if (requireFeature({6, 0, 0}, "property assertions"))
3230 return failure();
3231 return parsePropAssert();
3232 case FIRToken::kw_propassign:
3233 if (requireFeature({3, 1, 0}, "properties"))
3234 return failure();
3235 return parsePropAssign();
3236 case FIRToken::kw_invalidate:
3237 return parseInvalidate();
3238 case FIRToken::lp_printf:
3239 return parsePrintf();
3240 case FIRToken::lp_fprintf:
3241 return parseFPrintf();
3242 case FIRToken::lp_fflush:
3243 return parseFFlush();
3244 case FIRToken::kw_skip:
3245 return parseSkip();
3246 case FIRToken::lp_stop:
3247 return parseStop();
3248 case FIRToken::lp_assert:
3249 return parseAssert();
3250 case FIRToken::lp_assume:
3251 return parseAssume();
3252 case FIRToken::lp_cover:
3253 return parseCover();
3254 case FIRToken::kw_when:
3255 return parseWhen(stmtIndent);
3256 case FIRToken::kw_match:
3257 return parseMatch(stmtIndent);
3258 case FIRToken::kw_domain:
3259 // In module context, 'domain' is only valid for domain instantiation
3260 return parseDomainInstantiation();
3261 case FIRToken::kw_domain_define:
3262 return parseDomainDefine();
3263 case FIRToken::kw_define:
3264 return parseRefDefine();
3265 case FIRToken::lp_force:
3266 return parseRefForce();
3267 case FIRToken::lp_force_initial:
3268 return parseRefForceInitial();
3269 case FIRToken::lp_release:
3270 return parseRefRelease();
3271 case FIRToken::lp_release_initial:
3272 return parseRefReleaseInitial();
3273 case FIRToken::kw_group:
3274 if (requireFeature({3, 2, 0}, "optional groups") ||
3275 removedFeature({3, 3, 0}, "optional groups"))
3276 return failure();
3277 return parseLayerBlockOrGroup(stmtIndent);
3278 case FIRToken::kw_layerblock:
3279 if (requireFeature({3, 3, 0}, "layers"))
3280 return failure();
3281 return parseLayerBlockOrGroup(stmtIndent);
3282 case FIRToken::lp_intrinsic:
3283 if (requireFeature({4, 0, 0}, "generic intrinsics"))
3284 return failure();
3285 return parseIntrinsicStmt();
3286 default: {
3287 // Statement productions that start with an expression.
3288 Value lhs;
3289 if (parseExpLeadingStmt(lhs, "unexpected token in module"))
3290 return failure();
3291 // We use parseExp in a special mode that can complete the entire stmt
3292 // at once in unusual cases. If this happened, then we are done.
3293 if (!lhs)
3294 return success();
3295
3296 return parseLeadingExpStmt(lhs);
3297 }
3298
3299 // Declarations
3300 case FIRToken::kw_inst:
3301 return parseInstance();
3302 case FIRToken::kw_instchoice:
3303 return parseInstanceChoice();
3304 case FIRToken::kw_object:
3305 return parseObject();
3306 case FIRToken::kw_cmem:
3307 return parseCombMem();
3308 case FIRToken::kw_smem:
3309 return parseSeqMem();
3310 case FIRToken::kw_mem:
3311 return parseMem(stmtIndent);
3312 case FIRToken::kw_node:
3313 return parseNode();
3314 case FIRToken::kw_wire:
3315 return parseWire();
3316 case FIRToken::kw_reg:
3317 return parseRegister(stmtIndent);
3318 case FIRToken::kw_regreset:
3319 return parseRegisterWithReset();
3320 case FIRToken::kw_contract:
3321 return parseContract(stmtIndent);
3322 }
3323}
3324
3325ParseResult FIRStmtParser::parseSubBlock(Block &blockToInsertInto,
3326 unsigned indent,
3327 SymbolRefAttr layerSym) {
3328 // Declarations within the suite are scoped to within the suite.
3329 auto suiteScope = std::make_unique<FIRModuleContext::ContextScope>(
3330 moduleContext, &blockToInsertInto);
3331
3332 // After parsing the when region, we can release any new entries in
3333 // unbundledValues since the symbol table entries that refer to them will be
3334 // gone.
3335 UnbundledValueRestorer x(moduleContext.unbundledValues);
3336
3337 // We parse the substatements into their own parser, so they get inserted
3338 // into the specified 'when' region.
3339 auto subParser = std::make_unique<FIRStmtParser>(
3340 blockToInsertInto, moduleContext, innerSymFixups, circuitSymTbl, version,
3341 layerSym);
3342
3343 // Figure out whether the body is a single statement or a nested one.
3344 auto stmtIndent = getIndentation();
3345
3346 // Parsing a single statment is straightforward.
3347 if (!stmtIndent.has_value())
3348 return subParser->parseSimpleStmt(indent);
3349
3350 if (*stmtIndent <= indent)
3351 return emitError("statement must be indented more than previous statement"),
3352 failure();
3353
3354 // Parse a block of statements that are indented more than the when.
3355 return subParser->parseSimpleStmtBlock(indent);
3356}
3357
3358/// attach ::= 'attach' '(' exp+ ')' info?
3359ParseResult FIRStmtParser::parseAttach() {
3360 auto startTok = consumeToken(FIRToken::kw_attach);
3361
3362 // If this was actually the start of a connect or something else handle that.
3363 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3364 return *isExpr;
3365
3366 if (parseToken(FIRToken::l_paren, "expected '(' after attach"))
3367 return failure();
3368
3369 SmallVector<Value, 4> operands;
3370 operands.push_back({});
3371 if (parseExp(operands.back(), "expected operand in attach"))
3372 return failure();
3373
3374 while (consumeIf(FIRToken::comma)) {
3375 operands.push_back({});
3376 if (parseExp(operands.back(), "expected operand in attach"))
3377 return failure();
3378 }
3379 if (parseToken(FIRToken::r_paren, "expected close paren"))
3380 return failure();
3381
3382 if (parseOptionalInfo())
3383 return failure();
3384
3385 locationProcessor.setLoc(startTok.getLoc());
3386 AttachOp::create(builder, operands);
3387 return success();
3388}
3389
3390/// stmt ::= mdir 'mport' id '=' id '[' exp ']' exp info?
3391/// mdir ::= 'infer' | 'read' | 'write' | 'rdwr'
3392///
3393ParseResult FIRStmtParser::parseMemPort(MemDirAttr direction) {
3394 auto startTok = consumeToken();
3395 auto startLoc = startTok.getLoc();
3396
3397 // If this was actually the start of a connect or something else handle
3398 // that.
3399 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3400 return *isExpr;
3401
3402 StringRef id;
3403 StringRef memName;
3404 SymbolValueEntry memorySym;
3405 Value memory, indexExp, clock;
3406 if (parseToken(FIRToken::kw_mport, "expected 'mport' in memory port") ||
3407 parseId(id, "expected result name") ||
3408 parseToken(FIRToken::equal, "expected '=' in memory port") ||
3409 parseId(memName, "expected memory name") ||
3410 moduleContext.lookupSymbolEntry(memorySym, memName, startLoc) ||
3411 moduleContext.resolveSymbolEntry(memory, memorySym, startLoc) ||
3412 parseToken(FIRToken::l_square, "expected '[' in memory port") ||
3413 parseExp(indexExp, "expected index expression") ||
3414 parseToken(FIRToken::r_square, "expected ']' in memory port") ||
3415 parseToken(FIRToken::comma, "expected ','") ||
3416 parseExp(clock, "expected clock expression") || parseOptionalInfo())
3417 return failure();
3418
3419 auto memVType = type_dyn_cast<CMemoryType>(memory.getType());
3420 if (!memVType)
3421 return emitError(startLoc,
3422 "memory port should have behavioral memory type");
3423 auto resultType = memVType.getElementType();
3424
3425 ArrayAttr annotations = getConstants().emptyArrayAttr;
3426 locationProcessor.setLoc(startLoc);
3427
3428 // Create the memory port at the location of the cmemory.
3429 Value memoryPort, memoryData;
3430 {
3431 OpBuilder::InsertionGuard guard(builder);
3432 builder.setInsertionPointAfterValue(memory);
3433 auto memoryPortOp = MemoryPortOp::create(
3434 builder, resultType, CMemoryPortType::get(getContext()), memory,
3435 direction, id, annotations);
3436 memoryData = memoryPortOp.getResult(0);
3437 memoryPort = memoryPortOp.getResult(1);
3438 }
3439
3440 // Create a memory port access in the current scope.
3441 MemoryPortAccessOp::create(builder, memoryPort, indexExp, clock);
3442
3443 return moduleContext.addSymbolEntry(id, memoryData, startLoc, true);
3444}
3445
3446// Parse a format string and build operations for FIRRTL "special"
3447// substitutions. Set `formatStringResult` to the validated format string and
3448// `operands` to the list of actual operands.
3449ParseResult FIRStmtParser::parseFormatString(SMLoc formatStringLoc,
3450 StringRef formatString,
3451 ArrayRef<Value> specOperands,
3452 StringAttr &formatStringResult,
3453 SmallVectorImpl<Value> &operands) {
3454 // For FIRRTL versions < 5.0.0, don't process special substitutions
3455 if (version < FIRVersion(5, 0, 0)) {
3456 operands.append(specOperands.begin(), specOperands.end());
3457 formatStringResult =
3458 builder.getStringAttr(FIRToken::getStringValue(formatString));
3459 return success();
3460 }
3461
3462 // Use the utility function to parse the format string
3463 auto loc = translateLocation(formatStringLoc);
3465 builder, loc, FIRToken::getStringValue(formatString), specOperands,
3466 formatStringResult, operands);
3467 return result;
3468}
3469
3470/// printf ::= 'printf(' exp exp StringLit exp* ')' name? info?
3471ParseResult FIRStmtParser::parsePrintf() {
3472 auto startTok = consumeToken(FIRToken::lp_printf);
3473
3474 Value clock, condition;
3475 StringRef formatString;
3476 if (parseExp(clock, "expected clock expression in printf") ||
3477 parseToken(FIRToken::comma, "expected ','") ||
3478 parseExp(condition, "expected condition in printf") ||
3479 parseToken(FIRToken::comma, "expected ','"))
3480 return failure();
3481
3482 auto formatStringLoc = getToken().getLoc();
3483 if (parseGetSpelling(formatString) ||
3484 parseToken(FIRToken::string, "expected format string in printf"))
3485 return failure();
3486
3487 SmallVector<Value, 4> specOperands;
3488 while (consumeIf(FIRToken::comma)) {
3489 specOperands.push_back({});
3490 if (parseExp(specOperands.back(), "expected operand in printf"))
3491 return failure();
3492 }
3493
3494 StringAttr name;
3495 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3496 parseOptionalName(name) || parseOptionalInfo())
3497 return failure();
3498
3499 locationProcessor.setLoc(startTok.getLoc());
3500
3501 StringAttr formatStrUnescaped;
3502 SmallVector<Value> operands;
3503 if (parseFormatString(formatStringLoc, formatString, specOperands,
3504 formatStrUnescaped, operands))
3505 return failure();
3506
3507 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3508 name);
3509 return success();
3510}
3511
3512/// fprintf ::= 'fprintf(' exp exp StringLit StringLit exp* ')' name? info?
3513ParseResult FIRStmtParser::parseFPrintf() {
3514 if (requireFeature({6, 0, 0}, "fprintf"))
3515 return failure();
3516 auto startTok = consumeToken(FIRToken::lp_fprintf);
3517
3518 Value clock, condition;
3519 StringRef outputFile, formatString;
3520 if (parseExp(clock, "expected clock expression in fprintf") ||
3521 parseToken(FIRToken::comma, "expected ','") ||
3522 parseExp(condition, "expected condition in fprintf") ||
3523 parseToken(FIRToken::comma, "expected ','"))
3524 return failure();
3525
3526 auto outputFileLoc = getToken().getLoc();
3527 if (parseGetSpelling(outputFile) ||
3528 parseToken(FIRToken::string, "expected output file in fprintf"))
3529 return failure();
3530
3531 SmallVector<Value, 4> outputFileSpecOperands;
3532 while (consumeIf(FIRToken::comma)) {
3533 // Stop parsing operands when we see the format string.
3534 if (getToken().getKind() == FIRToken::string)
3535 break;
3536 outputFileSpecOperands.push_back({});
3537 if (parseExp(outputFileSpecOperands.back(), "expected operand in fprintf"))
3538 return failure();
3539 }
3540
3541 auto formatStringLoc = getToken().getLoc();
3542 if (parseGetSpelling(formatString) ||
3543 parseToken(FIRToken::string, "expected format string in printf"))
3544 return failure();
3545
3546 SmallVector<Value, 4> specOperands;
3547 while (consumeIf(FIRToken::comma)) {
3548 specOperands.push_back({});
3549 if (parseExp(specOperands.back(), "expected operand in fprintf"))
3550 return failure();
3551 }
3552
3553 StringAttr name;
3554 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3555 parseOptionalName(name) || parseOptionalInfo())
3556 return failure();
3557
3558 locationProcessor.setLoc(startTok.getLoc());
3559
3560 StringAttr outputFileNameStrUnescaped;
3561 SmallVector<Value> outputFileOperands;
3562 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3563 outputFileNameStrUnescaped, outputFileOperands))
3564 return failure();
3565
3566 StringAttr formatStrUnescaped;
3567 SmallVector<Value> operands;
3568 if (parseFormatString(formatStringLoc, formatString, specOperands,
3569 formatStrUnescaped, operands))
3570 return failure();
3571
3572 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3573 outputFileOperands, formatStrUnescaped, operands, name);
3574 return success();
3575}
3576
3577/// fflush ::= 'fflush(' exp exp (StringLit exp*)? ')' info?
3578ParseResult FIRStmtParser::parseFFlush() {
3579 if (requireFeature({6, 0, 0}, "fflush"))
3580 return failure();
3581
3582 auto startTok = consumeToken(FIRToken::lp_fflush);
3583
3584 Value clock, condition;
3585 if (parseExp(clock, "expected clock expression in 'fflush'") ||
3586 parseToken(FIRToken::comma, "expected ','") ||
3587 parseExp(condition, "expected condition in 'fflush'"))
3588 return failure();
3589
3590 locationProcessor.setLoc(startTok.getLoc());
3591 StringAttr outputFileNameStrUnescaped;
3592 SmallVector<Value> outputFileOperands;
3593 // Parse file name if present.
3594 if (consumeIf(FIRToken::comma)) {
3595 SmallVector<Value, 4> outputFileSpecOperands;
3596 auto outputFileLoc = getToken().getLoc();
3597 StringRef outputFile;
3598 if (parseGetSpelling(outputFile) ||
3599 parseToken(FIRToken::string, "expected output file in fflush"))
3600 return failure();
3601
3602 while (consumeIf(FIRToken::comma)) {
3603 outputFileSpecOperands.push_back({});
3604 if (parseExp(outputFileSpecOperands.back(), "expected operand in fflush"))
3605 return failure();
3606 }
3607
3608 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3609 outputFileNameStrUnescaped, outputFileOperands))
3610 return failure();
3611 }
3612
3613 if (parseToken(FIRToken::r_paren, "expected ')' in 'fflush'") ||
3614 parseOptionalInfo())
3615 return failure();
3616
3617 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3618 outputFileOperands);
3619 return success();
3620}
3621
3622/// skip ::= 'skip' info?
3623ParseResult FIRStmtParser::parseSkip() {
3624 auto startTok = consumeToken(FIRToken::kw_skip);
3625
3626 // If this was actually the start of a connect or something else handle
3627 // that.
3628 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3629 return *isExpr;
3630
3631 if (parseOptionalInfo())
3632 return failure();
3633
3634 locationProcessor.setLoc(startTok.getLoc());
3635 SkipOp::create(builder);
3636 return success();
3637}
3638
3639/// stop ::= 'stop(' exp exp intLit ')' info?
3640ParseResult FIRStmtParser::parseStop() {
3641 auto startTok = consumeToken(FIRToken::lp_stop);
3642
3643 Value clock, condition;
3644 int64_t exitCode;
3645 StringAttr name;
3646 if (parseExp(clock, "expected clock expression in 'stop'") ||
3647 parseToken(FIRToken::comma, "expected ','") ||
3648 parseExp(condition, "expected condition in 'stop'") ||
3649 parseToken(FIRToken::comma, "expected ','") ||
3650 parseIntLit(exitCode, "expected exit code in 'stop'") ||
3651 parseToken(FIRToken::r_paren, "expected ')' in 'stop'") ||
3652 parseOptionalName(name) || parseOptionalInfo())
3653 return failure();
3654
3655 locationProcessor.setLoc(startTok.getLoc());
3656 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3657 name);
3658 return success();
3659}
3660
3661/// assert ::= 'assert(' exp exp exp StringLit exp*')' info?
3662ParseResult FIRStmtParser::parseAssert() {
3663 auto startTok = consumeToken(FIRToken::lp_assert);
3664
3665 Value clock, predicate, enable;
3666 StringRef formatString;
3667 StringAttr name;
3668 if (parseExp(clock, "expected clock expression in 'assert'") ||
3669 parseToken(FIRToken::comma, "expected ','") ||
3670 parseExp(predicate, "expected predicate in 'assert'") ||
3671 parseToken(FIRToken::comma, "expected ','") ||
3672 parseExp(enable, "expected enable in 'assert'") ||
3673 parseToken(FIRToken::comma, "expected ','") ||
3674 parseGetSpelling(formatString) ||
3675 parseToken(FIRToken::string, "expected format string in 'assert'"))
3676 return failure();
3677
3678 SmallVector<Value, 4> operands;
3679 while (!consumeIf(FIRToken::r_paren)) {
3680 operands.push_back({});
3681 if (parseToken(FIRToken::comma, "expected ','") ||
3682 parseExp(operands.back(), "expected operand in 'assert'"))
3683 return failure();
3684 }
3685
3686 if (parseOptionalName(name) || parseOptionalInfo())
3687 return failure();
3688
3689 locationProcessor.setLoc(startTok.getLoc());
3690 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3691 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3692 operands, name.getValue());
3693 return success();
3694}
3695
3696/// assume ::= 'assume(' exp exp exp StringLit exp* ')' info?
3697ParseResult FIRStmtParser::parseAssume() {
3698 auto startTok = consumeToken(FIRToken::lp_assume);
3699
3700 Value clock, predicate, enable;
3701 StringRef formatString;
3702 StringAttr name;
3703 if (parseExp(clock, "expected clock expression in 'assume'") ||
3704 parseToken(FIRToken::comma, "expected ','") ||
3705 parseExp(predicate, "expected predicate in 'assume'") ||
3706 parseToken(FIRToken::comma, "expected ','") ||
3707 parseExp(enable, "expected enable in 'assume'") ||
3708 parseToken(FIRToken::comma, "expected ','") ||
3709 parseGetSpelling(formatString) ||
3710 parseToken(FIRToken::string, "expected format string in 'assume'"))
3711 return failure();
3712
3713 SmallVector<Value, 4> operands;
3714 while (!consumeIf(FIRToken::r_paren)) {
3715 operands.push_back({});
3716 if (parseToken(FIRToken::comma, "expected ','") ||
3717 parseExp(operands.back(), "expected operand in 'assume'"))
3718 return failure();
3719 }
3720
3721 if (parseOptionalName(name) || parseOptionalInfo())
3722 return failure();
3723
3724 locationProcessor.setLoc(startTok.getLoc());
3725 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3726 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3727 operands, name.getValue());
3728 return success();
3729}
3730
3731/// cover ::= 'cover(' exp exp exp StringLit ')' info?
3732ParseResult FIRStmtParser::parseCover() {
3733 auto startTok = consumeToken(FIRToken::lp_cover);
3734
3735 Value clock, predicate, enable;
3736 StringRef message;
3737 StringAttr name;
3738 if (parseExp(clock, "expected clock expression in 'cover'") ||
3739 parseToken(FIRToken::comma, "expected ','") ||
3740 parseExp(predicate, "expected predicate in 'cover'") ||
3741 parseToken(FIRToken::comma, "expected ','") ||
3742 parseExp(enable, "expected enable in 'cover'") ||
3743 parseToken(FIRToken::comma, "expected ','") ||
3744 parseGetSpelling(message) ||
3745 parseToken(FIRToken::string, "expected message in 'cover'") ||
3746 parseToken(FIRToken::r_paren, "expected ')' in 'cover'") ||
3747 parseOptionalName(name) || parseOptionalInfo())
3748 return failure();
3749
3750 locationProcessor.setLoc(startTok.getLoc());
3751 auto messageUnescaped = FIRToken::getStringValue(message);
3752 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3753 ValueRange{}, name.getValue());
3754 return success();
3755}
3756
3757/// when ::= 'when' exp ':' info? suite? ('else' ( when | ':' info? suite?)
3758/// )? suite ::= simple_stmt | INDENT simple_stmt+ DEDENT
3759ParseResult FIRStmtParser::parseWhen(unsigned whenIndent) {
3760 auto startTok = consumeToken(FIRToken::kw_when);
3761
3762 // If this was actually the start of a connect or something else handle
3763 // that.
3764 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3765 return *isExpr;
3766
3767 Value condition;
3768 if (parseExp(condition, "expected condition in 'when'") ||
3769 parseToken(FIRToken::colon, "expected ':' in when") ||
3770 parseOptionalInfo())
3771 return failure();
3772
3773 locationProcessor.setLoc(startTok.getLoc());
3774 // Create the IR representation for the when.
3775 auto whenStmt = WhenOp::create(builder, condition, /*createElse*/ false);
3776
3777 // Parse the 'then' body into the 'then' region.
3778 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3779 return failure();
3780
3781 // If the else is present, handle it otherwise we're done.
3782 if (getToken().isNot(FIRToken::kw_else))
3783 return success();
3784
3785 // If the 'else' is less indented than the when, then it must belong to some
3786 // containing 'when'.
3787 auto elseIndent = getIndentation();
3788 if (elseIndent && *elseIndent < whenIndent)
3789 return success();
3790
3791 consumeToken(FIRToken::kw_else);
3792
3793 // Create an else block to parse into.
3794 whenStmt.createElseRegion();
3795
3796 // If we have the ':' form, then handle it.
3797
3798 // Syntactic shorthand 'else when'. This uses the same indentation level as
3799 // the outer 'when'.
3800 if (getToken().is(FIRToken::kw_when)) {
3801 // We create a sub parser for the else block.
3802 auto subParser = std::make_unique<FIRStmtParser>(
3803 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3804 version, layerSym);
3805
3806 return subParser->parseSimpleStmt(whenIndent);
3807 }
3808
3809 // Parse the 'else' body into the 'else' region.
3810 LocationAttr elseLoc; // ignore the else locator.
3811 if (parseToken(FIRToken::colon, "expected ':' after 'else'") ||
3812 parseOptionalInfoLocator(elseLoc) ||
3813 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3814 return failure();
3815
3816 // TODO(firrtl spec): There is no reason for the 'else :' grammar to take an
3817 // info. It doesn't appear to be generated either.
3818 return success();
3819}
3820
3821/// enum-exp ::= enum-type '(' Id ( ',' exp )? ')'
3822ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3823 auto startLoc = getToken().getLoc();
3824 locationProcessor.setLoc(startLoc);
3825 FIRRTLType type;
3826 if (parseEnumType(type))
3827 return failure();
3828
3829 // Check that the input type is a legal enumeration.
3830 auto enumType = type_dyn_cast<FEnumType>(type);
3831 if (!enumType)
3832 return emitError(startLoc,
3833 "expected enumeration type in enumeration expression");
3834
3835 StringRef tag;
3836 if (parseToken(FIRToken::l_paren, "expected '(' in enumeration expression") ||
3837 parseId(tag, "expected enumeration tag"))
3838 return failure();
3839
3840 Value input;
3841 if (consumeIf(FIRToken::r_paren)) {
3842 // If the payload is not specified, we create a 0 bit unsigned integer
3843 // constant.
3844 auto type = IntType::get(builder.getContext(), false, 0, true);
3845 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3846 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0, false));
3847 input = ConstantOp::create(builder, type, attr);
3848 } else {
3849 // Otherwise we parse an expression.
3850 if (parseToken(FIRToken::comma, "expected ','") ||
3851 parseExp(input, "expected expression in enumeration value") ||
3852 parseToken(FIRToken::r_paren, "expected closing ')'"))
3853 return failure();
3854 }
3855
3856 value = FEnumCreateOp::create(builder, enumType, tag, input);
3857 return success();
3858}
3859
3860/// match ::= 'match' exp ':' info?
3861/// (INDENT ( Id ( '(' Id ')' )? ':'
3862/// (INDENT simple_stmt* DEDENT )?
3863/// )* DEDENT)?
3864ParseResult FIRStmtParser::parseMatch(unsigned matchIndent) {
3865 auto startTok = consumeToken(FIRToken::kw_match);
3866
3867 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3868 return *isExpr;
3869
3870 Value input;
3871 if (parseExp(input, "expected expression in 'match'") ||
3872 parseToken(FIRToken::colon, "expected ':' in 'match'") ||
3873 parseOptionalInfo())
3874 return failure();
3875
3876 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3877 if (!enumType)
3878 return mlir::emitError(
3879 input.getLoc(),
3880 "expected enumeration type for 'match' statement, but got ")
3881 << input.getType();
3882
3883 locationProcessor.setLoc(startTok.getLoc());
3884
3885 SmallVector<Attribute> tags;
3886 SmallVector<std::unique_ptr<Region>> regions;
3887 while (true) {
3888 auto tagLoc = getToken().getLoc();
3889
3890 // Only consume the keyword if the indentation is correct.
3891 auto caseIndent = getIndentation();
3892 if (!caseIndent || *caseIndent <= matchIndent)
3893 break;
3894
3895 // Parse the tag.
3896 StringRef tagSpelling;
3897 if (parseId(tagSpelling, "expected enumeration tag in match statement"))
3898 return failure();
3899 auto tagIndex = enumType.getElementIndex(tagSpelling);
3900 if (!tagIndex)
3901 return emitError(tagLoc, "tag ")
3902 << tagSpelling << " not a member of enumeration " << enumType;
3903 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3904 tags.push_back(tag);
3905
3906 // Add a new case to the match operation.
3907 auto *caseBlock = &regions.emplace_back(new Region)->emplaceBlock();
3908
3909 // Declarations are scoped to the case.
3910 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3911
3912 // After parsing the region, we can release any new entries in
3913 // unbundledValues since the symbol table entries that refer to them will be
3914 // gone.
3915 UnbundledValueRestorer x(moduleContext.unbundledValues);
3916
3917 // Parse the argument.
3918 if (consumeIf(FIRToken::l_paren)) {
3919 StringAttr identifier;
3920 if (parseId(identifier, "expected identifier for 'case' binding"))
3921 return failure();
3922
3923 // Add an argument to the block.
3924 auto dataType = enumType.getElementType(*tagIndex);
3925 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3926
3927 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3928 startTok.getLoc()))
3929 return failure();
3930
3931 if (parseToken(FIRToken::r_paren, "expected ')' in match statement case"))
3932 return failure();
3933
3934 } else {
3935 auto dataType = IntType::get(builder.getContext(), false, 0);
3936 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3937 }
3938
3939 if (parseToken(FIRToken::colon, "expected ':' in match statement case"))
3940 return failure();
3941
3942 // Parse a block of statements that are indented more than the case.
3943 auto subParser = std::make_unique<FIRStmtParser>(
3944 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3945 layerSym);
3946 if (subParser->parseSimpleStmtBlock(*caseIndent))
3947 return failure();
3948 }
3949
3950 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3951 return success();
3952}
3953
3954/// domain_exp ::= id
3955/// domain_exp ::= domain_exp '.' id
3956/// domain_exp ::= domain_exp '[' int ']'
3957ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3958 auto loc = getToken().getLoc();
3959 SymbolValueEntry entry;
3960 StringRef id;
3961 if (parseId(id, "expected domain expression") ||
3962 moduleContext.lookupSymbolEntry(entry, id, loc))
3963 return failure();
3964
3965 if (moduleContext.resolveSymbolEntry(result, entry, loc, false)) {
3966 StringRef field;
3967 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
3968 parseFieldId(field, "expected field name") ||
3969 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3970 return failure();
3971 }
3972
3973 if (parseOptionalExpPostscript(result, /*allowDynamic=*/false))
3974 return failure();
3975
3976 auto type = result.getType();
3977 if (!type_isa<DomainType>(type))
3978 return emitError(loc) << "expected domain-type expression, got " << type;
3979
3980 return success();
3981}
3982
3983/// ref_expr ::= 'probe' '(' static_reference ')'
3984/// ::= 'rwprobe' '(' static_reference ')'
3985/// ::= id
3986/// ::= ref_expr '.' id
3987/// ::= ref_expr '[' int ']'
3988// NOLINTNEXTLINE(misc-no-recursion)
3989ParseResult FIRStmtParser::parseRefExp(Value &result, const Twine &message) {
3990 auto token = getToken().getKind();
3991 if (token == FIRToken::lp_probe)
3992 return failure(parseProbe(result) ||
3993 parseOptionalExpPostscript(result, /*allowDynamic=*/false));
3994 if (token == FIRToken::lp_rwprobe)
3995 return failure(parseRWProbe(result) ||
3996 parseOptionalExpPostscript(result, /*allowDynamic=*/false));
3997
3998 // Default to parsing as static reference expression.
3999 // Don't check token kind, we need to support literal_identifier and keywords,
4000 // let parseId handle this.
4001 return parseStaticRefExp(result, message);
4002}
4003
4004/// static_reference ::= id
4005/// ::= static_reference '.' id
4006/// ::= static_reference '[' int ']'
4007// NOLINTNEXTLINE(misc-no-recursion)
4008ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
4009 const Twine &message) {
4010 auto parseIdOrInstance = [&]() -> ParseResult {
4011 StringRef id;
4012 auto loc = getToken().getLoc();
4013 SymbolValueEntry symtabEntry;
4014 if (parseId(id, message) ||
4015 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
4016 return failure();
4017
4018 // If we looked up a normal value, then we're done.
4019 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
4020 return success();
4021
4022 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
4023
4024 // Handle the normal "instance.x" reference.
4025 StringRef fieldName;
4026 return failure(
4027 parseToken(FIRToken::period, "expected '.' in field reference") ||
4028 parseFieldId(fieldName, "expected field name") ||
4029 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
4030 };
4031 return failure(parseIdOrInstance() ||
4032 parseOptionalExpPostscript(result, false));
4033}
4034/// static_reference ::= id
4035/// ::= static_reference '.' id
4036/// ::= static_reference '[' int ']'
4037/// Populate `refResult` with rwprobe "root" and parsed indexing.
4038/// Root is base-type target, and will be block argument or forceable.
4039/// Also set `Type`, so we can handle const-ness while visiting.
4040/// If root is an unbundled entry, replace with bounce wire and update
4041/// the unbundled entry to point to this for future users.
4042// NOLINTNEXTLINE(misc-no-recursion)
4043ParseResult FIRStmtParser::parseRWProbeStaticRefExp(FieldRef &refResult,
4044 Type &type,
4045 const Twine &message) {
4046 auto loc = getToken().getLoc();
4047
4048 StringRef id;
4049 SymbolValueEntry symtabEntry;
4050 if (parseId(id, message) ||
4051 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
4052 return failure();
4053
4054 // Three kinds of rwprobe targets:
4055 // 1. Instance result. Replace with a forceable wire, handle as (2).
4056 // 2. Forceable declaration.
4057 // 3. BlockArgument.
4058
4059 // We use inner symbols for all.
4060
4061 // Figure out what we have, and parse indexing.
4062 Value result;
4063 if (auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
4064 // This means we have an instance.
4065 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
4066
4067 StringRef fieldName;
4068 auto loc = getToken().getLoc();
4069 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
4070 parseFieldId(fieldName, "expected field name"))
4071 return failure();
4072
4073 // Find unbundled entry for the specified result/port.
4074 // Get a reference to it--as we may update it (!!).
4075 auto fieldAttr = StringAttr::get(getContext(), fieldName);
4076 for (auto &elt : ubEntry) {
4077 if (elt.first == fieldAttr) {
4078 // Grab the unbundled entry /by reference/ so we can update it with the
4079 // new forceable wire we insert (if not already done).
4080 auto &instResult = elt.second;
4081
4082 // If it's already forceable, use that.
4083 auto *defining = instResult.getDefiningOp();
4084 assert(defining);
4085 if (isa<WireOp>(defining)) {
4086 result = instResult;
4087 break;
4088 }
4089
4090 // Otherwise, replace with bounce wire.
4091 auto type = instResult.getType();
4092
4093 // Create bounce wire for the instance result.
4094 // This may be an open aggregate, or other non-base type.
4095 auto annotations = getConstants().emptyArrayAttr;
4096 StringAttr sym = {};
4097 SmallString<64> name;
4098 (id + "_" + fieldName + "_bounce").toVector(name);
4099 locationProcessor.setLoc(loc);
4100 OpBuilder::InsertionGuard guard(builder);
4101 builder.setInsertionPoint(defining);
4102 auto bounce =
4103 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
4104 annotations, sym);
4105 auto bounceVal = bounce.getDataRaw();
4106
4107 // Replace instance result with reads from bounce wire.
4108 instResult.replaceAllUsesWith(bounceVal);
4109
4110 // Connect to/from the result per flow.
4111 builder.setInsertionPointAfter(defining);
4112 if (foldFlow(instResult) == Flow::Source)
4113 emitConnect(builder, bounceVal, instResult,
4114 getConstants().options.warnOnTruncation);
4115 else
4116 emitConnect(builder, instResult, bounceVal,
4117 getConstants().options.warnOnTruncation);
4118 // Set the parse result AND update `instResult` which is a reference to
4119 // the unbundled entry for the instance result, so that future uses also
4120 // find this new wire.
4121 result = instResult = bounce.getDataRaw();
4122 break;
4123 }
4124 }
4125
4126 if (!result) {
4127 emitError(loc, "use of invalid field name '")
4128 << fieldName << "' on bundle value";
4129 return failure();
4130 }
4131 } else {
4132 // This target can be a port or a regular value.
4133 result = cast<Value>(symtabEntry);
4134 }
4135
4136 assert(result);
4137 assert(isa<BlockArgument>(result) ||
4138 result.getDefiningOp<hw::InnerSymbolOpInterface>());
4139
4140 // We have our root value, we just need to parse the field id.
4141 // Build up the FieldRef as processing indexing expressions, and
4142 // compute the type so that we know the const-ness of the final expression.
4143 refResult = FieldRef(result, 0);
4144 type = result.getType();
4145 while (true) {
4146 if (consumeIf(FIRToken::period)) {
4147 SmallVector<StringRef, 3> fields;
4148 if (parseFieldIdSeq(fields, "expected field name"))
4149 return failure();
4150 for (auto fieldName : fields) {
4151 if (auto bundle = type_dyn_cast<BundleType>(type)) {
4152 if (auto index = bundle.getElementIndex(fieldName)) {
4153 refResult = refResult.getSubField(bundle.getFieldID(*index));
4154 type = bundle.getElementTypePreservingConst(*index);
4155 continue;
4156 }
4157 } else if (auto bundle = type_dyn_cast<OpenBundleType>(type)) {
4158 if (auto index = bundle.getElementIndex(fieldName)) {
4159 refResult = refResult.getSubField(bundle.getFieldID(*index));
4160 type = bundle.getElementTypePreservingConst(*index);
4161 continue;
4162 }
4163 } else {
4164 return emitError(loc, "subfield requires bundle operand")
4165 << "got " << type << "\n";
4166 }
4167 return emitError(loc,
4168 "unknown field '" + fieldName + "' in bundle type ")
4169 << type;
4170 }
4171 continue;
4172 }
4173 if (consumeIf(FIRToken::l_square)) {
4174 auto loc = getToken().getLoc();
4175 int32_t index;
4176 if (parseIntLit(index, "expected index") ||
4177 parseToken(FIRToken::r_square, "expected ']'"))
4178 return failure();
4179
4180 if (index < 0)
4181 return emitError(loc, "invalid index specifier");
4182
4183 if (auto vector = type_dyn_cast<FVectorType>(type)) {
4184 if ((unsigned)index < vector.getNumElements()) {
4185 refResult = refResult.getSubField(vector.getFieldID(index));
4186 type = vector.getElementTypePreservingConst();
4187 continue;
4188 }
4189 } else if (auto vector = type_dyn_cast<OpenVectorType>(type)) {
4190 if ((unsigned)index < vector.getNumElements()) {
4191 refResult = refResult.getSubField(vector.getFieldID(index));
4192 type = vector.getElementTypePreservingConst();
4193 continue;
4194 }
4195 } else {
4196 return emitError(loc, "subindex requires vector operand");
4197 }
4198 return emitError(loc, "out of range index '")
4199 << index << "' for vector type " << type;
4200 }
4201 return success();
4202 }
4203}
4204
4205/// intrinsic_expr ::= 'intrinsic(' Id (params)? ':' type exp* ')'
4206/// intrinsic_stmt ::= 'intrinsic(' Id (params)? (':' type )? exp* ')'
4207ParseResult FIRStmtParser::parseIntrinsic(Value &result, bool isStatement) {
4208 auto startTok = consumeToken(FIRToken::lp_intrinsic);
4209 StringRef intrinsic;
4210 ArrayAttr parameters;
4211 FIRRTLType type;
4212
4213 if (parseId(intrinsic, "expected intrinsic identifier") ||
4214 parseOptionalParams(parameters))
4215 return failure();
4216
4217 if (consumeIf(FIRToken::colon)) {
4218 if (parseType(type, "expected intrinsic return type"))
4219 return failure();
4220 } else if (!isStatement)
4221 return emitError("expected ':' in intrinsic expression");
4222
4223 SmallVector<Value> operands;
4224 auto loc = startTok.getLoc();
4225 if (consumeIf(FIRToken::comma)) {
4226 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4227 Value operand;
4228 if (parseExp(operand, "expected operand in intrinsic"))
4229 return failure();
4230 operands.push_back(operand);
4231 locationProcessor.setLoc(loc);
4232 return success();
4233 }))
4234 return failure();
4235 } else {
4236 if (parseToken(FIRToken::r_paren, "expected ')' in intrinsic"))
4237 return failure();
4238 }
4239
4240 if (isStatement)
4241 if (parseOptionalInfo())
4242 return failure();
4243
4244 locationProcessor.setLoc(loc);
4245
4246 auto op = GenericIntrinsicOp::create(
4247 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
4248 if (type)
4249 result = op.getResult();
4250 return success();
4251}
4252
4253/// params ::= '<' param','* '>'
4254ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
4255 if (!consumeIf(FIRToken::less))
4256 return success();
4257
4258 SmallVector<Attribute, 8> parameters;
4259 SmallPtrSet<StringAttr, 8> seen;
4260 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
4261 StringAttr name;
4262 Attribute value;
4263 SMLoc loc;
4264 if (parseParameter(name, value, loc))
4265 return failure();
4266 auto typedValue = dyn_cast<TypedAttr>(value);
4267 if (!typedValue)
4268 return emitError(loc)
4269 << "invalid value for parameter '" << name.getValue() << "'";
4270 if (!seen.insert(name).second)
4271 return emitError(loc, "redefinition of parameter '" +
4272 name.getValue() + "'");
4273 parameters.push_back(ParamDeclAttr::get(name, typedValue));
4274 return success();
4275 }))
4276 return failure();
4277
4278 resultParameters = ArrayAttr::get(getContext(), parameters);
4279 return success();
4280}
4281
4282/// path ::= 'path(' StringLit ')'
4283// NOLINTNEXTLINE(misc-no-recursion)
4284ParseResult FIRStmtParser::parsePathExp(Value &result) {
4285 auto startTok = consumeToken(FIRToken::lp_path);
4286 locationProcessor.setLoc(startTok.getLoc());
4287 StringRef target;
4288 if (parseGetSpelling(target) ||
4289 parseToken(FIRToken::string,
4290 "expected target string in path expression") ||
4291 parseToken(FIRToken::r_paren, "expected ')' in path expression"))
4292 return failure();
4293 result = UnresolvedPathOp::create(
4294 builder, StringAttr::get(getContext(), FIRToken::getStringValue(target)));
4295 return success();
4296}
4297
4298/// domain_instantiation ::= 'domain' id 'of' id ('(' exp (',' exp)* ')')? info?
4299ParseResult FIRStmtParser::parseDomainInstantiation() {
4300 auto startTok = consumeToken(FIRToken::kw_domain);
4301 auto startLoc = startTok.getLoc();
4302
4303 // If this was actually the start of a connect or something else handle that.
4304 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4305 return *isExpr;
4306
4307 locationProcessor.setLoc(startTok.getLoc());
4308
4309 StringAttr instanceName;
4310 StringAttr domainKind;
4311
4312 if (requireFeature(missingSpecFIRVersion, "domains", startLoc) ||
4313 parseId(instanceName, "expected domain instance name") ||
4314 parseToken(FIRToken::kw_of, "expected 'of' after domain instance name") ||
4315 parseId(domainKind, "expected domain type name"))
4316 return failure();
4317
4318 // Create the domain instance
4319 // Look up the domain to get its fields
4320 const auto &domainMap = getConstants().domainMap;
4321 auto lookup = domainMap.find(domainKind.getValue());
4322 if (lookup == domainMap.end())
4323 return emitError(startTok.getLoc())
4324 << "unknown domain '" << domainKind.getValue() << "'";
4325
4326 auto domainType = DomainType::getFromDomainOp(lookup->second);
4327 auto fields = domainType.getFields();
4328
4329 // Parse optional field values
4330 SmallVector<Value> fieldValues;
4331 if (consumeIf(FIRToken::l_paren)) {
4332 // Parse comma-separated list of expressions
4333 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
4334 if (fieldValues.size() >= fields.size())
4335 return emitError(getToken().getLoc())
4336 << "too many field values for domain '"
4337 << domainKind.getValue() << "': expected " << fields.size();
4338
4339 Value value;
4340 if (parseExp(value, "expected field value expression"))
4341 return failure();
4342
4343 value = emitImplicitAnyRefCast(
4344 value,
4345 cast<DomainFieldAttr>(fields[fieldValues.size()]).getType());
4346
4347 fieldValues.push_back(value);
4348 return success();
4349 }))
4350 return failure();
4351 }
4352
4353 if (parseOptionalInfo())
4354 return failure();
4355
4356 if (fieldValues.size() < fields.size())
4357 return emitError(startLoc)
4358 << "not enough field values for domain '" << domainKind.getValue()
4359 << "': expected " << fields.size() << ", got " << fieldValues.size();
4360
4361 locationProcessor.setLoc(startLoc);
4362 auto result =
4363 DomainCreateOp::create(builder, domainType, instanceName, fieldValues);
4364
4365 // Add to symbol table
4366 return moduleContext.addSymbolEntry(instanceName.getValue(), result,
4367 startTok.getLoc());
4368}
4369
4370/// domain_define ::= 'domain_define' domain_exp '=' domain_exp info?
4371ParseResult FIRStmtParser::parseDomainDefine() {
4372 auto startTok = consumeToken(FIRToken::kw_domain_define);
4373 auto startLoc = startTok.getLoc();
4374 locationProcessor.setLoc(startLoc);
4375
4376 Value dest, src;
4377 if (requireFeature(missingSpecFIRVersion, "domains", startLoc) ||
4378 parseDomainExp(dest) || parseToken(FIRToken::equal, "expected '='") ||
4379 parseDomainExp(src) || parseOptionalInfo())
4380 return failure();
4381
4382 emitConnect(builder, dest, src, getConstants().options.warnOnTruncation);
4383 return success();
4384}
4385
4386/// define ::= 'define' static_reference '=' ref_expr info?
4387ParseResult FIRStmtParser::parseRefDefine() {
4388 auto startTok = consumeToken(FIRToken::kw_define);
4389
4390 Value src, target;
4391 if (parseStaticRefExp(target,
4392 "expected static reference expression in 'define'") ||
4393 parseToken(FIRToken::equal,
4394 "expected '=' after define reference expression") ||
4395 parseRefExp(src, "expected reference expression in 'define'") ||
4396 parseOptionalInfo())
4397 return failure();
4398
4399 // Check reference expressions are of reference type.
4400 if (!type_isa<RefType>(target.getType()))
4401 return emitError(startTok.getLoc(), "expected reference-type expression in "
4402 "'define' target (LHS), got ")
4403 << target.getType();
4404 if (!type_isa<RefType>(src.getType()))
4405 return emitError(startTok.getLoc(), "expected reference-type expression in "
4406 "'define' source (RHS), got ")
4407 << src.getType();
4408
4409 // static_reference doesn't differentiate which can be ref.sub'd, so check
4410 // this explicitly:
4411 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4412 return emitError(startTok.getLoc(),
4413 "cannot define into a sub-element of a reference");
4414
4415 locationProcessor.setLoc(startTok.getLoc());
4416
4417 if (!areTypesRefCastable(target.getType(), src.getType()))
4418 return emitError(startTok.getLoc(), "cannot define reference of type ")
4419 << target.getType() << " with incompatible reference of type "
4420 << src.getType();
4421
4422 emitConnect(builder, target, src, getConstants().options.warnOnTruncation);
4423
4424 return success();
4425}
4426
4427/// read ::= 'read' '(' ref_expr ')'
4428ParseResult FIRStmtParser::parseRefRead(Value &result) {
4429 auto startTok = consumeToken(FIRToken::lp_read);
4430
4431 Value ref;
4432 if (parseRefExp(ref, "expected reference expression in 'read'") ||
4433 parseToken(FIRToken::r_paren, "expected ')' in 'read'"))
4434 return failure();
4435
4436 locationProcessor.setLoc(startTok.getLoc());
4437
4438 // Check argument is a ref-type value.
4439 if (!type_isa<RefType>(ref.getType()))
4440 return emitError(startTok.getLoc(),
4441 "expected reference-type expression in 'read', got ")
4442 << ref.getType();
4443
4444 result = RefResolveOp::create(builder, ref);
4445
4446 return success();
4447}
4448
4449/// probe ::= 'probe' '(' static_ref ')'
4450ParseResult FIRStmtParser::parseProbe(Value &result) {
4451 auto startTok = consumeToken(FIRToken::lp_probe);
4452
4453 Value staticRef;
4454 if (parseStaticRefExp(staticRef,
4455 "expected static reference expression in 'probe'") ||
4456 parseToken(FIRToken::r_paren, "expected ')' in 'probe'"))
4457 return failure();
4458
4459 locationProcessor.setLoc(startTok.getLoc());
4460
4461 // Check probe expression is base-type.
4462 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4463 return emitError(startTok.getLoc(),
4464 "expected base-type expression in 'probe', got ")
4465 << staticRef.getType();
4466
4467 // Check for other unsupported reference sources.
4468 // TODO: Add to ref.send verifier / inferReturnTypes.
4469 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4470 MemoryDebugPortOp, MemoryPortAccessOp>(
4471 staticRef.getDefiningOp()))
4472 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4473
4474 result = RefSendOp::create(builder, staticRef);
4475
4476 return success();
4477}
4478
4479/// rwprobe ::= 'rwprobe' '(' static_ref ')'
4480ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4481 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4482
4483 FieldRef staticRef;
4484 Type parsedTargetType;
4485 if (parseRWProbeStaticRefExp(
4486 staticRef, parsedTargetType,
4487 "expected static reference expression in 'rwprobe'") ||
4488 parseToken(FIRToken::r_paren, "expected ')' in 'rwprobe'"))
4489 return failure();
4490
4491 locationProcessor.setLoc(startTok.getLoc());
4492
4493 // Checks:
4494 // Not public port (verifier)
4495
4496 // Check probe expression is base-type.
4497 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4498 if (!targetType)
4499 return emitError(startTok.getLoc(),
4500 "expected base-type expression in 'rwprobe', got ")
4501 << parsedTargetType;
4502
4503 auto root = staticRef.getValue();
4504 auto *definingOp = root.getDefiningOp();
4505
4506 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4507 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4508 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4509
4510 auto forceableType = firrtl::detail::getForceableResultType(true, targetType);
4511 if (!forceableType)
4512 return emitError(startTok.getLoc(), "cannot force target of type ")
4513 << targetType;
4514
4515 // Create the operation with a placeholder reference and add to fixup list.
4516 auto op = RWProbeOp::create(builder, forceableType,
4517 getConstants().placeholderInnerRef);
4518 innerSymFixups.add(op, getTargetFor(staticRef));
4519 result = op;
4520 return success();
4521}
4522
4523/// force ::= 'force(' exp exp ref_expr exp ')' info?
4524ParseResult FIRStmtParser::parseRefForce() {
4525 auto startTok = consumeToken(FIRToken::lp_force);
4526
4527 Value clock, pred, dest, src;
4528 if (parseExp(clock, "expected clock expression in force") ||
4529 parseToken(FIRToken::comma, "expected ','") ||
4530 parseExp(pred, "expected predicate expression in force") ||
4531 parseToken(FIRToken::comma, "expected ','") ||
4532 parseRefExp(dest, "expected destination reference expression in force") ||
4533 parseToken(FIRToken::comma, "expected ','") ||
4534 parseExp(src, "expected source expression in force") ||
4535 parseToken(FIRToken::r_paren, "expected ')' in force") ||
4536 parseOptionalInfo())
4537 return failure();
4538
4539 // Check reference expression is of reference type.
4540 auto ref = type_dyn_cast<RefType>(dest.getType());
4541 if (!ref || !ref.getForceable())
4542 return emitError(
4543 startTok.getLoc(),
4544 "expected rwprobe-type expression for force destination, got ")
4545 << dest.getType();
4546 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4547 if (!srcBaseType)
4548 return emitError(startTok.getLoc(),
4549 "expected base-type for force source, got ")
4550 << src.getType();
4551 if (!srcBaseType.isPassive())
4552 return emitError(startTok.getLoc(),
4553 "expected passive value for force source, got ")
4554 << srcBaseType;
4555
4556 locationProcessor.setLoc(startTok.getLoc());
4557
4558 // Cast ref to accommodate uninferred sources.
4559 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4560 if (noConstSrcType != ref.getType()) {
4561 // Try to cast destination to rwprobe of source type (dropping const).
4562 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4563 if (areTypesRefCastable(compatibleRWProbe, ref))
4564 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4565 else
4566 return emitError(startTok.getLoc(), "incompatible force source of type ")
4567 << src.getType() << " cannot target destination "
4568 << dest.getType();
4569 }
4570
4571 RefForceOp::create(builder, clock, pred, dest, src);
4572
4573 return success();
4574}
4575
4576/// force_initial ::= 'force_initial(' ref_expr exp ')' info?
4577ParseResult FIRStmtParser::parseRefForceInitial() {
4578 auto startTok = consumeToken(FIRToken::lp_force_initial);
4579
4580 Value dest, src;
4581 if (parseRefExp(
4582 dest, "expected destination reference expression in force_initial") ||
4583 parseToken(FIRToken::comma, "expected ','") ||
4584 parseExp(src, "expected source expression in force_initial") ||
4585 parseToken(FIRToken::r_paren, "expected ')' in force_initial") ||
4586 parseOptionalInfo())
4587 return failure();
4588
4589 // Check reference expression is of reference type.
4590 auto ref = type_dyn_cast<RefType>(dest.getType());
4591 if (!ref || !ref.getForceable())
4592 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4593 "force_initial destination, got ")
4594 << dest.getType();
4595 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4596 if (!srcBaseType)
4597 return emitError(startTok.getLoc(),
4598 "expected base-type expression for force_initial "
4599 "source, got ")
4600 << src.getType();
4601 if (!srcBaseType.isPassive())
4602 return emitError(startTok.getLoc(),
4603 "expected passive value for force_initial source, got ")
4604 << srcBaseType;
4605
4606 locationProcessor.setLoc(startTok.getLoc());
4607
4608 // Cast ref to accommodate uninferred sources.
4609 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4610 if (noConstSrcType != ref.getType()) {
4611 // Try to cast destination to rwprobe of source type (dropping const).
4612 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4613 if (areTypesRefCastable(compatibleRWProbe, ref))
4614 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4615 else
4616 return emitError(startTok.getLoc(),
4617 "incompatible force_initial source of type ")
4618 << src.getType() << " cannot target destination "
4619 << dest.getType();
4620 }
4621
4622 auto value = APInt::getAllOnes(1);
4623 auto type = UIntType::get(builder.getContext(), 1);
4624 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4625 value.getBitWidth(),
4626 IntegerType::Unsigned),
4627 value);
4628 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4629 RefForceInitialOp::create(builder, pred, dest, src);
4630
4631 return success();
4632}
4633
4634/// release ::= 'release(' exp exp ref_expr ')' info?
4635ParseResult FIRStmtParser::parseRefRelease() {
4636 auto startTok = consumeToken(FIRToken::lp_release);
4637
4638 Value clock, pred, dest;
4639 if (parseExp(clock, "expected clock expression in release") ||
4640 parseToken(FIRToken::comma, "expected ','") ||
4641 parseExp(pred, "expected predicate expression in release") ||
4642 parseToken(FIRToken::comma, "expected ','") ||
4643 parseRefExp(dest,
4644 "expected destination reference expression in release") ||
4645 parseToken(FIRToken::r_paren, "expected ')' in release") ||
4646 parseOptionalInfo())
4647 return failure();
4648
4649 // Check reference expression is of reference type.
4650 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4651 !ref || !ref.getForceable())
4652 return emitError(
4653 startTok.getLoc(),
4654 "expected rwprobe-type expression for release destination, got ")
4655 << dest.getType();
4656
4657 locationProcessor.setLoc(startTok.getLoc());
4658
4659 RefReleaseOp::create(builder, clock, pred, dest);
4660
4661 return success();
4662}
4663
4664/// release_initial ::= 'release_initial(' ref_expr ')' info?
4665ParseResult FIRStmtParser::parseRefReleaseInitial() {
4666 auto startTok = consumeToken(FIRToken::lp_release_initial);
4667
4668 Value dest;
4669 if (parseRefExp(
4670 dest,
4671 "expected destination reference expression in release_initial") ||
4672 parseToken(FIRToken::r_paren, "expected ')' in release_initial") ||
4673 parseOptionalInfo())
4674 return failure();
4675
4676 // Check reference expression is of reference type.
4677 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4678 !ref || !ref.getForceable())
4679 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4680 "release_initial destination, got ")
4681 << dest.getType();
4682
4683 locationProcessor.setLoc(startTok.getLoc());
4684
4685 auto value = APInt::getAllOnes(1);
4686 auto type = UIntType::get(builder.getContext(), 1);
4687 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4688 value.getBitWidth(),
4689 IntegerType::Unsigned),
4690 value);
4691 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4692 RefReleaseInitialOp::create(builder, pred, dest);
4693
4694 return success();
4695}
4696
4697/// connect ::= 'connect' expr expr
4698ParseResult FIRStmtParser::parseConnect() {
4699 auto startTok = consumeToken(FIRToken::kw_connect);
4700 auto loc = startTok.getLoc();
4701
4702 Value lhs, rhs;
4703 if (parseExp(lhs, "expected connect expression") ||
4704 parseToken(FIRToken::comma, "expected ','") ||
4705 parseExp(rhs, "expected connect expression") || parseOptionalInfo())
4706 return failure();
4707
4708 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4709 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4710 if (!lhsType || !rhsType)
4711 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4712 "cannot connect reference or property types");
4713 // TODO: Once support lands for agg-of-ref, add test for this check!
4714 if (lhsType.containsReference() || rhsType.containsReference())
4715 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4716 "cannot connect types containing references");
4717
4718 if (!areTypesEquivalent(lhsType, rhsType))
4719 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4720 "cannot connect non-equivalent type ")
4721 << rhsType << " to " << lhsType;
4722
4723 locationProcessor.setLoc(loc);
4725 builder, lhs, rhs, [&] { return locationProcessor.getLoc(*this, loc); },
4726 getConstants().options.warnOnTruncation);
4727 return success();
4728}
4729
4730/// FIRRTL 6.0.0 <= version < FIRRTL 8.0.0:
4731/// propassert ::= 'propassert' expr ',' string_literal
4732/// FIRRTL 7.0.0 <= version:
4733/// propassert ::= 'propassert' expr ',' expr
4734///
4735/// Before calling, it has already been verified that the FIRRTL version is
4736/// greater than 6.0.0.
4737ParseResult FIRStmtParser::parsePropAssert() {
4738 auto startTok = consumeToken(FIRToken::kw_propassert);
4739 auto loc = startTok.getLoc();
4740
4741 llvm::SMLoc conditionLoc = getToken().getLoc(), messageLoc;
4742 Value condition, message;
4743 if (parseExp(condition, "expected condition in 'propassert'") ||
4744 parseToken(FIRToken::comma, "expected ','"))
4745 return failure();
4746 // String message handling
4747 if (getToken().is(FIRToken::string)) {
4748 if (removedFeature({8, 0, 0}, "string messages in property asserts"))
4749 return failure();
4750 StringRef messageStr;
4751 messageLoc = getToken().getLoc();
4752 if (parseGetSpelling(messageStr) ||
4753 parseToken(FIRToken::string, "expected message string in 'propassert'"))
4754 return failure();
4755 locationProcessor.setLoc(messageLoc);
4756 auto attr = builder.getStringAttr(FIRToken::getStringValue(messageStr));
4757 message = moduleContext.getCachedConstant<StringConstantOp>(
4758 builder, attr, builder.getType<StringType>(), attr);
4759 } else {
4760 if (requireFeature(
4761 {7, 0, 0},
4762 "string property expression message in property asserts"))
4763 return failure();
4764 messageLoc = getToken().getLoc();
4765 if (parseExp(message, "expected message in 'propassert'"))
4766 return failure();
4767 }
4768
4769 if (!isa<BoolType>(condition.getType()))
4770 return emitError(conditionLoc,
4771 "propassert condition must be of boolean type");
4772
4773 // Note: This is a dead check for FIRRTL < 7.0.0.
4774 if (!type_isa<StringType>(message.getType()))
4775 return emitError(messageLoc, "propassert message must be a string type");
4776
4777 if (parseOptionalInfo())
4778 return failure();
4779
4780 locationProcessor.setLoc(loc);
4781 PropertyAssertOp::create(builder, condition, message);
4782 return success();
4783}
4784
4785/// propassign ::= 'propassign' expr expr
4786ParseResult FIRStmtParser::parsePropAssign() {
4787 auto startTok = consumeToken(FIRToken::kw_propassign);
4788 auto loc = startTok.getLoc();
4789
4790 Value lhs, rhs;
4791 if (parseExp(lhs, "expected propassign expression") ||
4792 parseToken(FIRToken::comma, "expected ','") ||
4793 parseExp(rhs, "expected propassign expression") || parseOptionalInfo())
4794 return failure();
4795
4796 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4797 if (!lhsType)
4798 return emitError(loc, "can only propassign property types");
4799 locationProcessor.setLoc(loc);
4800 rhs = emitImplicitAnyRefCast(rhs, lhsType);
4801 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4802 if (!rhsType)
4803 return emitError(loc, "can only propassign property types");
4804 if (lhsType != rhsType)
4805 return emitError(loc, "cannot propassign non-equivalent type ")
4806 << rhsType << " to " << lhsType;
4807 PropAssignOp::create(builder, lhs, rhs);
4808 return success();
4809}
4810
4811/// invalidate ::= 'invalidate' expr
4812ParseResult FIRStmtParser::parseInvalidate() {
4813 auto startTok = consumeToken(FIRToken::kw_invalidate);
4814
4815 Value lhs;
4816
4817 StringRef id;
4818 auto loc = getToken().getLoc();
4819 SymbolValueEntry symtabEntry;
4820 if (parseId(id, "expected static reference expression") ||
4821 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
4822 return failure();
4823
4824 // If we looked up a normal value (e.g., wire, register, or port), then we
4825 // just need to get any optional trailing expression. Invalidate this.
4826 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
4827 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4828 parseOptionalInfo())
4829 return failure();
4830
4831 locationProcessor.setLoc(startTok.getLoc());
4832 emitInvalidate(lhs);
4833 return success();
4834 }
4835
4836 // We're dealing with an instance. This instance may or may not have a
4837 // trailing expression. Handle the special case of no trailing expression
4838 // first by invalidating all of its results.
4839 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
4840
4841 if (getToken().isNot(FIRToken::period)) {
4842 locationProcessor.setLoc(loc);
4843 // Invalidate all of the results of the bundled value.
4844 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4845 UnbundledValueEntry &ubEntry = moduleContext.getUnbundledEntry(unbundledId);
4846 for (auto elt : ubEntry)
4847 emitInvalidate(elt.second);
4848 return success();
4849 }
4850
4851 // Handle the case of an instance with a trailing expression. This must begin
4852 // with a '.' (until we add instance arrays).
4853 StringRef fieldName;
4854 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
4855 parseFieldId(fieldName, "expected field name") ||
4856 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4857 return failure();
4858
4859 // Update with any trailing expression and invalidate it.
4860 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4861 parseOptionalInfo())
4862 return failure();
4863
4864 locationProcessor.setLoc(startTok.getLoc());
4865 emitInvalidate(lhs);
4866 return success();
4867}
4868
4869ParseResult FIRStmtParser::parseLayerBlockOrGroup(unsigned indent) {
4870
4871 auto startTok = consumeToken();
4872 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4873 "consumed an unexpected token");
4874 auto loc = startTok.getLoc();
4875
4876 StringRef id;
4877 if (parseId(id, "expected layer identifer") ||
4878 parseToken(FIRToken::colon, "expected ':' at end of layer block") ||
4879 parseOptionalInfo())
4880 return failure();
4881
4882 locationProcessor.setLoc(loc);
4883
4884 StringRef rootLayer;
4885 SmallVector<FlatSymbolRefAttr> nestedLayers;
4886 if (!layerSym) {
4887 rootLayer = id;
4888 } else {
4889 rootLayer = layerSym.getRootReference();
4890 auto nestedRefs = layerSym.getNestedReferences();
4891 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4892 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(), id));
4893 }
4894
4895 auto layerBlockOp = LayerBlockOp::create(
4896 builder,
4897 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4898 layerBlockOp->getRegion(0).push_back(new Block());
4899
4900 if (getIndentation() > indent)
4901 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4902 layerBlockOp.getLayerName()))
4903 return failure();
4904
4905 return success();
4906}
4907
4908/// leading-exp-stmt ::= exp '<=' exp info?
4909/// ::= exp 'is' 'invalid' info?
4910ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4911 auto loc = getToken().getLoc();
4912
4913 // If 'is' grammar is special.
4914 if (consumeIf(FIRToken::kw_is)) {
4915 if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
4916 parseOptionalInfo())
4917 return failure();
4918
4919 if (removedFeature({3, 0, 0}, "'is invalid' statements", loc))
4920 return failure();
4921
4922 locationProcessor.setLoc(loc);
4923 emitInvalidate(lhs);
4924 return success();
4925 }
4926
4927 if (parseToken(FIRToken::less_equal, "expected '<=' in statement"))
4928 return failure();
4929
4930 if (removedFeature({3, 0, 0}, "'<=' connections", loc))
4931 return failure();
4932
4933 Value rhs;
4934 if (parseExp(rhs, "unexpected token in statement") || parseOptionalInfo())
4935 return failure();
4936
4937 locationProcessor.setLoc(loc);
4938
4939 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4940 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4941 if (!lhsType || !rhsType)
4942 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4943 "cannot connect reference or property types");
4944 // TODO: Once support lands for agg-of-ref, add test for this check!
4945 if (lhsType.containsReference() || rhsType.containsReference())
4946 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4947 "cannot connect types containing references");
4948
4949 if (!areTypesEquivalent(lhsType, rhsType))
4950 return mlir::emitError(locationProcessor.getLoc(*this, loc),
4951 "cannot connect non-equivalent type ")
4952 << rhsType << " to " << lhsType;
4954 builder, lhs, rhs, [&] { return locationProcessor.getLoc(*this, loc); },
4955 getConstants().options.warnOnTruncation);
4956 return success();
4957}
4958
4959//===-------------------------------
4960// FIRStmtParser Declaration Parsing
4961
4962/// instance ::= 'inst' id 'of' id info?
4963ParseResult FIRStmtParser::parseInstance() {
4964 auto startTok = consumeToken(FIRToken::kw_inst);
4965
4966 // If this was actually the start of a connect or something else handle
4967 // that.
4968 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4969 return *isExpr;
4970
4971 StringRef id;
4972 StringRef moduleName;
4973 if (parseId(id, "expected instance name") ||
4974 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
4975 parseId(moduleName, "expected module name") || parseOptionalInfo())
4976 return failure();
4977
4978 locationProcessor.setLoc(startTok.getLoc());
4979
4980 // Look up the module that is being referenced.
4981 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4982 if (!referencedModule)
4983 return failure();
4984
4985 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4986
4987 auto annotations = getConstants().emptyArrayAttr;
4988 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4989
4990 hw::InnerSymAttr sym = {};
4991 auto result = InstanceOp::create(
4992 builder, referencedModule, id, NameKindEnum::InterestingName,
4993 annotations.getValue(), portAnnotations, false, false, sym);
4994
4995 // Since we are implicitly unbundling the instance results, we need to keep
4996 // track of the mapping from bundle fields to results in the unbundledValues
4997 // data structure. Build our entry now.
4998 UnbundledValueEntry unbundledValueEntry;
4999 unbundledValueEntry.reserve(modulePorts.size());
5000 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
5001 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
5002
5003 // Add it to unbundledValues and add an entry to the symbol table to remember
5004 // it.
5005 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5006 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
5007 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
5008}
5009
5010/// instance_choice ::=
5011/// 'inst_choice' id 'of' id id info? newline indent ( id "=>" id )+ dedent
5012ParseResult FIRStmtParser::parseInstanceChoice() {
5013 auto startTok = consumeToken(FIRToken::kw_instchoice);
5014 SMLoc loc = startTok.getLoc();
5015
5016 // If this was actually the start of a connect or something else handle that.
5017 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5018 return *isExpr;
5019
5020 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
5021 return failure();
5022
5023 StringRef id;
5024 StringRef defaultModuleName;
5025 StringRef optionGroupName;
5026 if (parseId(id, "expected instance name") ||
5027 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
5028 parseId(defaultModuleName, "expected module name") ||
5029 parseToken(FIRToken::comma, "expected ','") ||
5030 parseId(optionGroupName, "expected option group name") ||
5031 parseToken(FIRToken::colon, "expected ':' after instchoice") ||
5032 parseOptionalInfo())
5033 return failure();
5034
5035 locationProcessor.setLoc(startTok.getLoc());
5036
5037 // Look up the default module referenced by the instance choice.
5038 // The port lists of all the other referenced modules must match this one.
5039 auto defaultModule = getReferencedModule(loc, defaultModuleName);
5040 if (!defaultModule)
5041 return failure();
5042
5043 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
5044
5045 // Find the option group.
5046 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
5047 if (!optionGroup)
5048 return emitError(loc,
5049 "use of undefined option group '" + optionGroupName + "'");
5050
5051 auto baseIndent = getIndentation();
5052 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
5053 while (getIndentation() == baseIndent) {
5054 StringRef caseId;
5055 StringRef caseModuleName;
5056 if (parseId(caseId, "expected a case identifier") ||
5057 parseToken(FIRToken::equal_greater,
5058 "expected '=> in instance choice definition") ||
5059 parseId(caseModuleName, "expected module name"))
5060 return failure();
5061
5062 auto caseModule = getReferencedModule(loc, caseModuleName);
5063 if (!caseModule)
5064 return failure();
5065
5066 for (const auto &[defaultPort, casePort] :
5067 llvm::zip(modulePorts, caseModule.getPorts())) {
5068 if (defaultPort.name != casePort.name)
5069 return emitError(loc, "instance case module port '")
5070 << casePort.name.getValue()
5071 << "' does not match the default module port '"
5072 << defaultPort.name.getValue() << "'";
5073 if (defaultPort.type != casePort.type)
5074 return emitError(loc, "instance case port '")
5075 << casePort.name.getValue()
5076 << "' type does not match the default module port";
5077 }
5078
5079 auto optionCase =
5080 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
5081 if (!optionCase)
5082 return emitError(loc, "use of undefined option case '" + caseId + "'");
5083 caseModules.emplace_back(optionCase, caseModule);
5084 }
5085
5086 auto annotations = getConstants().emptyArrayAttr;
5087 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
5088
5089 // Create an instance choice op.
5090 StringAttr sym;
5091 auto result = InstanceChoiceOp::create(
5092 builder, defaultModule, caseModules, id, NameKindEnum::InterestingName,
5093 annotations.getValue(), portAnnotations, sym);
5094
5095 // Un-bundle the ports, identically to the regular instance operation.
5096 UnbundledValueEntry unbundledValueEntry;
5097 unbundledValueEntry.reserve(modulePorts.size());
5098 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
5099 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
5100
5101 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5102 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
5103 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
5104}
5105
5106FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
5107 StringRef moduleName) {
5108 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
5109 if (!referencedModule) {
5110 emitError(loc,
5111 "use of undefined module name '" + moduleName + "' in instance");
5112 return {};
5113 }
5114 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
5115 emitError(loc, "cannot create instance of class '" + moduleName +
5116 "', did you mean object?");
5117 return {};
5118 }
5119 return referencedModule;
5120}
5121
5122/// object ::= 'object' id 'of' id info?
5123ParseResult FIRStmtParser::parseObject() {
5124 auto startTok = consumeToken(FIRToken::kw_object);
5125
5126 // If this was actually the start of a connect or something else handle
5127 // that.
5128 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5129 return *isExpr;
5130
5131 if (requireFeature({6, 0, 0}, "object statements"))
5132 return failure();
5133
5134 StringRef id;
5135 StringRef className;
5136 if (parseId(id, "expected object name") ||
5137 parseToken(FIRToken::kw_of, "expected 'of' in object") ||
5138 parseId(className, "expected class name") || parseOptionalInfo())
5139 return failure();
5140
5141 locationProcessor.setLoc(startTok.getLoc());
5142
5143 // Look up the class that is being referenced.
5144 const auto &classMap = getConstants().classMap;
5145 auto lookup = classMap.find(className);
5146 if (lookup == classMap.end())
5147 return emitError(startTok.getLoc(), "use of undefined class name '" +
5148 className + "' in object");
5149 auto referencedClass = lookup->getSecond();
5150 auto result = ObjectOp::create(builder, referencedClass, id);
5151 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5152}
5153
5154/// cmem ::= 'cmem' id ':' type info?
5155ParseResult FIRStmtParser::parseCombMem() {
5156 // TODO(firrtl spec) cmem is completely undocumented.
5157 auto startTok = consumeToken(FIRToken::kw_cmem);
5158
5159 // If this was actually the start of a connect or something else handle
5160 // that.
5161 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5162 return *isExpr;
5163
5164 StringRef id;
5165 FIRRTLType type;
5166 if (parseId(id, "expected cmem name") ||
5167 parseToken(FIRToken::colon, "expected ':' in cmem") ||
5168 parseType(type, "expected cmem type") || parseOptionalInfo())
5169 return failure();
5170
5171 locationProcessor.setLoc(startTok.getLoc());
5172
5173 // Transform the parsed vector type into a memory type.
5174 auto vectorType = type_dyn_cast<FVectorType>(type);
5175 if (!vectorType)
5176 return emitError("cmem requires vector type");
5177
5178 auto annotations = getConstants().emptyArrayAttr;
5179 StringAttr sym = {};
5180 auto result = CombMemOp::create(
5181 builder, vectorType.getElementType(), vectorType.getNumElements(), id,
5182 NameKindEnum::InterestingName, annotations, sym);
5183 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5184}
5185
5186/// smem ::= 'smem' id ':' type ruw? info?
5187ParseResult FIRStmtParser::parseSeqMem() {
5188 // TODO(firrtl spec) smem is completely undocumented.
5189 auto startTok = consumeToken(FIRToken::kw_smem);
5190
5191 // If this was actually the start of a connect or something else handle
5192 // that.
5193 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5194 return *isExpr;
5195
5196 StringRef id;
5197 FIRRTLType type;
5198 RUWBehavior ruw = RUWBehavior::Undefined;
5199
5200 if (parseId(id, "expected smem name") ||
5201 parseToken(FIRToken::colon, "expected ':' in smem") ||
5202 parseType(type, "expected smem type"))
5203 return failure();
5204
5205 if (consumeIf(FIRToken::comma)) {
5206 if (parseRUW(ruw))
5207 return failure();
5208 }
5209
5210 if (parseOptionalInfo()) {
5211 return failure();
5212 }
5213
5214 locationProcessor.setLoc(startTok.getLoc());
5215
5216 // Transform the parsed vector type into a memory type.
5217 auto vectorType = type_dyn_cast<FVectorType>(type);
5218 if (!vectorType)
5219 return emitError("smem requires vector type");
5220
5221 auto annotations = getConstants().emptyArrayAttr;
5222 StringAttr sym = {};
5223 auto result = SeqMemOp::create(
5224 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
5225 id, NameKindEnum::InterestingName, annotations, sym);
5226 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5227}
5228
5229/// mem ::= 'mem' id ':' info? INDENT memField* DEDENT
5230/// memField ::= 'data-type' '=>' type NEWLINE
5231/// ::= 'depth' '=>' intLit NEWLINE
5232/// ::= 'read-latency' '=>' intLit NEWLINE
5233/// ::= 'write-latency' '=>' intLit NEWLINE
5234/// ::= 'read-under-write' '=>' ruw NEWLINE
5235/// ::= 'reader' '=>' id+ NEWLINE
5236/// ::= 'writer' '=>' id+ NEWLINE
5237/// ::= 'readwriter' '=>' id+ NEWLINE
5238ParseResult FIRStmtParser::parseMem(unsigned memIndent) {
5239 auto startTok = consumeToken(FIRToken::kw_mem);
5240
5241 // If this was actually the start of a connect or something else handle
5242 // that.
5243 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5244 return *isExpr;
5245
5246 StringRef id;
5247 if (parseId(id, "expected mem name") ||
5248 parseToken(FIRToken::colon, "expected ':' in mem") || parseOptionalInfo())
5249 return failure();
5250
5251 FIRRTLType type;
5252 int64_t depth = -1, readLatency = -1, writeLatency = -1;
5253 RUWBehavior ruw = RUWBehavior::Undefined;
5254
5255 SmallVector<std::pair<StringAttr, Type>, 4> ports;
5256
5257 // Parse all the memfield records, which are indented more than the mem.
5258 while (1) {
5259 auto nextIndent = getIndentation();
5260 if (!nextIndent || *nextIndent <= memIndent)
5261 break;
5262
5263 auto spelling = getTokenSpelling();
5264 if (parseToken(FIRToken::identifier, "unexpected token in 'mem'") ||
5265 parseToken(FIRToken::equal_greater, "expected '=>' in 'mem'"))
5266 return failure();
5267
5268 if (spelling == "data-type") {
5269 if (type)
5270 return emitError("'mem' type specified multiple times"), failure();
5271
5272 if (parseType(type, "expected type in data-type declaration"))
5273 return failure();
5274 continue;
5275 }
5276 if (spelling == "depth") {
5277 if (parseIntLit(depth, "expected integer in depth specification"))
5278 return failure();
5279 continue;
5280 }
5281 if (spelling == "read-latency") {
5282 if (parseIntLit(readLatency, "expected integer latency"))
5283 return failure();
5284 continue;
5285 }
5286 if (spelling == "write-latency") {
5287 if (parseIntLit(writeLatency, "expected integer latency"))
5288 return failure();
5289 continue;
5290 }
5291 if (spelling == "read-under-write") {
5292 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
5293 FIRToken::kw_undefined))
5294 return emitError("expected specifier"), failure();
5295
5296 if (parseOptionalRUW(ruw))
5297 return failure();
5298 continue;
5299 }
5300
5301 MemOp::PortKind portKind;
5302 if (spelling == "reader")
5303 portKind = MemOp::PortKind::Read;
5304 else if (spelling == "writer")
5305 portKind = MemOp::PortKind::Write;
5306 else if (spelling == "readwriter")
5307 portKind = MemOp::PortKind::ReadWrite;
5308 else
5309 return emitError("unexpected field in 'mem' declaration"), failure();
5310
5311 StringRef portName;
5312 if (parseId(portName, "expected port name"))
5313 return failure();
5314 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
5315 if (!baseType)
5316 return emitError("unexpected type, must be base type");
5317 ports.push_back({builder.getStringAttr(portName),
5318 MemOp::getTypeForPort(depth, baseType, portKind)});
5319
5320 while (!getIndentation().has_value()) {
5321 if (parseId(portName, "expected port name"))
5322 return failure();
5323 ports.push_back({builder.getStringAttr(portName),
5324 MemOp::getTypeForPort(depth, baseType, portKind)});
5325 }
5326 }
5327
5328 // The FIRRTL dialect requires mems to have at least one port. Since portless
5329 // mems can never be referenced, it is always safe to drop them.
5330 if (ports.empty())
5331 return success();
5332
5333 // Canonicalize the ports into alphabetical order.
5334 // TODO: Move this into MemOp construction/canonicalization.
5335 llvm::array_pod_sort(ports.begin(), ports.end(),
5336 [](const std::pair<StringAttr, Type> *lhs,
5337 const std::pair<StringAttr, Type> *rhs) -> int {
5338 return lhs->first.getValue().compare(
5339 rhs->first.getValue());
5340 });
5341
5342 auto annotations = getConstants().emptyArrayAttr;
5343 SmallVector<Attribute, 4> resultNames;
5344 SmallVector<Type, 4> resultTypes;
5345 SmallVector<Attribute, 4> resultAnnotations;
5346 for (auto p : ports) {
5347 resultNames.push_back(p.first);
5348 resultTypes.push_back(p.second);
5349 resultAnnotations.push_back(annotations);
5350 }
5351
5352 locationProcessor.setLoc(startTok.getLoc());
5353
5354 auto result = MemOp::create(
5355 builder, resultTypes, readLatency, writeLatency, depth, ruw,
5356 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
5357 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
5358 MemoryInitAttr(), StringAttr());
5359
5360 UnbundledValueEntry unbundledValueEntry;
5361 unbundledValueEntry.reserve(result.getNumResults());
5362 for (size_t i = 0, e = result.getNumResults(); i != e; ++i)
5363 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
5364
5365 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
5366 auto entryID = UnbundledID(moduleContext.unbundledValues.size());
5367 return moduleContext.addSymbolEntry(id, entryID, startTok.getLoc());
5368}
5369
5370/// node ::= 'node' id '=' exp info?
5371ParseResult FIRStmtParser::parseNode() {
5372 auto startTok = consumeToken(FIRToken::kw_node);
5373
5374 // If this was actually the start of a connect or something else handle
5375 // that.
5376 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5377 return *isExpr;
5378
5379 StringRef id;
5380 Value initializer;
5381 if (parseId(id, "expected node name") ||
5382 parseToken(FIRToken::equal, "expected '=' in node") ||
5383 parseExp(initializer, "expected expression for node") ||
5384 parseOptionalInfo())
5385 return failure();
5386
5387 locationProcessor.setLoc(startTok.getLoc());
5388
5389 // Error out in the following conditions:
5390 //
5391 // 1. Node type is Analog (at the top level)
5392 // 2. Node type is not passive under an optional outer flip
5393 // (analog field is okay)
5394 //
5395 // Note: (1) is more restictive than normal NodeOp verification, but
5396 // this is added to align with the SFC. (2) is less restrictive than
5397 // the SFC to accomodate for situations where the node is something
5398 // weird like a module output or an instance input.
5399 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
5400 auto initializerBaseType =
5401 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
5402 if (type_isa<AnalogType>(initializerType) ||
5403 !(initializerBaseType && initializerBaseType.isPassive())) {
5404 emitError(startTok.getLoc())
5405 << "Node cannot be analog and must be passive or passive under a flip "
5406 << initializer.getType();
5407 return failure();
5408 }
5409
5410 auto annotations = getConstants().emptyArrayAttr;
5411 StringAttr sym = {};
5412
5413 auto result = NodeOp::create(builder, initializer, id,
5414 NameKindEnum::InterestingName, annotations, sym);
5415 return moduleContext.addSymbolEntry(id, result.getResult(),
5416 startTok.getLoc());
5417}
5418
5419/// wire ::= 'wire' id ':' type ('domains' '[' domain_list ']')? info?
5420ParseResult FIRStmtParser::parseWire() {
5421 auto startTok = consumeToken(FIRToken::kw_wire);
5422
5423 // If this was actually the start of a connect or something else handle
5424 // that.
5425 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5426 return *isExpr;
5427
5428 StringRef id;
5429 FIRRTLType type;
5430 if (parseId(id, "expected wire name") ||
5431 parseToken(FIRToken::colon, "expected ':' in wire") ||
5432 parseType(type, "expected wire type"))
5433 return failure();
5434
5435 // Parse optional domain associations
5436 SmallVector<Value> domains;
5437 if (consumeIf(FIRToken::kw_domains)) {
5438 if (requireFeature(missingSpecFIRVersion, "domains", startTok.getLoc()))
5439 return failure();
5440
5441 if (parseToken(FIRToken::l_square, "expected '[' after 'domains'"))
5442 return failure();
5443
5444 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
5445 StringRef domainName;
5446 auto domainLoc = getToken().getLoc();
5447 if (parseId(domainName, "expected domain name"))
5448 return failure();
5449
5450 // Look up the domain value in the module context
5451 SymbolValueEntry lookup;
5452 if (moduleContext.lookupSymbolEntry(lookup, domainName, domainLoc))
5453 return failure();
5454
5455 // Resolve the symbol table entry to a Value
5456 Value domainValue;
5457 if (moduleContext.resolveSymbolEntry(domainValue, lookup, domainLoc))
5458 return failure();
5459
5460 if (!isa<DomainType>(domainValue.getType()))
5461 return emitError(domainLoc)
5462 << "'" << domainName << "' is not a domain";
5463
5464 domains.push_back(domainValue);
5465 return success();
5466 }))
5467 return failure();
5468 }
5469
5470 if (parseOptionalInfo())
5471 return failure();
5472
5473 locationProcessor.setLoc(startTok.getLoc());
5474
5475 auto annotations = getConstants().emptyArrayAttr;
5476 StringAttr sym = {};
5477
5478 // Names of only-nonHW should be droppable.
5479 auto namekind = isa<PropertyType, RefType>(type)
5480 ? NameKindEnum::DroppableName
5481 : NameKindEnum::InterestingName;
5482
5483 auto result = WireOp::create(builder, type, id, namekind, annotations, sym,
5484 /*forceable=*/false, domains);
5485 return moduleContext.addSymbolEntry(id, result.getResult(),
5486 startTok.getLoc());
5487}
5488
5489/// register ::= 'reg' id ':' type exp ('with' ':' reset_block)? info?
5490///
5491/// reset_block ::= INDENT simple_reset info? NEWLINE DEDENT
5492/// ::= '(' simple_reset ')'
5493///
5494/// simple_reset ::= simple_reset0
5495/// ::= '(' simple_reset0 ')'
5496///
5497/// simple_reset0: 'reset' '=>' '(' exp exp ')'
5498///
5499ParseResult FIRStmtParser::parseRegister(unsigned regIndent) {
5500 auto startTok = consumeToken(FIRToken::kw_reg);
5501
5502 // If this was actually the start of a connect or something else handle
5503 // that.
5504 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5505 return *isExpr;
5506
5507 StringRef id;
5508 FIRRTLType type;
5509 Value clock;
5510
5511 // TODO(firrtl spec): info? should come after the clock expression before
5512 // the 'with'.
5513 if (parseId(id, "expected reg name") ||
5514 parseToken(FIRToken::colon, "expected ':' in reg") ||
5515 parseType(type, "expected reg type") ||
5516 parseToken(FIRToken::comma, "expected ','") ||
5517 parseExp(clock, "expected expression for register clock"))
5518 return failure();
5519
5520 if (!type_isa<FIRRTLBaseType>(type))
5521 return emitError(startTok.getLoc(), "register must have base type");
5522
5523 // Parse the 'with' specifier if present.
5524 Value resetSignal, resetValue;
5525 if (consumeIf(FIRToken::kw_with)) {
5526 if (removedFeature({3, 0, 0}, "'reg with' registers"))
5527 return failure();
5528
5529 if (parseToken(FIRToken::colon, "expected ':' in reg"))
5530 return failure();
5531
5532 // TODO(firrtl spec): Simplify the grammar for register reset logic.
5533 // Why allow multiple ambiguous parentheses? Why rely on indentation at
5534 // all?
5535
5536 // This implements what the examples have in practice.
5537 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5538
5539 auto indent = getIndentation();
5540 if (!indent || *indent <= regIndent)
5541 if (!hasExtraLParen)
5542 return emitError("expected indented reset specifier in reg"), failure();
5543
5544 if (parseToken(FIRToken::kw_reset, "expected 'reset' in reg") ||
5545 parseToken(FIRToken::equal_greater, "expected => in reset specifier") ||
5546 parseToken(FIRToken::l_paren, "expected '(' in reset specifier") ||
5547 parseExp(resetSignal, "expected expression for reset signal") ||
5548 parseToken(FIRToken::comma, "expected ','"))
5549 return failure();
5550
5551 // The Scala implementation of FIRRTL represents registers without resets
5552 // as a self referential register... and the pretty printer doesn't print
5553 // the right form. Recognize that this is happening and treat it as a
5554 // register without a reset for compatibility.
5555 // TODO(firrtl scala impl): pretty print registers without resets right.
5556 if (getTokenSpelling() == id) {
5557 consumeToken();
5558 if (parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5559 return failure();
5560 resetSignal = Value();
5561 } else {
5562 if (parseExp(resetValue, "expected expression for reset value") ||
5563 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5564 return failure();
5565 }
5566
5567 if (hasExtraLParen &&
5568 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5569 return failure();
5570 }
5571
5572 // Finally, handle the last info if present, providing location info for the
5573 // clock expression.
5574 if (parseOptionalInfo())
5575 return failure();
5576
5577 locationProcessor.setLoc(startTok.getLoc());
5578
5579 ArrayAttr annotations = getConstants().emptyArrayAttr;
5580 Value result;
5581 StringAttr sym = {};
5582 if (resetSignal)
5583 result =
5584 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5585 NameKindEnum::InterestingName, annotations, sym)
5586 .getResult();
5587 else
5588 result = RegOp::create(builder, type, clock, id,
5589 NameKindEnum::InterestingName, annotations, sym)
5590 .getResult();
5591 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5592}
5593
5594/// registerWithReset ::= 'regreset' id ':' type exp exp exp
5595///
5596/// This syntax is only supported in FIRRTL versions >= 3.0.0. Because this
5597/// syntax is only valid for >= 3.0.0, there is no need to check if the leading
5598/// "regreset" is part of an expression with a leading keyword.
5599ParseResult FIRStmtParser::parseRegisterWithReset() {
5600 auto startTok = consumeToken(FIRToken::kw_regreset);
5601
5602 StringRef id;
5603 FIRRTLType type;
5604 Value clock, resetSignal, resetValue;
5605
5606 if (parseId(id, "expected reg name") ||
5607 parseToken(FIRToken::colon, "expected ':' in reg") ||
5608 parseType(type, "expected reg type") ||
5609 parseToken(FIRToken::comma, "expected ','") ||
5610 parseExp(clock, "expected expression for register clock") ||
5611 parseToken(FIRToken::comma, "expected ','") ||
5612 parseExp(resetSignal, "expected expression for register reset") ||
5613 parseToken(FIRToken::comma, "expected ','") ||
5614 parseExp(resetValue, "expected expression for register reset value") ||
5615 parseOptionalInfo())
5616 return failure();
5617
5618 if (!type_isa<FIRRTLBaseType>(type))
5619 return emitError(startTok.getLoc(), "register must have base type");
5620
5621 locationProcessor.setLoc(startTok.getLoc());
5622
5623 auto result =
5624 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5625 NameKindEnum::InterestingName,
5626 getConstants().emptyArrayAttr, StringAttr{})
5627 .getResult();
5628
5629 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5630}
5631
5632/// contract ::= 'contract' (id,+ '=' exp,+) ':' info? contract_body
5633/// contract_body ::= simple_stmt | INDENT simple_stmt+ DEDENT
5634ParseResult FIRStmtParser::parseContract(unsigned blockIndent) {
5635 if (requireFeature(missingSpecFIRVersion, "contracts"))
5636 return failure();
5637
5638 auto startTok = consumeToken(FIRToken::kw_contract);
5639
5640 // Parse the contract results and expressions.
5641 SmallVector<StringRef> ids;
5642 SmallVector<SMLoc> locs;
5643 SmallVector<Value> values;
5644 SmallVector<Type> types;
5645 if (!consumeIf(FIRToken::colon)) {
5646 auto parseContractId = [&] {
5647 StringRef id;
5648 locs.push_back(getToken().getLoc());
5649 if (parseId(id, "expected contract result name"))
5650 return failure();
5651 ids.push_back(id);
5652 return success();
5653 };
5654 auto parseContractValue = [&] {
5655 Value value;
5656 if (parseExp(value, "expected expression for contract result"))
5657 return failure();
5658 values.push_back(value);
5659 types.push_back(value.getType());
5660 return success();
5661 };
5662 if (parseListUntil(FIRToken::equal, parseContractId) ||
5663 parseListUntil(FIRToken::colon, parseContractValue))
5664 return failure();
5665 }
5666 if (parseOptionalInfo())
5667 return failure();
5668
5669 // Each result must have a corresponding expression assigned.
5670 if (ids.size() != values.size())
5671 return emitError(startTok.getLoc())
5672 << "contract requires same number of results and expressions; got "
5673 << ids.size() << " results and " << values.size()
5674 << " expressions instead";
5675
5676 locationProcessor.setLoc(startTok.getLoc());
5677
5678 // Add block arguments for each result and declare their names in a subscope
5679 // for the contract body.
5680 auto contract = ContractOp::create(builder, types, values);
5681 auto &block = contract.getBody().emplaceBlock();
5682
5683 // Parse the contract body.
5684 {
5685 FIRModuleContext::ContextScope scope(moduleContext, &block);
5686 for (auto [id, loc, type] : llvm::zip(ids, locs, types)) {
5687 auto arg = block.addArgument(type, LocWithInfo(loc, this).getLoc());
5688 if (failed(moduleContext.addSymbolEntry(id, arg, loc)))
5689 return failure();
5690 }
5691 if (getIndentation() > blockIndent)
5692 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5693 return failure();
5694 }
5695
5696 // Declare the results.
5697 for (auto [id, loc, value, result] :
5698 llvm::zip(ids, locs, values, contract.getResults())) {
5699 // Remove previous symbol to avoid duplicates
5700 moduleContext.removeSymbolEntry(id);
5701 if (failed(moduleContext.addSymbolEntry(id, result, loc)))
5702 return failure();
5703 }
5704 return success();
5705}
5706
5707//===----------------------------------------------------------------------===//
5708// FIRCircuitParser
5709//===----------------------------------------------------------------------===//
5710
5711namespace {
5712/// This class implements the outer level of the parser, including things
5713/// like circuit and module.
5714struct FIRCircuitParser : public FIRParser {
5715 explicit FIRCircuitParser(SharedParserConstants &state, FIRLexer &lexer,
5716 ModuleOp mlirModule, FIRVersion version)
5717 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5718
5719 ParseResult
5720 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5721 mlir::TimingScope &ts);
5722
5723private:
5724 /// Extract Annotations from a JSON-encoded Annotation array string and add
5725 /// them to a vector of attributes.
5726 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5727 SmallVectorImpl<Attribute> &attrs);
5728
5729 ParseResult parseToplevelDefinition(CircuitOp circuit, unsigned indent);
5730
5731 ParseResult parseClass(CircuitOp circuit, unsigned indent);
5732 ParseResult parseDomain(CircuitOp circuit, unsigned indent);
5733 ParseResult parseExtClass(CircuitOp circuit, unsigned indent);
5734 ParseResult parseExtModule(CircuitOp circuit, unsigned indent);
5735 ParseResult parseIntModule(CircuitOp circuit, unsigned indent);
5736 ParseResult parseModule(CircuitOp circuit, bool isPublic, unsigned indent);
5737 ParseResult parseFormal(CircuitOp circuit, unsigned indent);
5738 ParseResult parseSimulation(CircuitOp circuit, unsigned indent);
5739 template <class Op>
5740 ParseResult parseFormalLike(CircuitOp circuit, unsigned indent);
5741
5742 ParseResult parseLayerName(SymbolRefAttr &result);
5743 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5744 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5745 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5746 ParseResult parseRequiresSpec(SmallVectorImpl<Attribute> &result);
5747 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5748 ParseResult parseExtModuleAttributesSpec(ArrayAttr &enabledLayers,
5749 ArrayAttr &knownLayers,
5750 ArrayAttr &externalRequirements);
5751
5752 ParseResult parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5753 SmallVectorImpl<SMLoc> &resultPortLocs,
5754 unsigned indent);
5755 ParseResult parseParameterList(ArrayAttr &resultParameters);
5756
5757 ParseResult skipToModuleEnd(unsigned indent);
5758
5759 ParseResult parseTypeDecl();
5760
5761 ParseResult parseOptionDecl(CircuitOp circuit);
5762
5763 ParseResult parseLayer(CircuitOp circuit);
5764
5765 ParseResult resolveDomains(
5766 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5767 const DenseMap<Attribute, size_t> &nameToIndex,
5768 SmallVectorImpl<Attribute> &domainsByIndex);
5769
5770 ParseResult
5771 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5772 const DenseMap<Attribute, size_t> &nameToIndex);
5773
5774 struct DeferredModuleToParse {
5775 FModuleLike moduleOp;
5776 SmallVector<SMLoc> portLocs;
5777 FIRLexerCursor lexerCursor;
5778 unsigned indent;
5779 };
5780
5781 ParseResult parseModuleBody(const SymbolTable &circuitSymTbl,
5782 DeferredModuleToParse &deferredModule,
5783 InnerSymFixups &fixups);
5784
5785 SmallVector<DeferredModuleToParse, 0> deferredModules;
5786
5787 SmallVector<InnerSymFixups, 0> moduleFixups;
5788
5789 hw::InnerSymbolNamespaceCollection innerSymbolNamespaces;
5790
5791 ModuleOp mlirModule;
5792};
5793
5794} // end anonymous namespace
5795ParseResult
5796FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5797 SmallVectorImpl<Attribute> &attrs) {
5798
5799 auto annotations = json::parse(annotationsStr);
5800 if (auto err = annotations.takeError()) {
5801 handleAllErrors(std::move(err), [&](const json::ParseError &a) {
5802 auto diag = emitError(loc, "Failed to parse JSON Annotations");
5803 diag.attachNote() << a.message();
5804 });
5805 return failure();
5806 }
5807
5808 json::Path::Root root;
5809 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5810 if (!importAnnotationsFromJSONRaw(annotations.get(), attrs, root,
5811 getContext())) {
5812 auto diag = emitError(loc, "Invalid/unsupported annotation format");
5813 std::string jsonErrorMessage =
5814 "See inline comments for problem area in JSON:\n";
5815 llvm::raw_string_ostream s(jsonErrorMessage);
5816 root.printErrorContext(annotations.get(), s);
5817 diag.attachNote() << jsonErrorMessage;
5818 return failure();
5819 }
5820
5821 return success();
5822}
5823
5824ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5825 auto *context = getContext();
5826 SmallVector<StringRef> strings;
5827 do {
5828 StringRef name;
5829 if (parseId(name, "expected layer name"))
5830 return failure();
5831 strings.push_back(name);
5832 } while (consumeIf(FIRToken::period));
5833
5834 SmallVector<FlatSymbolRefAttr> nested;
5835 nested.reserve(strings.size() - 1);
5836 for (unsigned i = 1, e = strings.size(); i < e; ++i)
5837 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5838
5839 result = SymbolRefAttr::get(context, strings[0], nested);
5840 return success();
5841}
5842
5843ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5844 SmallVector<Attribute> enabledLayersBuffer;
5845 while (true) {
5846 auto tokenKind = getToken().getKind();
5847 // Parse an enablelayer spec.
5848 if (tokenKind == FIRToken::kw_enablelayer) {
5849 if (parseEnableLayerSpec(enabledLayersBuffer))
5850 return failure();
5851 continue;
5852 }
5853 // Didn't parse a layer spec.
5854 break;
5855 }
5856
5857 if (enabledLayersBuffer.size() != 0)
5858 if (requireFeature({4, 0, 0}, "modules with layers enabled"))
5859 return failure();
5860
5861 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5862 return success();
5863}
5864
5865ParseResult FIRCircuitParser::parseExtModuleAttributesSpec(
5866 ArrayAttr &enabledLayers, ArrayAttr &knownLayers,
5867 ArrayAttr &externalRequirements) {
5868 SmallVector<Attribute> enabledLayersBuffer;
5869 SmallVector<Attribute> knownLayersBuffer;
5870 SmallVector<Attribute> requirementsBuffer;
5871 while (true) {
5872 auto tokenKind = getToken().getKind();
5873 // Parse an enablelayer spec.
5874 if (tokenKind == FIRToken::kw_enablelayer) {
5875 if (parseEnableLayerSpec(enabledLayersBuffer))
5876 return failure();
5877 continue;
5878 }
5879 // Parse a knownlayer spec.
5880 if (tokenKind == FIRToken::kw_knownlayer) {
5881 if (parseKnownLayerSpec(knownLayersBuffer))
5882 return failure();
5883 continue;
5884 }
5885 // Parse a requires spec.
5886 if (tokenKind == FIRToken::kw_requires) {
5887 if (parseRequiresSpec(requirementsBuffer))
5888 return failure();
5889 continue;
5890 }
5891 // Didn't parse a layer spec or requires.
5892 break;
5893 }
5894
5895 if (enabledLayersBuffer.size() != 0)
5896 if (requireFeature({4, 0, 0}, "extmodules with layers enabled"))
5897 return failure();
5898
5899 if (knownLayersBuffer.size() != 0)
5900 if (requireFeature({6, 0, 0}, "extmodules with known layers"))
5901 return failure();
5902
5903 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5904 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5905 externalRequirements = ArrayAttr::get(getContext(), requirementsBuffer);
5906 return success();
5907}
5908
5909ParseResult
5910FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5911 do {
5912 SymbolRefAttr layer;
5913 if (parseLayerName(layer))
5914 return failure();
5915 result.push_back(layer);
5916 } while (consumeIf(FIRToken::comma));
5917 return success();
5918}
5919
5920ParseResult
5921FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5922 consumeToken(FIRToken::kw_enablelayer);
5923 return parseLayerList(result);
5924}
5925
5926ParseResult
5927FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5928 consumeToken(FIRToken::kw_knownlayer);
5929 return parseLayerList(result);
5930}
5931
5932ParseResult
5933FIRCircuitParser::parseRequiresSpec(SmallVectorImpl<Attribute> &result) {
5934 consumeToken(FIRToken::kw_requires);
5935 do {
5936 StringRef requireStr;
5937 if (parseGetSpelling(requireStr) ||
5938 parseToken(FIRToken::string, "expected string after 'requires'"))
5939 return failure();
5940 // Remove the surrounding quotes from the string.
5941 result.push_back(
5942 StringAttr::get(getContext(), requireStr.drop_front().drop_back()));
5943 } while (consumeIf(FIRToken::comma));
5944 return success();
5945}
5946
5947/// portlist ::= port*
5948/// port ::= dir id ':' type info? NEWLINE
5949/// dir ::= 'input' | 'output'
5950ParseResult
5951FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5952 SmallVectorImpl<SMLoc> &resultPortLocs,
5953 unsigned indent) {
5954 // Stores of information about domains as they are parsed:
5955 // 1. Mapping of domain name to port index
5956 // 2. Mapping of port index to domain associations, using domain _names_.
5957 // The locations are recorded to generate good error messages.
5958 DenseMap<Attribute, size_t> nameToIndex;
5959 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5960
5961 // Parse any ports. Populate domain information.
5962 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5963 // Must be nested under the module.
5964 getIndentation() > indent) {
5965
5966 // We need one token lookahead to resolve the ambiguity between:
5967 // output foo ; port
5968 // output <= input ; identifier expression
5969 // output.thing <= input ; identifier expression
5970 auto backtrackState = getLexer().getCursor();
5971
5972 bool isOutput = getToken().is(FIRToken::kw_output);
5973 consumeToken();
5974
5975 // If we have something that isn't a keyword then this must be an
5976 // identifier, not an input/output marker.
5977 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5978 !getToken().isKeyword()) {
5979 backtrackState.restore(getLexer());
5980 break;
5981 }
5982
5983 StringAttr name;
5984 FIRRTLType type;
5985 LocWithInfo info(getToken().getLoc(), this);
5986 if (parseId(name, "expected port name") ||
5987 parseToken(FIRToken::colon, "expected ':' in port definition") ||
5988 parseType(type, "expected a type in port declaration"))
5989 return failure();
5990 Attribute domainInfoElement = {};
5991 size_t portIdx = resultPorts.size();
5992 if (auto domainType = dyn_cast<DomainType>(type)) {
5993 // Domain information is now stored in the type itself.
5994 // Domain type ports have no associations.
5995 domainInfoElement = ArrayAttr::get(getContext(), {});
5996 } else {
5997 if (getToken().is(FIRToken::kw_domains))
5998 if (parseDomains(domainNames[portIdx], nameToIndex))
5999 return failure();
6000 }
6001
6002 if (info.parseOptionalInfo())
6003 return failure();
6004
6005 StringAttr innerSym = {};
6006 resultPorts.push_back(PortInfo{name,
6007 type,
6008 direction::get(isOutput),
6009 innerSym,
6010 info.getLoc(),
6011 {},
6012 domainInfoElement});
6013 resultPortLocs.push_back(info.getFIRLoc());
6014 nameToIndex.insert({name, portIdx});
6015 }
6016
6017 // Apply domain assocations to ports.
6018 for (size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
6019 auto &port = resultPorts[portIdx];
6020 Attribute &attr = port.domains;
6021 if (attr)
6022 continue;
6023
6024 SmallVector<Attribute> domainInfo;
6025 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
6026 return failure();
6027 attr = ArrayAttr::get(getContext(), domainInfo);
6028 }
6029
6030 // Check for port name collisions.
6031 SmallDenseMap<Attribute, SMLoc> portIds;
6032 for (auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
6033 PortInfo &port = std::get<0>(portAndLoc);
6034 auto &entry = portIds[port.name];
6035 if (!entry.isValid()) {
6036 entry = std::get<1>(portAndLoc);
6037 continue;
6038 }
6039
6040 emitError(std::get<1>(portAndLoc),
6041 "redefinition of name '" + port.getName() + "'")
6042 .attachNote(translateLocation(entry))
6043 << "previous definition here";
6044 return failure();
6045 }
6046
6047 return success();
6048}
6049
6050/// We're going to defer parsing this module, so just skip tokens until we
6051/// get to the next module or the end of the file.
6052ParseResult FIRCircuitParser::skipToModuleEnd(unsigned indent) {
6053 while (true) {
6054 switch (getToken().getKind()) {
6055
6056 // End of file or invalid token will be handled by outer level.
6057 case FIRToken::eof:
6058 case FIRToken::error:
6059 return success();
6060
6061 // If we got to the next top-level declaration, then we're done.
6062 case FIRToken::kw_class:
6063 case FIRToken::kw_domain:
6064 case FIRToken::kw_declgroup:
6065 case FIRToken::kw_extclass:
6066 case FIRToken::kw_extmodule:
6067 case FIRToken::kw_intmodule:
6068 case FIRToken::kw_formal:
6069 case FIRToken::kw_module:
6070 case FIRToken::kw_public:
6071 case FIRToken::kw_layer:
6072 case FIRToken::kw_option:
6073 case FIRToken::kw_simulation:
6074 case FIRToken::kw_type:
6075 // All module declarations should have the same indentation
6076 // level. Use this fact to differentiate between module
6077 // declarations and usages of "module" as identifiers.
6078 if (getIndentation() == indent)
6079 return success();
6080 [[fallthrough]];
6081 default:
6082 consumeToken();
6083 break;
6084 }
6085 }
6086}
6087
6088/// parameter-list ::= parameter*
6089/// parameter ::= 'parameter' param NEWLINE
6090ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
6091 SmallVector<Attribute, 8> parameters;
6092 SmallPtrSet<StringAttr, 8> seen;
6093 while (consumeIf(FIRToken::kw_parameter)) {
6094 StringAttr name;
6095 Attribute value;
6096 SMLoc loc;
6097 if (parseParameter(name, value, loc))
6098 return failure();
6099 auto typedValue = dyn_cast<TypedAttr>(value);
6100 if (!typedValue)
6101 return emitError(loc)
6102 << "invalid value for parameter '" << name.getValue() << "'";
6103 if (!seen.insert(name).second)
6104 return emitError(loc,
6105 "redefinition of parameter '" + name.getValue() + "'");
6106 parameters.push_back(ParamDeclAttr::get(name, typedValue));
6107 }
6108 resultParameters = ArrayAttr::get(getContext(), parameters);
6109 return success();
6110}
6111
6112/// class ::= 'class' id ':' info? INDENT portlist simple_stmt_block DEDENT
6113ParseResult FIRCircuitParser::parseClass(CircuitOp circuit, unsigned indent) {
6114 StringAttr name;
6115 SmallVector<PortInfo, 8> portList;
6116 SmallVector<SMLoc> portLocs;
6117 LocWithInfo info(getToken().getLoc(), this);
6118
6119 if (requireFeature({6, 0, 0}, "classes"))
6120 return failure();
6121
6122 consumeToken(FIRToken::kw_class);
6123 if (parseId(name, "expected class name") ||
6124 parseToken(FIRToken::colon, "expected ':' in class definition") ||
6125 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
6126 return failure();
6127
6128 if (name == circuit.getName())
6129 return mlir::emitError(info.getLoc(),
6130 "class cannot be the top of a circuit");
6131
6132 for (auto &portInfo : portList)
6133 if (!isa<PropertyType>(portInfo.type))
6134 return mlir::emitError(portInfo.loc,
6135 "ports on classes must be properties");
6136
6137 // build it
6138 auto builder = circuit.getBodyBuilder();
6139 auto classOp = ClassOp::create(builder, info.getLoc(), name, portList);
6140 classOp.setPrivate();
6141 deferredModules.emplace_back(
6142 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
6143
6144 // Stash the class name -> op in the constants, so we can resolve Inst types.
6145 getConstants().classMap[name.getValue()] = classOp;
6146 return skipToModuleEnd(indent);
6147}
6148
6149/// domain ::= 'domain' id ':' info?
6150ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit, unsigned indent) {
6151 consumeToken(FIRToken::kw_domain);
6152
6153 StringAttr name;
6154 LocWithInfo info(getToken().getLoc(), this);
6155 if (parseId(name, "domain name") ||
6156 parseToken(FIRToken::colon, "expected ':' after domain definition") ||
6157 info.parseOptionalInfo())
6158 return failure();
6159
6160 SmallVector<Attribute> fields;
6161 while (true) {
6162 auto nextIndent = getIndentation();
6163 if (!nextIndent || *nextIndent <= indent)
6164 break;
6165
6166 StringAttr fieldName;
6167 PropertyType type;
6168 if (parseId(fieldName, "field name") ||
6169 parseToken(FIRToken::colon, "expected ':' after field name") ||
6170 parsePropertyType(type, "field type") || info.parseOptionalInfo())
6171 return failure();
6172
6173 fields.push_back(
6174 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
6175 }
6176
6177 auto builder = circuit.getBodyBuilder();
6178 auto domainOp =
6179 DomainOp::create(builder, info.getLoc(), name, /*sym_visibility=*/{},
6180 builder.getArrayAttr(fields));
6181
6182 // Stash the domain name -> op in the constants, so we can resolve Domain
6183 // types.
6184 getConstants().domainMap[name.getValue()] = domainOp;
6185
6186 return success();
6187}
6188
6189/// extclass ::= 'extclass' id ':' info? INDENT portlist DEDENT
6190ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
6191 unsigned indent) {
6192 StringAttr name;
6193 SmallVector<PortInfo, 8> portList;
6194 SmallVector<SMLoc> portLocs;
6195 LocWithInfo info(getToken().getLoc(), this);
6196
6197 if (requireFeature({6, 0, 0}, "classes"))
6198 return failure();
6199
6200 consumeToken(FIRToken::kw_extclass);
6201 if (parseId(name, "expected extclass name") ||
6202 parseToken(FIRToken::colon, "expected ':' in extclass definition") ||
6203 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
6204 return failure();
6205
6206 if (name == circuit.getName())
6207 return mlir::emitError(info.getLoc(),
6208 "extclass cannot be the top of a circuit");
6209
6210 for (auto &portInfo : portList)
6211 if (!isa<PropertyType>(portInfo.type))
6212 return mlir::emitError(portInfo.loc,
6213 "ports on extclasses must be properties");
6214
6215 // Build it
6216 auto builder = circuit.getBodyBuilder();
6217 auto extClassOp = ExtClassOp::create(builder, info.getLoc(), name, portList);
6218
6219 // Stash the class name -> op in the constants, so we can resolve Inst types.
6220 getConstants().classMap[name.getValue()] = extClassOp;
6221 return skipToModuleEnd(indent);
6222}
6223
6224/// extmodule ::=
6225/// 'extmodule' id requires? ':' info?
6226/// INDENT portlist defname? parameter-list DEDENT
6227/// defname ::= 'defname' '=' id NEWLINE
6228/// requires ::= 'requires' string (',' string)*
6229ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
6230 unsigned indent) {
6231 StringAttr name;
6232 ArrayAttr enabledLayers;
6233 ArrayAttr knownLayers;
6234 ArrayAttr externalRequirements;
6235 SmallVector<PortInfo, 8> portList;
6236 SmallVector<SMLoc> portLocs;
6237 LocWithInfo info(getToken().getLoc(), this);
6238 consumeToken(FIRToken::kw_extmodule);
6239 if (parseId(name, "expected extmodule name") ||
6240 parseExtModuleAttributesSpec(enabledLayers, knownLayers,
6241 externalRequirements) ||
6242 parseToken(FIRToken::colon, "expected ':' in extmodule definition") ||
6243 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
6244 return failure();
6245
6246 StringRef defName;
6247 if (consumeIf(FIRToken::kw_defname)) {
6248 if (parseToken(FIRToken::equal, "expected '=' in defname") ||
6249 parseId(defName, "expected defname name"))
6250 return failure();
6251 }
6252
6253 ArrayAttr parameters;
6254 if (parseParameterList(parameters))
6255 return failure();
6256
6257 if (version >= FIRVersion({4, 0, 0})) {
6258 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
6259 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6260 if (ftype.hasUninferredWidth())
6261 return emitError(loc, "extmodule port must have known width");
6262 }
6263 }
6264 }
6265
6266 auto builder = circuit.getBodyBuilder();
6267 auto isMainModule = (name == circuit.getName());
6268 auto convention =
6269 (isMainModule && getConstants().options.scalarizePublicModules) ||
6270 getConstants().options.scalarizeExtModules
6271 ? Convention::Scalarized
6272 : Convention::Internal;
6273 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6274 auto annotations = ArrayAttr::get(getContext(), {});
6275 auto extModuleOp = FExtModuleOp::create(
6276 builder, info.getLoc(), name, conventionAttr, portList, knownLayers,
6277 defName, annotations, parameters, enabledLayers, externalRequirements);
6278 auto visibility = isMainModule ? SymbolTable::Visibility::Public
6279 : SymbolTable::Visibility::Private;
6280 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
6281 return success();
6282}
6283
6284/// intmodule ::=
6285/// 'intmodule' id ':' info?
6286/// INDENT portlist intname parameter-list ref-list DEDENT
6287/// intname ::= 'intrinsic' '=' id NEWLINE
6288ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
6289 unsigned indent) {
6290 StringAttr name;
6291 StringRef intName;
6292 ArrayAttr enabledLayers;
6293 SmallVector<PortInfo, 8> portList;
6294 SmallVector<SMLoc> portLocs;
6295 LocWithInfo info(getToken().getLoc(), this);
6296 consumeToken(FIRToken::kw_intmodule);
6297 if (parseId(name, "expected intmodule name") ||
6298 parseModuleLayerSpec(enabledLayers) ||
6299 parseToken(FIRToken::colon, "expected ':' in intmodule definition") ||
6300 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent) ||
6301 parseToken(FIRToken::kw_intrinsic, "expected 'intrinsic'") ||
6302 parseToken(FIRToken::equal, "expected '=' in intrinsic") ||
6303 parseId(intName, "expected intrinsic name"))
6304 return failure();
6305
6306 ArrayAttr parameters;
6307 if (parseParameterList(parameters))
6308 return failure();
6309
6310 ArrayAttr annotations = getConstants().emptyArrayAttr;
6311 auto builder = circuit.getBodyBuilder();
6312 FIntModuleOp::create(builder, info.getLoc(), name, portList, intName,
6313 annotations, parameters, enabledLayers)
6314 .setPrivate();
6315 return success();
6316}
6317
6318/// module ::= 'module' id ':' info? INDENT portlist simple_stmt_block DEDENT
6319ParseResult FIRCircuitParser::parseModule(CircuitOp circuit, bool isPublic,
6320 unsigned indent) {
6321 StringAttr name;
6322 SmallVector<PortInfo, 8> portList;
6323 SmallVector<SMLoc> portLocs;
6324 ArrayAttr enabledLayers;
6325 auto modLoc = getToken().getLoc();
6326 LocWithInfo info(modLoc, this);
6327 consumeToken(FIRToken::kw_module);
6328 if (parseId(name, "expected module name") ||
6329 parseModuleLayerSpec(enabledLayers) ||
6330 parseToken(FIRToken::colon, "expected ':' in module definition") ||
6331 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
6332 return failure();
6333
6334 // The main module is implicitly public.
6335 if (name == circuit.getName()) {
6336 if (!isPublic && removedFeature({4, 0, 0}, "private main modules", modLoc))
6337 return failure();
6338 isPublic = true;
6339 }
6340
6341 if (isPublic && version >= FIRVersion({4, 0, 0})) {
6342 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
6343 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
6344 if (ftype.hasUninferredWidth())
6345 return emitError(loc, "public module port must have known width");
6346 if (ftype.hasUninferredReset())
6347 return emitError(loc,
6348 "public module port must have concrete reset type");
6349 }
6350 }
6351 }
6352
6353 ArrayAttr annotations = getConstants().emptyArrayAttr;
6354 auto convention = Convention::Internal;
6355 if (isPublic && getConstants().options.scalarizePublicModules)
6356 convention = Convention::Scalarized;
6357 if (!isPublic && getConstants().options.scalarizeInternalModules)
6358 convention = Convention::Scalarized;
6359 auto conventionAttr = ConventionAttr::get(getContext(), convention);
6360 auto builder = circuit.getBodyBuilder();
6361 auto moduleOp =
6362 FModuleOp::create(builder, info.getLoc(), name, conventionAttr, portList,
6363 annotations, enabledLayers);
6364
6365 auto visibility = isPublic ? SymbolTable::Visibility::Public
6366 : SymbolTable::Visibility::Private;
6367 SymbolTable::setSymbolVisibility(moduleOp, visibility);
6368
6369 // Parse the body of this module after all prototypes have been parsed. This
6370 // allows us to handle forward references correctly.
6371 deferredModules.emplace_back(DeferredModuleToParse{
6372 moduleOp, portLocs, getLexer().getCursor(), indent});
6373
6374 if (skipToModuleEnd(indent))
6375 return failure();
6376 return success();
6377}
6378
6379/// formal ::= 'formal' formal-like
6380ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit, unsigned indent) {
6381 consumeToken(FIRToken::kw_formal);
6382 return parseFormalLike<FormalOp>(circuit, indent);
6383}
6384
6385/// simulation ::= 'simulation' formal-like
6386ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
6387 unsigned indent) {
6388 consumeToken(FIRToken::kw_simulation);
6389 return parseFormalLike<SimulationOp>(circuit, indent);
6390}
6391
6392/// formal-like ::= formal-like-old | formal-like-new
6393/// formal-like-old ::= id 'of' id ',' 'bound' '=' int info?
6394/// formal-like-new ::= id 'of' id ':' info? INDENT (param NEWLINE)* DEDENT
6395template <class Op>
6396ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
6397 unsigned indent) {
6398 StringRef id, moduleName;
6399 int64_t bound = 0;
6400 LocWithInfo info(getToken().getLoc(), this);
6401 auto builder = circuit.getBodyBuilder();
6402
6403 // Parse the name and target module of the test.
6404 if (parseId(id, "expected test name") ||
6405 parseToken(FIRToken::kw_of, "expected 'of' in test") ||
6406 parseId(moduleName, "expected module name"))
6407 return failure();
6408
6409 // TODO: Remove the old `, bound = N` variant in favor of the new parameters.
6410 NamedAttrList params;
6411 if (consumeIf(FIRToken::comma)) {
6412 // Parse the old style declaration with a `, bound = N` suffix.
6413 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() != "bound")
6414 return emitError("expected 'bound' after ','");
6415 consumeToken();
6416 if (parseToken(FIRToken::equal, "expected '=' after 'bound'") ||
6417 parseIntLit(bound, "expected integer bound after '='"))
6418 return failure();
6419 if (bound <= 0)
6420 return emitError("bound must be a positive integer");
6421 if (info.parseOptionalInfo())
6422 return failure();
6423 params.set("bound", builder.getIntegerAttr(builder.getI32Type(), bound));
6424 } else {
6425 // Parse the new style declaration with a `:` and parameter list.
6426 if (parseToken(FIRToken::colon, "expected ':' in test") ||
6427 info.parseOptionalInfo())
6428 return failure();
6429 while (getIndentation() > indent) {
6430 StringAttr paramName;
6431 Attribute paramValue;
6432 SMLoc paramLoc;
6433 if (parseParameter(paramName, paramValue, paramLoc,
6434 /*allowAggregates=*/true))
6435 return failure();
6436 if (params.set(paramName, paramValue))
6437 return emitError(paramLoc, "redefinition of parameter '" +
6438 paramName.getValue() + "'");
6439 }
6440 }
6441
6442 Op::create(builder, info.getLoc(), id, /*sym_visibility=*/{}, moduleName,
6443 params.getDictionary(getContext()));
6444 return success();
6445}
6446
6447ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
6448 unsigned indent) {
6449 switch (getToken().getKind()) {
6450 case FIRToken::kw_class:
6451 return parseClass(circuit, indent);
6452 case FIRToken::kw_declgroup:
6453 if (requireFeature({3, 2, 0}, "optional groups") ||
6454 removedFeature({3, 3, 0}, "optional groups"))
6455 return failure();
6456 return parseLayer(circuit);
6457 case FIRToken::kw_domain:
6458 if (requireFeature(missingSpecFIRVersion, "domains"))
6459 return failure();
6460 return parseDomain(circuit, indent);
6461 case FIRToken::kw_extclass:
6462 return parseExtClass(circuit, indent);
6463 case FIRToken::kw_extmodule:
6464 return parseExtModule(circuit, indent);
6465 case FIRToken::kw_formal:
6466 if (requireFeature({4, 0, 0}, "formal tests"))
6467 return failure();
6468 return parseFormal(circuit, indent);
6469 case FIRToken::kw_intmodule:
6470 if (requireFeature({1, 2, 0}, "intrinsic modules") ||
6471 removedFeature({4, 0, 0}, "intrinsic modules"))
6472 return failure();
6473 return parseIntModule(circuit, indent);
6474 case FIRToken::kw_layer:
6475 if (requireFeature({3, 3, 0}, "layers"))
6476 return failure();
6477 return parseLayer(circuit);
6478 case FIRToken::kw_module:
6479 return parseModule(circuit, /*isPublic=*/false, indent);
6480 case FIRToken::kw_public:
6481 if (requireFeature({3, 3, 0}, "public modules"))
6482 return failure();
6483 consumeToken();
6484 if (getToken().getKind() == FIRToken::kw_module)
6485 return parseModule(circuit, /*isPublic=*/true, indent);
6486 return emitError(getToken().getLoc(), "only modules may be public");
6487 case FIRToken::kw_simulation:
6488 if (requireFeature(nextFIRVersion, "simulation tests"))
6489 return failure();
6490 return parseSimulation(circuit, indent);
6491 case FIRToken::kw_type:
6492 return parseTypeDecl();
6493 case FIRToken::kw_option:
6494 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
6495 return failure();
6496 return parseOptionDecl(circuit);
6497 default:
6498 return emitError(getToken().getLoc(), "unknown toplevel definition");
6499 }
6500}
6501
6502// Parse a type declaration.
6503ParseResult FIRCircuitParser::parseTypeDecl() {
6504 StringRef id;
6505 FIRRTLType type;
6506 consumeToken();
6507 auto loc = getToken().getLoc();
6508
6509 if (getToken().isKeyword())
6510 return emitError(loc) << "cannot use keyword '" << getToken().getSpelling()
6511 << "' for type alias name";
6512
6513 if (parseId(id, "expected type name") ||
6514 parseToken(FIRToken::equal, "expected '=' in type decl") ||
6515 parseType(type, "expected a type"))
6516 return failure();
6517 auto name = StringAttr::get(type.getContext(), id);
6518 // Create type alias only for base types. Otherwise just pass through the
6519 // type.
6520 if (auto base = type_dyn_cast<FIRRTLBaseType>(type))
6521 type = BaseTypeAliasType::get(name, base);
6522 else
6523 emitWarning(loc)
6524 << "type alias for non-base type " << type
6525 << " is currently not supported. Type alias is stripped immediately";
6526
6527 if (!getConstants().aliasMap.insert({id, type}).second)
6528 return emitError(loc) << "type alias `" << name.getValue()
6529 << "` is already defined";
6530 return success();
6531}
6532
6533// Parse an option group declaration.
6534ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6535 StringRef id;
6536 consumeToken();
6537 auto loc = getToken().getLoc();
6538
6539 LocWithInfo info(getToken().getLoc(), this);
6540 if (parseId(id, "expected an option group name") ||
6541 parseToken(FIRToken::colon,
6542 "expected ':' after option group definition") ||
6543 info.parseOptionalInfo())
6544 return failure();
6545
6546 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6547 auto optionOp =
6548 OptionOp::create(builder, info.getLoc(), id, /*sym_visibility=*/{});
6549 auto *block = new Block;
6550 optionOp.getBody().push_back(block);
6551 builder.setInsertionPointToEnd(block);
6552
6553 auto baseIndent = getIndentation();
6554 StringSet<> cases;
6555 while (getIndentation() == baseIndent) {
6556 StringRef id;
6557 LocWithInfo caseInfo(getToken().getLoc(), this);
6558 if (parseId(id, "expected an option case ID") ||
6559 caseInfo.parseOptionalInfo())
6560 return failure();
6561
6562 if (!cases.insert(id).second)
6563 return emitError(loc)
6564 << "duplicate option case definition '" << id << "'";
6565
6566 OptionCaseOp::create(builder, caseInfo.getLoc(), id);
6567 }
6568
6569 return success();
6570}
6571
6572// Parse a layer definition.
6573ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6574 auto baseIndent = getIndentation();
6575
6576 // A stack of all layers that are possibly parents of the current layer.
6577 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6578
6579 // Parse a single layer and add it to the layerStack.
6580 auto parseOne = [&](Block *block) -> ParseResult {
6581 auto indent = getIndentation();
6582 StringRef id, convention;
6583 LocWithInfo info(getToken().getLoc(), this);
6584 consumeToken();
6585 if (parseId(id, "expected layer name") ||
6586 parseToken(FIRToken::comma, "expected ','") ||
6587 parseGetSpelling(convention))
6588 return failure();
6589
6590 auto layerConvention = symbolizeLayerConvention(convention);
6591 if (!layerConvention) {
6592 emitError() << "unknown convention '" << convention
6593 << "' (did you misspell it?)";
6594 return failure();
6595 }
6596 if (layerConvention == LayerConvention::Inline &&
6597 requireFeature({4, 1, 0}, "inline layers"))
6598 return failure();
6599 consumeToken();
6600
6601 hw::OutputFileAttr outputDir;
6602 if (consumeIf(FIRToken::comma)) {
6603 if (getToken().getKind() == FIRToken::string) {
6604 auto text = getToken().getStringValue();
6605 if (text.empty())
6606 return emitError() << "output directory must not be blank";
6607 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6608 consumeToken(FIRToken::string);
6609 }
6610 }
6611
6612 if (parseToken(FIRToken::colon, "expected ':' after layer definition") ||
6613 info.parseOptionalInfo())
6614 return failure();
6615 auto builder = OpBuilder::atBlockEnd(block);
6616 // Create the layer definition and give it an empty block.
6617 auto layerOp = LayerOp::create(builder, info.getLoc(), id,
6618 /*sym_visibility=*/{}, *layerConvention);
6619 layerOp->getRegion(0).push_back(new Block());
6620 if (outputDir)
6621 layerOp->setAttr("output_file", outputDir);
6622 layerStack.push_back({indent, layerOp});
6623 return success();
6624 };
6625
6626 if (parseOne(circuit.getBodyBlock()))
6627 return failure();
6628
6629 // Parse any nested layers.
6630 while (getIndentation() > baseIndent) {
6631 switch (getToken().getKind()) {
6632 case FIRToken::kw_declgroup:
6633 case FIRToken::kw_layer: {
6634 // Pop nested layers off the stack until we find out what layer to insert
6635 // this into.
6636 while (layerStack.back().first >= getIndentation())
6637 layerStack.pop_back();
6638 auto parentLayer = layerStack.back().second;
6639 if (parseOne(&parentLayer.getBody().front()))
6640 return failure();
6641 break;
6642 }
6643 default:
6644 return emitError("expected 'layer'"), failure();
6645 }
6646 }
6647
6648 return success();
6649}
6650
6651ParseResult FIRCircuitParser::resolveDomains(
6652 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6653 const DenseMap<Attribute, size_t> &nameToIndex,
6654 SmallVectorImpl<Attribute> &domainsByIndex) {
6655
6656 for (auto [attr, loc] : domainsByName) {
6657 auto domain = cast<StringAttr>(attr);
6658 auto indexItr = nameToIndex.find(domain);
6659 if (indexItr == nameToIndex.end()) {
6660 emitError(loc) << "unknown domain name '" << domain.getValue() << "'";
6661 return failure();
6662 }
6663 domainsByIndex.push_back(IntegerAttr::get(
6664 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6665 indexItr->second));
6666 }
6667
6668 return success();
6669}
6670
6671ParseResult FIRCircuitParser::parseDomains(
6672 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6673 const DenseMap<Attribute, size_t> &nameToIndex) {
6674 if (requireFeature(missingSpecFIRVersion, "domains"))
6675 return failure();
6676 if (parseToken(FIRToken::kw_domains, "expected 'domains'") ||
6677 parseToken(FIRToken::l_square, "expected '['"))
6678 return failure();
6679
6680 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6681 StringAttr domain;
6682 auto domainLoc = getToken().getLoc();
6683 if (parseId(domain, "expected domain name"))
6684 return failure();
6685 domains.push_back({domain, domainLoc});
6686 return success();
6687 }))
6688 return failure();
6689
6690 return success();
6691}
6692
6693// Parse the body of this module.
6694ParseResult
6695FIRCircuitParser::parseModuleBody(const SymbolTable &circuitSymTbl,
6696 DeferredModuleToParse &deferredModule,
6697 InnerSymFixups &fixups) {
6698 FModuleLike moduleOp = deferredModule.moduleOp;
6699 auto &body = moduleOp->getRegion(0).front();
6700 auto &portLocs = deferredModule.portLocs;
6701
6702 // We parse the body of this module with its own lexer, enabling parallel
6703 // parsing with the rest of the other module bodies.
6704 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6705
6706 // Reset the parser/lexer state back to right after the port list.
6707 deferredModule.lexerCursor.restore(moduleBodyLexer);
6708
6709 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6710 version);
6711
6712 // Install all of the ports into the symbol table, associated with their
6713 // block arguments.
6714 auto portList = moduleOp.getPorts();
6715 auto portArgs = body.getArguments();
6716 for (auto tuple : llvm::zip(portList, portLocs, portArgs)) {
6717 PortInfo &port = std::get<0>(tuple);
6718 llvm::SMLoc loc = std::get<1>(tuple);
6719 BlockArgument portArg = std::get<2>(tuple);
6720 assert(!port.sym);
6721 if (moduleContext.addSymbolEntry(port.getName(), portArg, loc))
6722 return failure();
6723 }
6724
6725 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6726
6727 // Parse the moduleBlock.
6728 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6729 if (failed(result))
6730 return result;
6731
6732 return success();
6733}
6734
6735/// file ::= circuit
6736/// versionHeader ::= 'FIRRTL' 'version' versionLit NEWLINE
6737/// circuit ::= versionHeader? 'circuit' id ':' info? INDENT module* DEDENT EOF
6738///
6739/// If non-null, annotationsBuf is a memory buffer containing JSON annotations.
6740///
6741ParseResult FIRCircuitParser::parseCircuit(
6742 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6743 mlir::TimingScope &ts) {
6744
6745 auto indent = getIndentation();
6746 if (parseToken(FIRToken::kw_FIRRTL, "expected 'FIRRTL'"))
6747 return failure();
6748 if (!indent.has_value())
6749 return emitError("'FIRRTL' must be first token on its line");
6750 if (parseToken(FIRToken::kw_version, "expected version after 'FIRRTL'") ||
6751 parseVersionLit("expected version literal"))
6752 return failure();
6753 indent = getIndentation();
6754
6755 if (!indent.has_value())
6756 return emitError("'circuit' must be first token on its line");
6757 unsigned circuitIndent = *indent;
6758
6759 LocWithInfo info(getToken().getLoc(), this);
6760 StringAttr name;
6761 SMLoc inlineAnnotationsLoc;
6762 StringRef inlineAnnotations;
6763
6764 // A file must contain a top level `circuit` definition.
6765 if (parseToken(FIRToken::kw_circuit,
6766 "expected a top-level 'circuit' definition") ||
6767 parseId(name, "expected circuit name") ||
6768 parseToken(FIRToken::colon, "expected ':' in circuit definition") ||
6769 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6770 info.parseOptionalInfo())
6771 return failure();
6772
6773 // Create the top-level circuit op in the MLIR module.
6774 OpBuilder b(mlirModule.getBodyRegion());
6775 auto circuit = CircuitOp::create(b, info.getLoc(), name);
6776
6777 // A timer to get execution time of annotation parsing.
6778 auto parseAnnotationTimer = ts.nest("Parse annotations");
6779
6780 // Deal with any inline annotations, if they exist. These are processed
6781 // first to place any annotations from an annotation file *after* the inline
6782 // annotations. While arbitrary, this makes the annotation file have
6783 // "append" semantics.
6784 SmallVector<Attribute> annos;
6785 if (!inlineAnnotations.empty())
6786 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6787 return failure();
6788
6789 // Deal with the annotation file if one was specified
6790 for (auto *annotationsBuf : annotationsBufs)
6791 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
6792 annos))
6793 return failure();
6794
6795 parseAnnotationTimer.stop();
6796
6797 // Get annotations that are supposed to be specially handled by the
6798 // LowerAnnotations pass.
6799 if (!annos.empty())
6800 circuit->setAttr(rawAnnotations, b.getArrayAttr(annos));
6801
6802 // A timer to get execution time of module parsing.
6803 auto parseTimer = ts.nest("Parse modules");
6804 deferredModules.reserve(16);
6805
6806 // Parse any contained modules.
6807 while (true) {
6808 switch (getToken().getKind()) {
6809 // If we got to the end of the file, then we're done.
6810 case FIRToken::eof:
6811 goto DoneParsing;
6812
6813 // If we got an error token, then the lexer already emitted an error,
6814 // just stop. We could introduce error recovery if there was demand for
6815 // it.
6816 case FIRToken::error:
6817 return failure();
6818
6819 default:
6820 emitError("unexpected token in circuit");
6821 return failure();
6822
6823 case FIRToken::kw_class:
6824 case FIRToken::kw_declgroup:
6825 case FIRToken::kw_domain:
6826 case FIRToken::kw_extclass:
6827 case FIRToken::kw_extmodule:
6828 case FIRToken::kw_intmodule:
6829 case FIRToken::kw_layer:
6830 case FIRToken::kw_formal:
6831 case FIRToken::kw_module:
6832 case FIRToken::kw_option:
6833 case FIRToken::kw_public:
6834 case FIRToken::kw_simulation:
6835 case FIRToken::kw_type: {
6836 auto indent = getIndentation();
6837 if (!indent.has_value())
6838 return emitError("'module' must be first token on its line"), failure();
6839 unsigned definitionIndent = *indent;
6840
6841 if (definitionIndent <= circuitIndent)
6842 return emitError("module should be indented more"), failure();
6843
6844 if (parseToplevelDefinition(circuit, definitionIndent))
6845 return failure();
6846 break;
6847 }
6848 }
6849 }
6850
6851 // After the outline of the file has been parsed, we can go ahead and parse
6852 // all the bodies. This allows us to resolve forward-referenced modules and
6853 // makes it possible to parse their bodies in parallel.
6854DoneParsing:
6855 // Each of the modules may translate source locations, and doing so touches
6856 // the SourceMgr to build a line number cache. This isn't thread safe, so we
6857 // proactively touch it to make sure that it is always already created.
6858 (void)getLexer().translateLocation(info.getFIRLoc());
6859
6860 // Pre-verify symbol table, so we can construct it next. Ideally, we would do
6861 // this verification through the trait.
6862 { // Memory is tight in parsing.
6863 // Check that all symbols are uniquely named within child regions.
6864 DenseMap<Attribute, Location> nameToOrigLoc;
6865 for (auto &op : *circuit.getBodyBlock()) {
6866 // Check for a symbol name attribute.
6867 auto symbol = dyn_cast<mlir::SymbolOpInterface>(&op);
6868 if (!symbol)
6869 continue;
6870
6871 auto nameAttr = symbol.getNameAttr();
6872
6873 // Try to insert this symbol into the table.
6874 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6875 if (!it.second) {
6876 op.emitError()
6877 .append("redefinition of symbol named '", nameAttr.getValue(), "'")
6878 .attachNote(it.first->second)
6879 .append("see existing symbol definition here");
6880 return failure();
6881 }
6882 }
6883 }
6884
6885 SymbolTable circuitSymTbl(circuit);
6886
6887 moduleFixups.resize(deferredModules.size());
6888
6889 // Stub out inner symbol namespace for each module,
6890 // none should be added so do this now to avoid walking later
6891 // to discover that this is the case.
6892 for (auto &d : deferredModules)
6893 innerSymbolNamespaces.get(d.moduleOp.getOperation());
6894
6895 // Next, parse all the module bodies.
6896 auto anyFailed = mlir::failableParallelForEachN(
6897 getContext(), 0, deferredModules.size(), [&](size_t index) {
6898 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6899 moduleFixups[index]))
6900 return failure();
6901 return success();
6902 });
6903 if (failed(anyFailed))
6904 return failure();
6905
6906 // Walk operations created that have inner symbol references
6907 // that need replacing now that it's safe to create inner symbols everywhere.
6908 for (auto &fixups : moduleFixups) {
6909 if (failed(fixups.resolve(innerSymbolNamespaces)))
6910 return failure();
6911 }
6912
6913 // Helper to transform a layer name specification of the form `A::B::C` into
6914 // a SymbolRefAttr.
6915 auto parseLayerName = [&](StringRef name) -> Attribute {
6916 // Parse the layer name into a SymbolRefAttr.
6917 auto [head, rest] = name.split(".");
6918 SmallVector<FlatSymbolRefAttr> nestedRefs;
6919 while (!rest.empty()) {
6920 StringRef next;
6921 std::tie(next, rest) = rest.split(".");
6922 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6923 }
6924 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6925 };
6926
6927 auto getArrayAttr = [&](ArrayRef<std::string> strArray, auto getAttr) {
6928 SmallVector<Attribute> attrArray;
6929 auto *context = getContext();
6930 for (const auto &str : strArray)
6931 attrArray.push_back(getAttr(str));
6932 if (attrArray.empty())
6933 return ArrayAttr();
6934 return ArrayAttr::get(context, attrArray);
6935 };
6936
6937 if (auto enableLayers =
6938 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6939 circuit.setEnableLayersAttr(enableLayers);
6940 if (auto disableLayers =
6941 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6942 circuit.setDisableLayersAttr(disableLayers);
6943
6944 auto getStrAttr = [&](StringRef str) -> Attribute {
6945 return StringAttr::get(getContext(), str);
6946 };
6947
6948 if (auto selectInstChoice =
6949 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6950 circuit.setSelectInstChoiceAttr(selectInstChoice);
6951
6952 circuit.setDefaultLayerSpecialization(
6953 getConstants().options.defaultLayerSpecialization);
6954
6955 return success();
6956}
6957
6958//===----------------------------------------------------------------------===//
6959// Driver
6960//===----------------------------------------------------------------------===//
6961
6962// Parse the specified .fir file into the specified MLIR context.
6963mlir::OwningOpRef<mlir::ModuleOp>
6964circt::firrtl::importFIRFile(SourceMgr &sourceMgr, MLIRContext *context,
6965 mlir::TimingScope &ts, FIRParserOptions options) {
6966 const auto *sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6967 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6968 unsigned fileID = 1;
6969 for (unsigned e = options.numAnnotationFiles + 1; fileID < e; ++fileID)
6970 annotationsBufs.push_back(
6971 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6972
6973 context->loadDialect<CHIRRTLDialect>();
6974 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6975
6976 // This is the result module we are parsing into.
6977 mlir::OwningOpRef<mlir::ModuleOp> module(ModuleOp::create(
6978 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6979 /*line=*/0,
6980 /*column=*/0)));
6981 SharedParserConstants state(context, options);
6982 FIRLexer lexer(sourceMgr, context);
6983 if (FIRCircuitParser(state, lexer, *module, minimumFIRVersion)
6984 .parseCircuit(annotationsBufs, ts))
6985 return nullptr;
6986
6987 // Make sure the parse module has no other structural problems detected by
6988 // the verifier.
6989 auto circuitVerificationTimer = ts.nest("Verify circuit");
6990 if (failed(verify(*module)))
6991 return {};
6992
6993 return module;
6994}
6995
6997 static mlir::TranslateToMLIRRegistration fromFIR(
6998 "import-firrtl", "import .fir",
6999 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
7000 mlir::TimingScope ts;
7001 return importFIRFile(sourceMgr, context, ts);
7002 });
7003}
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > &parameters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
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)
Definition Mem2Reg.cpp:193
false return failure()
Parse an optional keyword or string and set instance into 'result'.
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
return success()
NamedAttrList attrs
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...
FIRParser *const parser
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.
SMLoc getFIRLoc() const
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Definition FieldRef.h:64
Value getValue() const
Get the Value which created this location.
Definition FieldRef.h:39
This implements a lexer for .fir files.
Definition FIRLexer.h:101
bool isNot(Kind k) const
Definition FIRLexer.h:61
StringRef getSpelling() const
Definition FIRLexer.h:45
bool is(Kind K) const
Definition FIRLexer.h:49
std::string getStringValue() const
Given a token containing a string literal, return its value, including removing the quote characters ...
Definition FIRLexer.cpp:58
llvm::SMLoc getLoc() const
Definition FIRLexer.cpp:33
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.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition CalyxOps.cpp:56
mlir::Type innerType(mlir::Type type)
Definition ESITypes.cpp:423
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.
Definition FIRRTLEnums.h:36
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
constexpr FIRVersion nextFIRVersion(7, 0, 0)
The next version of FIRRTL that is not yet released.
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.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs, bool warnOnTruncation=false)
Emit a connect between two values.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
BaseTy type_dyn_cast(Type type)
constexpr FIRVersion missingSpecFIRVersion
A marker for parser features that are currently missing from the spec.
Definition FIRParser.h:147
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
bool type_isa(Type type)
constexpr FIRVersion minimumFIRVersion(2, 0, 0)
The current minimum version of FIRRTL that the parser supports.
bool importAnnotationsFromJSONRaw(llvm::json::Value &value, SmallVectorImpl< Attribute > &annotations, llvm::json::Path path, MLIRContext *context)
Deserialize a JSON value into FIRRTL Annotations.
void info(Twine message)
Definition LSPUtils.cpp:20
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
unsigned numAnnotationFiles
The number of annotation files that were specified on the command line.
Definition FIRParser.h:51
InfoLocHandling infoLocatorHandling
Definition FIRParser.h:47
InfoLocHandling
Specify how @info locators should be handled.
Definition FIRParser.h:37
@ IgnoreInfo
If this is set to true, the @info locators are ignored, and the locations are set to the location in ...
Definition FIRParser.h:40
The FIRRTL specification version.
Definition FIRParser.h:89
static std::optional< FIRVersion > fromString(StringRef str)
Parse a version string of the form "major.minor.patch".
Definition FIRParser.h:115