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