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