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