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 // For FIRRTL versions < 5.0.0, don't process special substitutions
3134 if (version < FIRVersion(5, 0, 0)) {
3135 operands.append(specOperands.begin(), specOperands.end());
3136 formatStringResult =
3137 builder.getStringAttr(FIRToken::getStringValue(formatString));
3138 return success();
3139 }
3140
3141 // Use the utility function to parse the format string
3142 auto loc = translateLocation(formatStringLoc);
3144 builder, loc, FIRToken::getStringValue(formatString), specOperands,
3145 formatStringResult, operands);
3146 return result;
3147}
3148
3149/// printf ::= 'printf(' exp exp StringLit exp* ')' name? info?
3150ParseResult FIRStmtParser::parsePrintf() {
3151 auto startTok = consumeToken(FIRToken::lp_printf);
3152
3153 Value clock, condition;
3154 StringRef formatString;
3155 if (parseExp(clock, "expected clock expression in printf") ||
3156 parseToken(FIRToken::comma, "expected ','") ||
3157 parseExp(condition, "expected condition in printf") ||
3158 parseToken(FIRToken::comma, "expected ','"))
3159 return failure();
3160
3161 auto formatStringLoc = getToken().getLoc();
3162 if (parseGetSpelling(formatString) ||
3163 parseToken(FIRToken::string, "expected format string in printf"))
3164 return failure();
3165
3166 SmallVector<Value, 4> specOperands;
3167 while (consumeIf(FIRToken::comma)) {
3168 specOperands.push_back({});
3169 if (parseExp(specOperands.back(), "expected operand in printf"))
3170 return failure();
3171 }
3172
3173 StringAttr name;
3174 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3175 parseOptionalName(name) || parseOptionalInfo())
3176 return failure();
3177
3178 locationProcessor.setLoc(startTok.getLoc());
3179
3180 StringAttr formatStrUnescaped;
3181 SmallVector<Value> operands;
3182 if (parseFormatString(formatStringLoc, formatString, specOperands,
3183 formatStrUnescaped, operands))
3184 return failure();
3185
3186 PrintFOp::create(builder, clock, condition, formatStrUnescaped, operands,
3187 name);
3188 return success();
3189}
3190
3191/// fprintf ::= 'fprintf(' exp exp StringLit StringLit exp* ')' name? info?
3192ParseResult FIRStmtParser::parseFPrintf() {
3193 if (requireFeature(nextFIRVersion, "fprintf"))
3194 return failure();
3195 auto startTok = consumeToken(FIRToken::lp_fprintf);
3196
3197 Value clock, condition;
3198 StringRef outputFile, formatString;
3199 if (parseExp(clock, "expected clock expression in fprintf") ||
3200 parseToken(FIRToken::comma, "expected ','") ||
3201 parseExp(condition, "expected condition in fprintf") ||
3202 parseToken(FIRToken::comma, "expected ','"))
3203 return failure();
3204
3205 auto outputFileLoc = getToken().getLoc();
3206 if (parseGetSpelling(outputFile) ||
3207 parseToken(FIRToken::string, "expected output file in fprintf"))
3208 return failure();
3209
3210 SmallVector<Value, 4> outputFileSpecOperands;
3211 while (consumeIf(FIRToken::comma)) {
3212 // Stop parsing operands when we see the format string.
3213 if (getToken().getKind() == FIRToken::string)
3214 break;
3215 outputFileSpecOperands.push_back({});
3216 if (parseExp(outputFileSpecOperands.back(), "expected operand in fprintf"))
3217 return failure();
3218 }
3219
3220 auto formatStringLoc = getToken().getLoc();
3221 if (parseGetSpelling(formatString) ||
3222 parseToken(FIRToken::string, "expected format string in printf"))
3223 return failure();
3224
3225 SmallVector<Value, 4> specOperands;
3226 while (consumeIf(FIRToken::comma)) {
3227 specOperands.push_back({});
3228 if (parseExp(specOperands.back(), "expected operand in fprintf"))
3229 return failure();
3230 }
3231
3232 StringAttr name;
3233 if (parseToken(FIRToken::r_paren, "expected ')'") ||
3234 parseOptionalName(name) || parseOptionalInfo())
3235 return failure();
3236
3237 locationProcessor.setLoc(startTok.getLoc());
3238
3239 StringAttr outputFileNameStrUnescaped;
3240 SmallVector<Value> outputFileOperands;
3241 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3242 outputFileNameStrUnescaped, outputFileOperands))
3243 return failure();
3244
3245 StringAttr formatStrUnescaped;
3246 SmallVector<Value> operands;
3247 if (parseFormatString(formatStringLoc, formatString, specOperands,
3248 formatStrUnescaped, operands))
3249 return failure();
3250
3251 FPrintFOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3252 outputFileOperands, formatStrUnescaped, operands, name);
3253 return success();
3254}
3255
3256/// fflush ::= 'fflush(' exp exp (StringLit exp*)? ')' info?
3257ParseResult FIRStmtParser::parseFFlush() {
3258 if (requireFeature(nextFIRVersion, "fflush"))
3259 return failure();
3260
3261 auto startTok = consumeToken(FIRToken::lp_fflush);
3262
3263 Value clock, condition;
3264 if (parseExp(clock, "expected clock expression in 'fflush'") ||
3265 parseToken(FIRToken::comma, "expected ','") ||
3266 parseExp(condition, "expected condition in 'fflush'"))
3267 return failure();
3268
3269 locationProcessor.setLoc(startTok.getLoc());
3270 StringAttr outputFileNameStrUnescaped;
3271 SmallVector<Value> outputFileOperands;
3272 // Parse file name if present.
3273 if (consumeIf(FIRToken::comma)) {
3274 SmallVector<Value, 4> outputFileSpecOperands;
3275 auto outputFileLoc = getToken().getLoc();
3276 StringRef outputFile;
3277 if (parseGetSpelling(outputFile) ||
3278 parseToken(FIRToken::string, "expected output file in fflush"))
3279 return failure();
3280
3281 while (consumeIf(FIRToken::comma)) {
3282 outputFileSpecOperands.push_back({});
3283 if (parseExp(outputFileSpecOperands.back(), "expected operand in fflush"))
3284 return failure();
3285 }
3286
3287 if (parseFormatString(outputFileLoc, outputFile, outputFileSpecOperands,
3288 outputFileNameStrUnescaped, outputFileOperands))
3289 return failure();
3290 }
3291
3292 if (parseToken(FIRToken::r_paren, "expected ')' in 'fflush'") ||
3293 parseOptionalInfo())
3294 return failure();
3295
3296 FFlushOp::create(builder, clock, condition, outputFileNameStrUnescaped,
3297 outputFileOperands);
3298 return success();
3299}
3300
3301/// skip ::= 'skip' info?
3302ParseResult FIRStmtParser::parseSkip() {
3303 auto startTok = consumeToken(FIRToken::kw_skip);
3304
3305 // If this was actually the start of a connect or something else handle
3306 // that.
3307 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3308 return *isExpr;
3309
3310 if (parseOptionalInfo())
3311 return failure();
3312
3313 locationProcessor.setLoc(startTok.getLoc());
3314 SkipOp::create(builder);
3315 return success();
3316}
3317
3318/// stop ::= 'stop(' exp exp intLit ')' info?
3319ParseResult FIRStmtParser::parseStop() {
3320 auto startTok = consumeToken(FIRToken::lp_stop);
3321
3322 Value clock, condition;
3323 int64_t exitCode;
3324 StringAttr name;
3325 if (parseExp(clock, "expected clock expression in 'stop'") ||
3326 parseToken(FIRToken::comma, "expected ','") ||
3327 parseExp(condition, "expected condition in 'stop'") ||
3328 parseToken(FIRToken::comma, "expected ','") ||
3329 parseIntLit(exitCode, "expected exit code in 'stop'") ||
3330 parseToken(FIRToken::r_paren, "expected ')' in 'stop'") ||
3331 parseOptionalName(name) || parseOptionalInfo())
3332 return failure();
3333
3334 locationProcessor.setLoc(startTok.getLoc());
3335 StopOp::create(builder, clock, condition, builder.getI32IntegerAttr(exitCode),
3336 name);
3337 return success();
3338}
3339
3340/// assert ::= 'assert(' exp exp exp StringLit exp*')' info?
3341ParseResult FIRStmtParser::parseAssert() {
3342 auto startTok = consumeToken(FIRToken::lp_assert);
3343
3344 Value clock, predicate, enable;
3345 StringRef formatString;
3346 StringAttr name;
3347 if (parseExp(clock, "expected clock expression in 'assert'") ||
3348 parseToken(FIRToken::comma, "expected ','") ||
3349 parseExp(predicate, "expected predicate in 'assert'") ||
3350 parseToken(FIRToken::comma, "expected ','") ||
3351 parseExp(enable, "expected enable in 'assert'") ||
3352 parseToken(FIRToken::comma, "expected ','") ||
3353 parseGetSpelling(formatString) ||
3354 parseToken(FIRToken::string, "expected format string in 'assert'"))
3355 return failure();
3356
3357 SmallVector<Value, 4> operands;
3358 while (!consumeIf(FIRToken::r_paren)) {
3359 operands.push_back({});
3360 if (parseToken(FIRToken::comma, "expected ','") ||
3361 parseExp(operands.back(), "expected operand in 'assert'"))
3362 return failure();
3363 }
3364
3365 if (parseOptionalName(name) || parseOptionalInfo())
3366 return failure();
3367
3368 locationProcessor.setLoc(startTok.getLoc());
3369 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3370 AssertOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3371 operands, name.getValue());
3372 return success();
3373}
3374
3375/// assume ::= 'assume(' exp exp exp StringLit exp* ')' info?
3376ParseResult FIRStmtParser::parseAssume() {
3377 auto startTok = consumeToken(FIRToken::lp_assume);
3378
3379 Value clock, predicate, enable;
3380 StringRef formatString;
3381 StringAttr name;
3382 if (parseExp(clock, "expected clock expression in 'assume'") ||
3383 parseToken(FIRToken::comma, "expected ','") ||
3384 parseExp(predicate, "expected predicate in 'assume'") ||
3385 parseToken(FIRToken::comma, "expected ','") ||
3386 parseExp(enable, "expected enable in 'assume'") ||
3387 parseToken(FIRToken::comma, "expected ','") ||
3388 parseGetSpelling(formatString) ||
3389 parseToken(FIRToken::string, "expected format string in 'assume'"))
3390 return failure();
3391
3392 SmallVector<Value, 4> operands;
3393 while (!consumeIf(FIRToken::r_paren)) {
3394 operands.push_back({});
3395 if (parseToken(FIRToken::comma, "expected ','") ||
3396 parseExp(operands.back(), "expected operand in 'assume'"))
3397 return failure();
3398 }
3399
3400 if (parseOptionalName(name) || parseOptionalInfo())
3401 return failure();
3402
3403 locationProcessor.setLoc(startTok.getLoc());
3404 auto formatStrUnescaped = FIRToken::getStringValue(formatString);
3405 AssumeOp::create(builder, clock, predicate, enable, formatStrUnescaped,
3406 operands, name.getValue());
3407 return success();
3408}
3409
3410/// cover ::= 'cover(' exp exp exp StringLit ')' info?
3411ParseResult FIRStmtParser::parseCover() {
3412 auto startTok = consumeToken(FIRToken::lp_cover);
3413
3414 Value clock, predicate, enable;
3415 StringRef message;
3416 StringAttr name;
3417 if (parseExp(clock, "expected clock expression in 'cover'") ||
3418 parseToken(FIRToken::comma, "expected ','") ||
3419 parseExp(predicate, "expected predicate in 'cover'") ||
3420 parseToken(FIRToken::comma, "expected ','") ||
3421 parseExp(enable, "expected enable in 'cover'") ||
3422 parseToken(FIRToken::comma, "expected ','") ||
3423 parseGetSpelling(message) ||
3424 parseToken(FIRToken::string, "expected message in 'cover'") ||
3425 parseToken(FIRToken::r_paren, "expected ')' in 'cover'") ||
3426 parseOptionalName(name) || parseOptionalInfo())
3427 return failure();
3428
3429 locationProcessor.setLoc(startTok.getLoc());
3430 auto messageUnescaped = FIRToken::getStringValue(message);
3431 CoverOp::create(builder, clock, predicate, enable, messageUnescaped,
3432 ValueRange{}, name.getValue());
3433 return success();
3434}
3435
3436/// when ::= 'when' exp ':' info? suite? ('else' ( when | ':' info? suite?)
3437/// )? suite ::= simple_stmt | INDENT simple_stmt+ DEDENT
3438ParseResult FIRStmtParser::parseWhen(unsigned whenIndent) {
3439 auto startTok = consumeToken(FIRToken::kw_when);
3440
3441 // If this was actually the start of a connect or something else handle
3442 // that.
3443 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3444 return *isExpr;
3445
3446 Value condition;
3447 if (parseExp(condition, "expected condition in 'when'") ||
3448 parseToken(FIRToken::colon, "expected ':' in when") ||
3449 parseOptionalInfo())
3450 return failure();
3451
3452 locationProcessor.setLoc(startTok.getLoc());
3453 // Create the IR representation for the when.
3454 auto whenStmt = WhenOp::create(builder, condition, /*createElse*/ false);
3455
3456 // Parse the 'then' body into the 'then' region.
3457 if (parseSubBlock(whenStmt.getThenBlock(), whenIndent, layerSym))
3458 return failure();
3459
3460 // If the else is present, handle it otherwise we're done.
3461 if (getToken().isNot(FIRToken::kw_else))
3462 return success();
3463
3464 // If the 'else' is less indented than the when, then it must belong to some
3465 // containing 'when'.
3466 auto elseIndent = getIndentation();
3467 if (elseIndent && *elseIndent < whenIndent)
3468 return success();
3469
3470 consumeToken(FIRToken::kw_else);
3471
3472 // Create an else block to parse into.
3473 whenStmt.createElseRegion();
3474
3475 // If we have the ':' form, then handle it.
3476
3477 // Syntactic shorthand 'else when'. This uses the same indentation level as
3478 // the outer 'when'.
3479 if (getToken().is(FIRToken::kw_when)) {
3480 // We create a sub parser for the else block.
3481 auto subParser = std::make_unique<FIRStmtParser>(
3482 whenStmt.getElseBlock(), moduleContext, innerSymFixups, circuitSymTbl,
3483 version, layerSym);
3484
3485 return subParser->parseSimpleStmt(whenIndent);
3486 }
3487
3488 // Parse the 'else' body into the 'else' region.
3489 LocationAttr elseLoc; // ignore the else locator.
3490 if (parseToken(FIRToken::colon, "expected ':' after 'else'") ||
3491 parseOptionalInfoLocator(elseLoc) ||
3492 parseSubBlock(whenStmt.getElseBlock(), whenIndent, layerSym))
3493 return failure();
3494
3495 // TODO(firrtl spec): There is no reason for the 'else :' grammar to take an
3496 // info. It doesn't appear to be generated either.
3497 return success();
3498}
3499
3500/// enum-exp ::= enum-type '(' Id ( ',' exp )? ')'
3501ParseResult FIRStmtParser::parseEnumExp(Value &value) {
3502 auto startLoc = getToken().getLoc();
3503 locationProcessor.setLoc(startLoc);
3504 FIRRTLType type;
3505 if (parseEnumType(type))
3506 return failure();
3507
3508 // Check that the input type is a legal enumeration.
3509 auto enumType = type_dyn_cast<FEnumType>(type);
3510 if (!enumType)
3511 return emitError(startLoc,
3512 "expected enumeration type in enumeration expression");
3513
3514 StringRef tag;
3515 if (parseToken(FIRToken::l_paren, "expected '(' in enumeration expression") ||
3516 parseId(tag, "expected enumeration tag"))
3517 return failure();
3518
3519 Value input;
3520 if (consumeIf(FIRToken::r_paren)) {
3521 // If the payload is not specified, we create a 0 bit unsigned integer
3522 // constant.
3523 auto type = IntType::get(builder.getContext(), false, 0, true);
3524 Type attrType = IntegerType::get(getContext(), 0, IntegerType::Unsigned);
3525 auto attr = builder.getIntegerAttr(attrType, APInt(0, 0, false));
3526 input = ConstantOp::create(builder, type, attr);
3527 } else {
3528 // Otherwise we parse an expression.
3529 if (parseToken(FIRToken::comma, "expected ','") ||
3530 parseExp(input, "expected expression in enumeration value") ||
3531 parseToken(FIRToken::r_paren, "expected closing ')'"))
3532 return failure();
3533 }
3534
3535 value = FEnumCreateOp::create(builder, enumType, tag, input);
3536 return success();
3537}
3538
3539/// match ::= 'match' exp ':' info?
3540/// (INDENT ( Id ( '(' Id ')' )? ':'
3541/// (INDENT simple_stmt* DEDENT )?
3542/// )* DEDENT)?
3543ParseResult FIRStmtParser::parseMatch(unsigned matchIndent) {
3544 auto startTok = consumeToken(FIRToken::kw_match);
3545
3546 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
3547 return *isExpr;
3548
3549 Value input;
3550 if (parseExp(input, "expected expression in 'match'") ||
3551 parseToken(FIRToken::colon, "expected ':' in 'match'") ||
3552 parseOptionalInfo())
3553 return failure();
3554
3555 auto enumType = type_dyn_cast<FEnumType>(input.getType());
3556 if (!enumType)
3557 return mlir::emitError(
3558 input.getLoc(),
3559 "expected enumeration type for 'match' statement, but got ")
3560 << input.getType();
3561
3562 locationProcessor.setLoc(startTok.getLoc());
3563
3564 SmallVector<Attribute> tags;
3565 SmallVector<std::unique_ptr<Region>> regions;
3566 while (true) {
3567 auto tagLoc = getToken().getLoc();
3568
3569 // Only consume the keyword if the indentation is correct.
3570 auto caseIndent = getIndentation();
3571 if (!caseIndent || *caseIndent <= matchIndent)
3572 break;
3573
3574 // Parse the tag.
3575 StringRef tagSpelling;
3576 if (parseId(tagSpelling, "expected enumeration tag in match statement"))
3577 return failure();
3578 auto tagIndex = enumType.getElementIndex(tagSpelling);
3579 if (!tagIndex)
3580 return emitError(tagLoc, "tag ")
3581 << tagSpelling << " not a member of enumeration " << enumType;
3582 auto tag = IntegerAttr::get(IntegerType::get(getContext(), 32), *tagIndex);
3583 tags.push_back(tag);
3584
3585 // Add a new case to the match operation.
3586 auto *caseBlock = &regions.emplace_back(new Region)->emplaceBlock();
3587
3588 // Declarations are scoped to the case.
3589 FIRModuleContext::ContextScope scope(moduleContext, caseBlock);
3590
3591 // After parsing the region, we can release any new entries in
3592 // unbundledValues since the symbol table entries that refer to them will be
3593 // gone.
3594 UnbundledValueRestorer x(moduleContext.unbundledValues);
3595
3596 // Parse the argument.
3597 if (consumeIf(FIRToken::l_paren)) {
3598 StringAttr identifier;
3599 if (parseId(identifier, "expected identifier for 'case' binding"))
3600 return failure();
3601
3602 // Add an argument to the block.
3603 auto dataType = enumType.getElementType(*tagIndex);
3604 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3605
3606 if (moduleContext.addSymbolEntry(identifier, caseBlock->getArgument(0),
3607 startTok.getLoc()))
3608 return failure();
3609
3610 if (parseToken(FIRToken::r_paren, "expected ')' in match statement case"))
3611 return failure();
3612
3613 } else {
3614 auto dataType = IntType::get(builder.getContext(), false, 0);
3615 caseBlock->addArgument(dataType, LocWithInfo(tagLoc, this).getLoc());
3616 }
3617
3618 if (parseToken(FIRToken::colon, "expected ':' in match statement case"))
3619 return failure();
3620
3621 // Parse a block of statements that are indented more than the case.
3622 auto subParser = std::make_unique<FIRStmtParser>(
3623 *caseBlock, moduleContext, innerSymFixups, circuitSymTbl, version,
3624 layerSym);
3625 if (subParser->parseSimpleStmtBlock(*caseIndent))
3626 return failure();
3627 }
3628
3629 MatchOp::create(builder, input, ArrayAttr::get(getContext(), tags), regions);
3630 return success();
3631}
3632
3633/// domain_exp ::= id
3634/// domain_exp ::= domain_exp '.' id
3635/// domain_exp ::= domain_exp '[' int ']'
3636ParseResult FIRStmtParser::parseDomainExp(Value &result) {
3637 auto loc = getToken().getLoc();
3638 SymbolValueEntry entry;
3639 StringRef id;
3640 if (parseId(id, "expected domain expression") ||
3641 moduleContext.lookupSymbolEntry(entry, id, loc))
3642 return failure();
3643
3644 if (moduleContext.resolveSymbolEntry(result, entry, loc, false)) {
3645 StringRef field;
3646 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
3647 parseFieldId(field, "expected field name") ||
3648 moduleContext.resolveSymbolEntry(result, entry, field, loc))
3649 return failure();
3650 }
3651
3652 if (parseOptionalExpPostscript(result, /*allowDynamic=*/false))
3653 return failure();
3654
3655 auto type = result.getType();
3656 if (!type_isa<DomainType>(type))
3657 return emitError(loc) << "expected domain-type expression, got " << type;
3658
3659 return success();
3660}
3661
3662/// ref_expr ::= probe | rwprobe | static_reference
3663// NOLINTNEXTLINE(misc-no-recursion)
3664ParseResult FIRStmtParser::parseRefExp(Value &result, const Twine &message) {
3665 auto token = getToken().getKind();
3666 if (token == FIRToken::lp_probe)
3667 return parseProbe(result);
3668 if (token == FIRToken::lp_rwprobe)
3669 return parseRWProbe(result);
3670
3671 // Default to parsing as static reference expression.
3672 // Don't check token kind, we need to support literal_identifier and keywords,
3673 // let parseId handle this.
3674 return parseStaticRefExp(result, message);
3675}
3676
3677/// static_reference ::= id
3678/// ::= static_reference '.' id
3679/// ::= static_reference '[' int ']'
3680// NOLINTNEXTLINE(misc-no-recursion)
3681ParseResult FIRStmtParser::parseStaticRefExp(Value &result,
3682 const Twine &message) {
3683 auto parseIdOrInstance = [&]() -> ParseResult {
3684 StringRef id;
3685 auto loc = getToken().getLoc();
3686 SymbolValueEntry symtabEntry;
3687 if (parseId(id, message) ||
3688 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
3689 return failure();
3690
3691 // If we looked up a normal value, then we're done.
3692 if (!moduleContext.resolveSymbolEntry(result, symtabEntry, loc, false))
3693 return success();
3694
3695 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
3696
3697 // Handle the normal "instance.x" reference.
3698 StringRef fieldName;
3699 return failure(
3700 parseToken(FIRToken::period, "expected '.' in field reference") ||
3701 parseFieldId(fieldName, "expected field name") ||
3702 moduleContext.resolveSymbolEntry(result, symtabEntry, fieldName, loc));
3703 };
3704 return failure(parseIdOrInstance() ||
3705 parseOptionalExpPostscript(result, false));
3706}
3707/// static_reference ::= id
3708/// ::= static_reference '.' id
3709/// ::= static_reference '[' int ']'
3710/// Populate `refResult` with rwprobe "root" and parsed indexing.
3711/// Root is base-type target, and will be block argument or forceable.
3712/// Also set `Type`, so we can handle const-ness while visiting.
3713/// If root is an unbundled entry, replace with bounce wire and update
3714/// the unbundled entry to point to this for future users.
3715// NOLINTNEXTLINE(misc-no-recursion)
3716ParseResult FIRStmtParser::parseRWProbeStaticRefExp(FieldRef &refResult,
3717 Type &type,
3718 const Twine &message) {
3719 auto loc = getToken().getLoc();
3720
3721 StringRef id;
3722 SymbolValueEntry symtabEntry;
3723 if (parseId(id, message) ||
3724 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
3725 return failure();
3726
3727 // Three kinds of rwprobe targets:
3728 // 1. Instance result. Replace with a forceable wire, handle as (2).
3729 // 2. Forceable declaration.
3730 // 3. BlockArgument.
3731
3732 // We use inner symbols for all.
3733
3734 // Figure out what we have, and parse indexing.
3735 Value result;
3736 if (auto unbundledId = dyn_cast<UnbundledID>(symtabEntry)) {
3737 // This means we have an instance.
3738 auto &ubEntry = moduleContext.getUnbundledEntry(unbundledId - 1);
3739
3740 StringRef fieldName;
3741 auto loc = getToken().getLoc();
3742 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
3743 parseFieldId(fieldName, "expected field name"))
3744 return failure();
3745
3746 // Find unbundled entry for the specified result/port.
3747 // Get a reference to it--as we may update it (!!).
3748 auto fieldAttr = StringAttr::get(getContext(), fieldName);
3749 for (auto &elt : ubEntry) {
3750 if (elt.first == fieldAttr) {
3751 // Grab the unbundled entry /by reference/ so we can update it with the
3752 // new forceable wire we insert (if not already done).
3753 auto &instResult = elt.second;
3754
3755 // If it's already forceable, use that.
3756 auto *defining = instResult.getDefiningOp();
3757 assert(defining);
3758 if (isa<WireOp>(defining)) {
3759 result = instResult;
3760 break;
3761 }
3762
3763 // Otherwise, replace with bounce wire.
3764 auto type = instResult.getType();
3765
3766 // Either entire instance result is forceable + bounce wire, or reject.
3767 // (even if rwprobe is of a portion of the port)
3768 bool forceable = static_cast<bool>(
3770 if (!forceable)
3771 return emitError(loc, "unable to force instance result of type ")
3772 << type;
3773
3774 // Create bounce wire for the instance result.
3775 auto annotations = getConstants().emptyArrayAttr;
3776 StringAttr sym = {};
3777 SmallString<64> name;
3778 (id + "_" + fieldName + "_bounce").toVector(name);
3779 locationProcessor.setLoc(loc);
3780 OpBuilder::InsertionGuard guard(builder);
3781 builder.setInsertionPoint(defining);
3782 auto bounce =
3783 WireOp::create(builder, type, name, NameKindEnum::InterestingName,
3784 annotations, sym);
3785 auto bounceVal = bounce.getData();
3786
3787 // Replace instance result with reads from bounce wire.
3788 instResult.replaceAllUsesWith(bounceVal);
3789
3790 // Connect to/from the result per flow.
3791 builder.setInsertionPointAfter(defining);
3792 if (foldFlow(instResult) == Flow::Source)
3793 emitConnect(builder, bounceVal, instResult);
3794 else
3795 emitConnect(builder, instResult, bounceVal);
3796 // Set the parse result AND update `instResult` which is a reference to
3797 // the unbundled entry for the instance result, so that future uses also
3798 // find this new wire.
3799 result = instResult = bounce.getDataRaw();
3800 break;
3801 }
3802 }
3803
3804 if (!result) {
3805 emitError(loc, "use of invalid field name '")
3806 << fieldName << "' on bundle value";
3807 return failure();
3808 }
3809 } else {
3810 // This target can be a port or a regular value.
3811 result = cast<Value>(symtabEntry);
3812 }
3813
3814 assert(result);
3815 assert(isa<BlockArgument>(result) ||
3816 result.getDefiningOp<hw::InnerSymbolOpInterface>());
3817
3818 // We have our root value, we just need to parse the field id.
3819 // Build up the FieldRef as processing indexing expressions, and
3820 // compute the type so that we know the const-ness of the final expression.
3821 refResult = FieldRef(result, 0);
3822 type = result.getType();
3823 while (true) {
3824 if (consumeIf(FIRToken::period)) {
3825 SmallVector<StringRef, 3> fields;
3826 if (parseFieldIdSeq(fields, "expected field name"))
3827 return failure();
3828 for (auto fieldName : fields) {
3829 if (auto bundle = type_dyn_cast<BundleType>(type)) {
3830 if (auto index = bundle.getElementIndex(fieldName)) {
3831 refResult = refResult.getSubField(bundle.getFieldID(*index));
3832 type = bundle.getElementTypePreservingConst(*index);
3833 continue;
3834 }
3835 } else if (auto bundle = type_dyn_cast<OpenBundleType>(type)) {
3836 if (auto index = bundle.getElementIndex(fieldName)) {
3837 refResult = refResult.getSubField(bundle.getFieldID(*index));
3838 type = bundle.getElementTypePreservingConst(*index);
3839 continue;
3840 }
3841 } else {
3842 return emitError(loc, "subfield requires bundle operand")
3843 << "got " << type << "\n";
3844 }
3845 return emitError(loc,
3846 "unknown field '" + fieldName + "' in bundle type ")
3847 << type;
3848 }
3849 continue;
3850 }
3851 if (consumeIf(FIRToken::l_square)) {
3852 auto loc = getToken().getLoc();
3853 int32_t index;
3854 if (parseIntLit(index, "expected index") ||
3855 parseToken(FIRToken::r_square, "expected ']'"))
3856 return failure();
3857
3858 if (index < 0)
3859 return emitError(loc, "invalid index specifier");
3860
3861 if (auto vector = type_dyn_cast<FVectorType>(type)) {
3862 if ((unsigned)index < vector.getNumElements()) {
3863 refResult = refResult.getSubField(vector.getFieldID(index));
3864 type = vector.getElementTypePreservingConst();
3865 continue;
3866 }
3867 } else if (auto vector = type_dyn_cast<OpenVectorType>(type)) {
3868 if ((unsigned)index < vector.getNumElements()) {
3869 refResult = refResult.getSubField(vector.getFieldID(index));
3870 type = vector.getElementTypePreservingConst();
3871 continue;
3872 }
3873 } else {
3874 return emitError(loc, "subindex requires vector operand");
3875 }
3876 return emitError(loc, "out of range index '")
3877 << index << "' for vector type " << type;
3878 }
3879 return success();
3880 }
3881}
3882
3883/// intrinsic_expr ::= 'intrinsic(' Id (params)? ':' type exp* ')'
3884/// intrinsic_stmt ::= 'intrinsic(' Id (params)? (':' type )? exp* ')'
3885ParseResult FIRStmtParser::parseIntrinsic(Value &result, bool isStatement) {
3886 auto startTok = consumeToken(FIRToken::lp_intrinsic);
3887 StringRef intrinsic;
3888 ArrayAttr parameters;
3889 FIRRTLType type;
3890
3891 if (parseId(intrinsic, "expected intrinsic identifier") ||
3892 parseOptionalParams(parameters))
3893 return failure();
3894
3895 if (consumeIf(FIRToken::colon)) {
3896 if (parseType(type, "expected intrinsic return type"))
3897 return failure();
3898 } else if (!isStatement)
3899 return emitError("expected ':' in intrinsic expression");
3900
3901 SmallVector<Value> operands;
3902 auto loc = startTok.getLoc();
3903 if (consumeIf(FIRToken::comma)) {
3904 if (parseListUntil(FIRToken::r_paren, [&]() -> ParseResult {
3905 Value operand;
3906 if (parseExp(operand, "expected operand in intrinsic"))
3907 return failure();
3908 operands.push_back(operand);
3909 locationProcessor.setLoc(loc);
3910 return success();
3911 }))
3912 return failure();
3913 } else {
3914 if (parseToken(FIRToken::r_paren, "expected ')' in intrinsic"))
3915 return failure();
3916 }
3917
3918 if (isStatement)
3919 if (parseOptionalInfo())
3920 return failure();
3921
3922 locationProcessor.setLoc(loc);
3923
3924 auto op = GenericIntrinsicOp::create(
3925 builder, type, builder.getStringAttr(intrinsic), operands, parameters);
3926 if (type)
3927 result = op.getResult();
3928 return success();
3929}
3930
3931/// params ::= '<' param','* '>'
3932ParseResult FIRStmtParser::parseOptionalParams(ArrayAttr &resultParameters) {
3933 if (!consumeIf(FIRToken::less))
3934 return success();
3935
3936 SmallVector<Attribute, 8> parameters;
3937 SmallPtrSet<StringAttr, 8> seen;
3938 if (parseListUntil(FIRToken::greater, [&]() -> ParseResult {
3939 StringAttr name;
3940 Attribute value;
3941 SMLoc loc;
3942 if (parseParameter(name, value, loc))
3943 return failure();
3944 auto typedValue = dyn_cast<TypedAttr>(value);
3945 if (!typedValue)
3946 return emitError(loc)
3947 << "invalid value for parameter '" << name.getValue() << "'";
3948 if (!seen.insert(name).second)
3949 return emitError(loc, "redefinition of parameter '" +
3950 name.getValue() + "'");
3951 parameters.push_back(ParamDeclAttr::get(name, typedValue));
3952 return success();
3953 }))
3954 return failure();
3955
3956 resultParameters = ArrayAttr::get(getContext(), parameters);
3957 return success();
3958}
3959
3960/// path ::= 'path(' StringLit ')'
3961// NOLINTNEXTLINE(misc-no-recursion)
3962ParseResult FIRStmtParser::parsePathExp(Value &result) {
3963 auto startTok = consumeToken(FIRToken::lp_path);
3964 locationProcessor.setLoc(startTok.getLoc());
3965 StringRef target;
3966 if (parseGetSpelling(target) ||
3967 parseToken(FIRToken::string,
3968 "expected target string in path expression") ||
3969 parseToken(FIRToken::r_paren, "expected ')' in path expression"))
3970 return failure();
3971 result = UnresolvedPathOp::create(
3972 builder, StringAttr::get(getContext(), FIRToken::getStringValue(target)));
3973 return success();
3974}
3975
3976/// domain_define ::= 'domain_define' domain_exp '=' domain_exp info?
3977ParseResult FIRStmtParser::parseDomainDefine() {
3978 auto startTok = consumeToken(FIRToken::kw_domain_define);
3979 auto startLoc = startTok.getLoc();
3980 locationProcessor.setLoc(startLoc);
3981
3982 Value dest, src;
3983 if (requireFeature(missingSpecFIRVersion, "domains", startLoc) ||
3984 parseDomainExp(dest) || parseToken(FIRToken::equal, "expected '='") ||
3985 parseDomainExp(src) || parseOptionalInfo())
3986 return failure();
3987
3988 emitConnect(builder, dest, src);
3989 return success();
3990}
3991
3992/// define ::= 'define' static_reference '=' ref_expr info?
3993ParseResult FIRStmtParser::parseRefDefine() {
3994 auto startTok = consumeToken(FIRToken::kw_define);
3995
3996 Value src, target;
3997 if (parseStaticRefExp(target,
3998 "expected static reference expression in 'define'") ||
3999 parseToken(FIRToken::equal,
4000 "expected '=' after define reference expression") ||
4001 parseRefExp(src, "expected reference expression in 'define'") ||
4002 parseOptionalInfo())
4003 return failure();
4004
4005 // Check reference expressions are of reference type.
4006 if (!type_isa<RefType>(target.getType()))
4007 return emitError(startTok.getLoc(), "expected reference-type expression in "
4008 "'define' target (LHS), got ")
4009 << target.getType();
4010 if (!type_isa<RefType>(src.getType()))
4011 return emitError(startTok.getLoc(), "expected reference-type expression in "
4012 "'define' source (RHS), got ")
4013 << src.getType();
4014
4015 // static_reference doesn't differentiate which can be ref.sub'd, so check
4016 // this explicitly:
4017 if (isa_and_nonnull<RefSubOp>(target.getDefiningOp()))
4018 return emitError(startTok.getLoc(),
4019 "cannot define into a sub-element of a reference");
4020
4021 locationProcessor.setLoc(startTok.getLoc());
4022
4023 if (!areTypesRefCastable(target.getType(), src.getType()))
4024 return emitError(startTok.getLoc(), "cannot define reference of type ")
4025 << target.getType() << " with incompatible reference of type "
4026 << src.getType();
4027
4028 emitConnect(builder, target, src);
4029
4030 return success();
4031}
4032
4033/// read ::= '(' ref_expr ')'
4034/// XXX: spec says static_reference, allow ref_expr anyway for read(probe(x)).
4035ParseResult FIRStmtParser::parseRefRead(Value &result) {
4036 auto startTok = consumeToken(FIRToken::lp_read);
4037
4038 Value ref;
4039 if (parseRefExp(ref, "expected reference expression in 'read'") ||
4040 parseToken(FIRToken::r_paren, "expected ')' in 'read'"))
4041 return failure();
4042
4043 locationProcessor.setLoc(startTok.getLoc());
4044
4045 // Check argument is a ref-type value.
4046 if (!type_isa<RefType>(ref.getType()))
4047 return emitError(startTok.getLoc(),
4048 "expected reference-type expression in 'read', got ")
4049 << ref.getType();
4050
4051 result = RefResolveOp::create(builder, ref);
4052
4053 return success();
4054}
4055
4056/// probe ::= 'probe' '(' static_ref ')'
4057ParseResult FIRStmtParser::parseProbe(Value &result) {
4058 auto startTok = consumeToken(FIRToken::lp_probe);
4059
4060 Value staticRef;
4061 if (parseStaticRefExp(staticRef,
4062 "expected static reference expression in 'probe'") ||
4063 parseToken(FIRToken::r_paren, "expected ')' in 'probe'"))
4064 return failure();
4065
4066 locationProcessor.setLoc(startTok.getLoc());
4067
4068 // Check probe expression is base-type.
4069 if (!type_isa<FIRRTLBaseType>(staticRef.getType()))
4070 return emitError(startTok.getLoc(),
4071 "expected base-type expression in 'probe', got ")
4072 << staticRef.getType();
4073
4074 // Check for other unsupported reference sources.
4075 // TODO: Add to ref.send verifier / inferReturnTypes.
4076 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4077 MemoryDebugPortOp, MemoryPortAccessOp>(
4078 staticRef.getDefiningOp()))
4079 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4080
4081 result = RefSendOp::create(builder, staticRef);
4082
4083 return success();
4084}
4085
4086/// rwprobe ::= 'rwprobe' '(' static_ref ')'
4087ParseResult FIRStmtParser::parseRWProbe(Value &result) {
4088 auto startTok = consumeToken(FIRToken::lp_rwprobe);
4089
4090 FieldRef staticRef;
4091 Type parsedTargetType;
4092 if (parseRWProbeStaticRefExp(
4093 staticRef, parsedTargetType,
4094 "expected static reference expression in 'rwprobe'") ||
4095 parseToken(FIRToken::r_paren, "expected ')' in 'rwprobe'"))
4096 return failure();
4097
4098 locationProcessor.setLoc(startTok.getLoc());
4099
4100 // Checks:
4101 // Not public port (verifier)
4102
4103 // Check probe expression is base-type.
4104 auto targetType = type_dyn_cast<FIRRTLBaseType>(parsedTargetType);
4105 if (!targetType)
4106 return emitError(startTok.getLoc(),
4107 "expected base-type expression in 'rwprobe', got ")
4108 << parsedTargetType;
4109
4110 auto root = staticRef.getValue();
4111 auto *definingOp = root.getDefiningOp();
4112
4113 if (isa_and_nonnull<MemOp, CombMemOp, SeqMemOp, MemoryPortOp,
4114 MemoryDebugPortOp, MemoryPortAccessOp>(definingOp))
4115 return emitError(startTok.getLoc(), "cannot probe memories or their ports");
4116
4117 auto forceableType = firrtl::detail::getForceableResultType(true, targetType);
4118 if (!forceableType)
4119 return emitError(startTok.getLoc(), "cannot force target of type ")
4120 << targetType;
4121
4122 // Create the operation with a placeholder reference and add to fixup list.
4123 auto op = RWProbeOp::create(builder, forceableType,
4124 getConstants().placeholderInnerRef);
4125 innerSymFixups.add(op, getTargetFor(staticRef));
4126 result = op;
4127 return success();
4128}
4129
4130/// force ::= 'force(' exp exp ref_expr exp ')' info?
4131ParseResult FIRStmtParser::parseRefForce() {
4132 auto startTok = consumeToken(FIRToken::lp_force);
4133
4134 Value clock, pred, dest, src;
4135 if (parseExp(clock, "expected clock expression in force") ||
4136 parseToken(FIRToken::comma, "expected ','") ||
4137 parseExp(pred, "expected predicate expression in force") ||
4138 parseToken(FIRToken::comma, "expected ','") ||
4139 parseRefExp(dest, "expected destination reference expression in force") ||
4140 parseToken(FIRToken::comma, "expected ','") ||
4141 parseExp(src, "expected source expression in force") ||
4142 parseToken(FIRToken::r_paren, "expected ')' in force") ||
4143 parseOptionalInfo())
4144 return failure();
4145
4146 // Check reference expression is of reference type.
4147 auto ref = type_dyn_cast<RefType>(dest.getType());
4148 if (!ref || !ref.getForceable())
4149 return emitError(
4150 startTok.getLoc(),
4151 "expected rwprobe-type expression for force destination, got ")
4152 << dest.getType();
4153 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4154 if (!srcBaseType)
4155 return emitError(startTok.getLoc(),
4156 "expected base-type for force source, got ")
4157 << src.getType();
4158 if (!srcBaseType.isPassive())
4159 return emitError(startTok.getLoc(),
4160 "expected passive value for force source, got ")
4161 << srcBaseType;
4162
4163 locationProcessor.setLoc(startTok.getLoc());
4164
4165 // Cast ref to accommodate uninferred sources.
4166 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4167 if (noConstSrcType != ref.getType()) {
4168 // Try to cast destination to rwprobe of source type (dropping const).
4169 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4170 if (areTypesRefCastable(compatibleRWProbe, ref))
4171 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4172 else
4173 return emitError(startTok.getLoc(), "incompatible force source of type ")
4174 << src.getType() << " cannot target destination "
4175 << dest.getType();
4176 }
4177
4178 RefForceOp::create(builder, clock, pred, dest, src);
4179
4180 return success();
4181}
4182
4183/// force_initial ::= 'force_initial(' ref_expr exp ')' info?
4184ParseResult FIRStmtParser::parseRefForceInitial() {
4185 auto startTok = consumeToken(FIRToken::lp_force_initial);
4186
4187 Value dest, src;
4188 if (parseRefExp(
4189 dest, "expected destination reference expression in force_initial") ||
4190 parseToken(FIRToken::comma, "expected ','") ||
4191 parseExp(src, "expected source expression in force_initial") ||
4192 parseToken(FIRToken::r_paren, "expected ')' in force_initial") ||
4193 parseOptionalInfo())
4194 return failure();
4195
4196 // Check reference expression is of reference type.
4197 auto ref = type_dyn_cast<RefType>(dest.getType());
4198 if (!ref || !ref.getForceable())
4199 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4200 "force_initial destination, got ")
4201 << dest.getType();
4202 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4203 if (!srcBaseType)
4204 return emitError(startTok.getLoc(),
4205 "expected base-type expression for force_initial "
4206 "source, got ")
4207 << src.getType();
4208 if (!srcBaseType.isPassive())
4209 return emitError(startTok.getLoc(),
4210 "expected passive value for force_initial source, got ")
4211 << srcBaseType;
4212
4213 locationProcessor.setLoc(startTok.getLoc());
4214
4215 // Cast ref to accommodate uninferred sources.
4216 auto noConstSrcType = srcBaseType.getAllConstDroppedType();
4217 if (noConstSrcType != ref.getType()) {
4218 // Try to cast destination to rwprobe of source type (dropping const).
4219 auto compatibleRWProbe = RefType::get(noConstSrcType, true, ref.getLayer());
4220 if (areTypesRefCastable(compatibleRWProbe, ref))
4221 dest = RefCastOp::create(builder, compatibleRWProbe, dest);
4222 else
4223 return emitError(startTok.getLoc(),
4224 "incompatible force_initial source of type ")
4225 << src.getType() << " cannot target destination "
4226 << dest.getType();
4227 }
4228
4229 auto value = APInt::getAllOnes(1);
4230 auto type = UIntType::get(builder.getContext(), 1);
4231 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4232 value.getBitWidth(),
4233 IntegerType::Unsigned),
4234 value);
4235 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4236 RefForceInitialOp::create(builder, pred, dest, src);
4237
4238 return success();
4239}
4240
4241/// release ::= 'release(' exp exp ref_expr ')' info?
4242ParseResult FIRStmtParser::parseRefRelease() {
4243 auto startTok = consumeToken(FIRToken::lp_release);
4244
4245 Value clock, pred, dest;
4246 if (parseExp(clock, "expected clock expression in release") ||
4247 parseToken(FIRToken::comma, "expected ','") ||
4248 parseExp(pred, "expected predicate expression in release") ||
4249 parseToken(FIRToken::comma, "expected ','") ||
4250 parseRefExp(dest,
4251 "expected destination reference expression in release") ||
4252 parseToken(FIRToken::r_paren, "expected ')' in release") ||
4253 parseOptionalInfo())
4254 return failure();
4255
4256 // Check reference expression is of reference type.
4257 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4258 !ref || !ref.getForceable())
4259 return emitError(
4260 startTok.getLoc(),
4261 "expected rwprobe-type expression for release destination, got ")
4262 << dest.getType();
4263
4264 locationProcessor.setLoc(startTok.getLoc());
4265
4266 RefReleaseOp::create(builder, clock, pred, dest);
4267
4268 return success();
4269}
4270
4271/// release_initial ::= 'release_initial(' ref_expr ')' info?
4272ParseResult FIRStmtParser::parseRefReleaseInitial() {
4273 auto startTok = consumeToken(FIRToken::lp_release_initial);
4274
4275 Value dest;
4276 if (parseRefExp(
4277 dest,
4278 "expected destination reference expression in release_initial") ||
4279 parseToken(FIRToken::r_paren, "expected ')' in release_initial") ||
4280 parseOptionalInfo())
4281 return failure();
4282
4283 // Check reference expression is of reference type.
4284 if (auto ref = type_dyn_cast<RefType>(dest.getType());
4285 !ref || !ref.getForceable())
4286 return emitError(startTok.getLoc(), "expected rwprobe-type expression for "
4287 "release_initial destination, got ")
4288 << dest.getType();
4289
4290 locationProcessor.setLoc(startTok.getLoc());
4291
4292 auto value = APInt::getAllOnes(1);
4293 auto type = UIntType::get(builder.getContext(), 1);
4294 auto attr = builder.getIntegerAttr(IntegerType::get(type.getContext(),
4295 value.getBitWidth(),
4296 IntegerType::Unsigned),
4297 value);
4298 auto pred = moduleContext.getCachedConstant(builder, attr, type, attr);
4299 RefReleaseInitialOp::create(builder, pred, dest);
4300
4301 return success();
4302}
4303
4304/// connect ::= 'connect' expr expr
4305ParseResult FIRStmtParser::parseConnect() {
4306 auto startTok = consumeToken(FIRToken::kw_connect);
4307 auto loc = startTok.getLoc();
4308
4309 Value lhs, rhs;
4310 if (parseExp(lhs, "expected connect expression") ||
4311 parseToken(FIRToken::comma, "expected ','") ||
4312 parseExp(rhs, "expected connect expression") || parseOptionalInfo())
4313 return failure();
4314
4315 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4316 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4317 if (!lhsType || !rhsType)
4318 return emitError(loc, "cannot connect reference or property types");
4319 // TODO: Once support lands for agg-of-ref, add test for this check!
4320 if (lhsType.containsReference() || rhsType.containsReference())
4321 return emitError(loc, "cannot connect types containing references");
4322
4323 if (!areTypesEquivalent(lhsType, rhsType))
4324 return emitError(loc, "cannot connect non-equivalent type ")
4325 << rhsType << " to " << lhsType;
4326
4327 locationProcessor.setLoc(loc);
4328 emitConnect(builder, lhs, rhs);
4329 return success();
4330}
4331
4332/// propassign ::= 'propassign' expr expr
4333ParseResult FIRStmtParser::parsePropAssign() {
4334 auto startTok = consumeToken(FIRToken::kw_propassign);
4335 auto loc = startTok.getLoc();
4336
4337 Value lhs, rhs;
4338 if (parseExp(lhs, "expected propassign expression") ||
4339 parseToken(FIRToken::comma, "expected ','") ||
4340 parseExp(rhs, "expected propassign expression") || parseOptionalInfo())
4341 return failure();
4342
4343 auto lhsType = type_dyn_cast<PropertyType>(lhs.getType());
4344 auto rhsType = type_dyn_cast<PropertyType>(rhs.getType());
4345 if (!lhsType || !rhsType)
4346 return emitError(loc, "can only propassign property types");
4347 locationProcessor.setLoc(loc);
4348 if (lhsType != rhsType) {
4349 // If the lhs is anyref, and the rhs is a ClassType, insert a cast.
4350 if (isa<AnyRefType>(lhsType) && isa<ClassType>(rhsType))
4351 rhs = ObjectAnyRefCastOp::create(builder, rhs);
4352 else
4353 return emitError(loc, "cannot propassign non-equivalent type ")
4354 << rhsType << " to " << lhsType;
4355 }
4356 PropAssignOp::create(builder, lhs, rhs);
4357 return success();
4358}
4359
4360/// invalidate ::= 'invalidate' expr
4361ParseResult FIRStmtParser::parseInvalidate() {
4362 auto startTok = consumeToken(FIRToken::kw_invalidate);
4363
4364 Value lhs;
4365
4366 StringRef id;
4367 auto loc = getToken().getLoc();
4368 SymbolValueEntry symtabEntry;
4369 if (parseId(id, "expected static reference expression") ||
4370 moduleContext.lookupSymbolEntry(symtabEntry, id, loc))
4371 return failure();
4372
4373 // If we looked up a normal value (e.g., wire, register, or port), then we
4374 // just need to get any optional trailing expression. Invalidate this.
4375 if (!moduleContext.resolveSymbolEntry(lhs, symtabEntry, loc, false)) {
4376 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4377 parseOptionalInfo())
4378 return failure();
4379
4380 locationProcessor.setLoc(startTok.getLoc());
4381 emitInvalidate(lhs);
4382 return success();
4383 }
4384
4385 // We're dealing with an instance. This instance may or may not have a
4386 // trailing expression. Handle the special case of no trailing expression
4387 // first by invalidating all of its results.
4388 assert(isa<UnbundledID>(symtabEntry) && "should be an instance");
4389
4390 if (getToken().isNot(FIRToken::period)) {
4391 locationProcessor.setLoc(loc);
4392 // Invalidate all of the results of the bundled value.
4393 unsigned unbundledId = cast<UnbundledID>(symtabEntry) - 1;
4394 UnbundledValueEntry &ubEntry = moduleContext.getUnbundledEntry(unbundledId);
4395 for (auto elt : ubEntry)
4396 emitInvalidate(elt.second);
4397 return success();
4398 }
4399
4400 // Handle the case of an instance with a trailing expression. This must begin
4401 // with a '.' (until we add instance arrays).
4402 StringRef fieldName;
4403 if (parseToken(FIRToken::period, "expected '.' in field reference") ||
4404 parseFieldId(fieldName, "expected field name") ||
4405 moduleContext.resolveSymbolEntry(lhs, symtabEntry, fieldName, loc))
4406 return failure();
4407
4408 // Update with any trailing expression and invalidate it.
4409 if (parseOptionalExpPostscript(lhs, /*allowDynamic=*/false) ||
4410 parseOptionalInfo())
4411 return failure();
4412
4413 locationProcessor.setLoc(startTok.getLoc());
4414 emitInvalidate(lhs);
4415 return success();
4416}
4417
4418ParseResult FIRStmtParser::parseLayerBlockOrGroup(unsigned indent) {
4419
4420 auto startTok = consumeToken();
4421 assert(startTok.isAny(FIRToken::kw_layerblock, FIRToken::kw_group) &&
4422 "consumed an unexpected token");
4423 auto loc = startTok.getLoc();
4424
4425 StringRef id;
4426 if (parseId(id, "expected layer identifer") ||
4427 parseToken(FIRToken::colon, "expected ':' at end of layer block") ||
4428 parseOptionalInfo())
4429 return failure();
4430
4431 locationProcessor.setLoc(loc);
4432
4433 StringRef rootLayer;
4434 SmallVector<FlatSymbolRefAttr> nestedLayers;
4435 if (!layerSym) {
4436 rootLayer = id;
4437 } else {
4438 rootLayer = layerSym.getRootReference();
4439 auto nestedRefs = layerSym.getNestedReferences();
4440 nestedLayers.append(nestedRefs.begin(), nestedRefs.end());
4441 nestedLayers.push_back(FlatSymbolRefAttr::get(builder.getContext(), id));
4442 }
4443
4444 auto layerBlockOp = LayerBlockOp::create(
4445 builder,
4446 SymbolRefAttr::get(builder.getContext(), rootLayer, nestedLayers));
4447 layerBlockOp->getRegion(0).push_back(new Block());
4448
4449 if (getIndentation() > indent)
4450 if (parseSubBlock(layerBlockOp.getRegion().front(), indent,
4451 layerBlockOp.getLayerName()))
4452 return failure();
4453
4454 return success();
4455}
4456
4457/// leading-exp-stmt ::= exp '<=' exp info?
4458/// ::= exp 'is' 'invalid' info?
4459ParseResult FIRStmtParser::parseLeadingExpStmt(Value lhs) {
4460 auto loc = getToken().getLoc();
4461
4462 // If 'is' grammar is special.
4463 if (consumeIf(FIRToken::kw_is)) {
4464 if (parseToken(FIRToken::kw_invalid, "expected 'invalid'") ||
4465 parseOptionalInfo())
4466 return failure();
4467
4468 if (removedFeature({3, 0, 0}, "'is invalid' statements", loc))
4469 return failure();
4470
4471 locationProcessor.setLoc(loc);
4472 emitInvalidate(lhs);
4473 return success();
4474 }
4475
4476 if (parseToken(FIRToken::less_equal, "expected '<=' in statement"))
4477 return failure();
4478
4479 if (removedFeature({3, 0, 0}, "'<=' connections", loc))
4480 return failure();
4481
4482 Value rhs;
4483 if (parseExp(rhs, "unexpected token in statement") || parseOptionalInfo())
4484 return failure();
4485
4486 locationProcessor.setLoc(loc);
4487
4488 auto lhsType = type_dyn_cast<FIRRTLBaseType>(lhs.getType());
4489 auto rhsType = type_dyn_cast<FIRRTLBaseType>(rhs.getType());
4490 if (!lhsType || !rhsType)
4491 return emitError(loc, "cannot connect reference or property types");
4492 // TODO: Once support lands for agg-of-ref, add test for this check!
4493 if (lhsType.containsReference() || rhsType.containsReference())
4494 return emitError(loc, "cannot connect types containing references");
4495
4496 if (!areTypesEquivalent(lhsType, rhsType))
4497 return emitError(loc, "cannot connect non-equivalent type ")
4498 << rhsType << " to " << lhsType;
4499 emitConnect(builder, lhs, rhs);
4500 return success();
4501}
4502
4503//===-------------------------------
4504// FIRStmtParser Declaration Parsing
4505
4506/// instance ::= 'inst' id 'of' id info?
4507ParseResult FIRStmtParser::parseInstance() {
4508 auto startTok = consumeToken(FIRToken::kw_inst);
4509
4510 // If this was actually the start of a connect or something else handle
4511 // that.
4512 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4513 return *isExpr;
4514
4515 StringRef id;
4516 StringRef moduleName;
4517 if (parseId(id, "expected instance name") ||
4518 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
4519 parseId(moduleName, "expected module name") || parseOptionalInfo())
4520 return failure();
4521
4522 locationProcessor.setLoc(startTok.getLoc());
4523
4524 // Look up the module that is being referenced.
4525 auto referencedModule = getReferencedModule(startTok.getLoc(), moduleName);
4526 if (!referencedModule)
4527 return failure();
4528
4529 SmallVector<PortInfo> modulePorts = referencedModule.getPorts();
4530
4531 auto annotations = getConstants().emptyArrayAttr;
4532 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4533
4534 hw::InnerSymAttr sym = {};
4535 auto result = InstanceOp::create(
4536 builder, referencedModule, id, NameKindEnum::InterestingName,
4537 annotations.getValue(), portAnnotations, false, false, sym);
4538
4539 // Since we are implicitly unbundling the instance results, we need to keep
4540 // track of the mapping from bundle fields to results in the unbundledValues
4541 // data structure. Build our entry now.
4542 UnbundledValueEntry unbundledValueEntry;
4543 unbundledValueEntry.reserve(modulePorts.size());
4544 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
4545 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4546
4547 // Add it to unbundledValues and add an entry to the symbol table to remember
4548 // it.
4549 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4550 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
4551 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
4552}
4553
4554/// instance_choice ::=
4555/// 'inst_choice' id 'of' id id info? newline indent ( id "=>" id )+ dedent
4556ParseResult FIRStmtParser::parseInstanceChoice() {
4557 auto startTok = consumeToken(FIRToken::kw_instchoice);
4558 SMLoc loc = startTok.getLoc();
4559
4560 // If this was actually the start of a connect or something else handle that.
4561 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4562 return *isExpr;
4563
4564 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
4565 return failure();
4566
4567 StringRef id;
4568 StringRef defaultModuleName;
4569 StringRef optionGroupName;
4570 if (parseId(id, "expected instance name") ||
4571 parseToken(FIRToken::kw_of, "expected 'of' in instance") ||
4572 parseId(defaultModuleName, "expected module name") ||
4573 parseToken(FIRToken::comma, "expected ','") ||
4574 parseId(optionGroupName, "expected option group name") ||
4575 parseToken(FIRToken::colon, "expected ':' after instchoice") ||
4576 parseOptionalInfo())
4577 return failure();
4578
4579 locationProcessor.setLoc(startTok.getLoc());
4580
4581 // Look up the default module referenced by the instance choice.
4582 // The port lists of all the other referenced modules must match this one.
4583 auto defaultModule = getReferencedModule(loc, defaultModuleName);
4584 if (!defaultModule)
4585 return failure();
4586
4587 SmallVector<PortInfo> modulePorts = defaultModule.getPorts();
4588
4589 // Find the option group.
4590 auto optionGroup = circuitSymTbl.lookup<OptionOp>(optionGroupName);
4591 if (!optionGroup)
4592 return emitError(loc,
4593 "use of undefined option group '" + optionGroupName + "'");
4594
4595 auto baseIndent = getIndentation();
4596 SmallVector<std::pair<OptionCaseOp, FModuleLike>> caseModules;
4597 while (getIndentation() == baseIndent) {
4598 StringRef caseId;
4599 StringRef caseModuleName;
4600 if (parseId(caseId, "expected a case identifier") ||
4601 parseToken(FIRToken::equal_greater,
4602 "expected '=> in instance choice definition") ||
4603 parseId(caseModuleName, "expected module name"))
4604 return failure();
4605
4606 auto caseModule = getReferencedModule(loc, caseModuleName);
4607 if (!caseModule)
4608 return failure();
4609
4610 for (const auto &[defaultPort, casePort] :
4611 llvm::zip(modulePorts, caseModule.getPorts())) {
4612 if (defaultPort.name != casePort.name)
4613 return emitError(loc, "instance case module port '")
4614 << casePort.name.getValue()
4615 << "' does not match the default module port '"
4616 << defaultPort.name.getValue() << "'";
4617 if (defaultPort.type != casePort.type)
4618 return emitError(loc, "instance case port '")
4619 << casePort.name.getValue()
4620 << "' type does not match the default module port";
4621 }
4622
4623 auto optionCase =
4624 dyn_cast_or_null<OptionCaseOp>(optionGroup.lookupSymbol(caseId));
4625 if (!optionCase)
4626 return emitError(loc, "use of undefined option case '" + caseId + "'");
4627 caseModules.emplace_back(optionCase, caseModule);
4628 }
4629
4630 auto annotations = getConstants().emptyArrayAttr;
4631 SmallVector<Attribute, 4> portAnnotations(modulePorts.size(), annotations);
4632
4633 // Create an instance choice op.
4634 StringAttr sym;
4635 auto result = InstanceChoiceOp::create(
4636 builder, defaultModule, caseModules, id, NameKindEnum::InterestingName,
4637 annotations.getValue(), portAnnotations, sym);
4638
4639 // Un-bundle the ports, identically to the regular instance operation.
4640 UnbundledValueEntry unbundledValueEntry;
4641 unbundledValueEntry.reserve(modulePorts.size());
4642 for (size_t i = 0, e = modulePorts.size(); i != e; ++i)
4643 unbundledValueEntry.push_back({modulePorts[i].name, result.getResult(i)});
4644
4645 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4646 auto entryId = UnbundledID(moduleContext.unbundledValues.size());
4647 return moduleContext.addSymbolEntry(id, entryId, startTok.getLoc());
4648}
4649
4650FModuleLike FIRStmtParser::getReferencedModule(SMLoc loc,
4651 StringRef moduleName) {
4652 auto referencedModule = circuitSymTbl.lookup<FModuleLike>(moduleName);
4653 if (!referencedModule) {
4654 emitError(loc,
4655 "use of undefined module name '" + moduleName + "' in instance");
4656 return {};
4657 }
4658 if (isa<ClassOp /* ClassLike */>(referencedModule)) {
4659 emitError(loc, "cannot create instance of class '" + moduleName +
4660 "', did you mean object?");
4661 return {};
4662 }
4663 return referencedModule;
4664}
4665
4666/// object ::= 'object' id 'of' id info?
4667ParseResult FIRStmtParser::parseObject() {
4668 auto startTok = consumeToken(FIRToken::kw_object);
4669
4670 // If this was actually the start of a connect or something else handle
4671 // that.
4672 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4673 return *isExpr;
4674
4675 if (requireFeature(missingSpecFIRVersion, "object statements"))
4676 return failure();
4677
4678 StringRef id;
4679 StringRef className;
4680 if (parseId(id, "expected object name") ||
4681 parseToken(FIRToken::kw_of, "expected 'of' in object") ||
4682 parseId(className, "expected class name") || parseOptionalInfo())
4683 return failure();
4684
4685 locationProcessor.setLoc(startTok.getLoc());
4686
4687 // Look up the class that is being referenced.
4688 const auto &classMap = getConstants().classMap;
4689 auto lookup = classMap.find(className);
4690 if (lookup == classMap.end())
4691 return emitError(startTok.getLoc(), "use of undefined class name '" +
4692 className + "' in object");
4693 auto referencedClass = lookup->getSecond();
4694 auto result = ObjectOp::create(builder, referencedClass, id);
4695 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4696}
4697
4698/// cmem ::= 'cmem' id ':' type info?
4699ParseResult FIRStmtParser::parseCombMem() {
4700 // TODO(firrtl spec) cmem is completely undocumented.
4701 auto startTok = consumeToken(FIRToken::kw_cmem);
4702
4703 // If this was actually the start of a connect or something else handle
4704 // that.
4705 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4706 return *isExpr;
4707
4708 StringRef id;
4709 FIRRTLType type;
4710 if (parseId(id, "expected cmem name") ||
4711 parseToken(FIRToken::colon, "expected ':' in cmem") ||
4712 parseType(type, "expected cmem type") || parseOptionalInfo())
4713 return failure();
4714
4715 locationProcessor.setLoc(startTok.getLoc());
4716
4717 // Transform the parsed vector type into a memory type.
4718 auto vectorType = type_dyn_cast<FVectorType>(type);
4719 if (!vectorType)
4720 return emitError("cmem requires vector type");
4721
4722 auto annotations = getConstants().emptyArrayAttr;
4723 StringAttr sym = {};
4724 auto result = CombMemOp::create(
4725 builder, vectorType.getElementType(), vectorType.getNumElements(), id,
4726 NameKindEnum::InterestingName, annotations, sym);
4727 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4728}
4729
4730/// smem ::= 'smem' id ':' type ruw? info?
4731ParseResult FIRStmtParser::parseSeqMem() {
4732 // TODO(firrtl spec) smem is completely undocumented.
4733 auto startTok = consumeToken(FIRToken::kw_smem);
4734
4735 // If this was actually the start of a connect or something else handle
4736 // that.
4737 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4738 return *isExpr;
4739
4740 StringRef id;
4741 FIRRTLType type;
4742 RUWBehavior ruw = RUWBehavior::Undefined;
4743
4744 if (parseId(id, "expected smem name") ||
4745 parseToken(FIRToken::colon, "expected ':' in smem") ||
4746 parseType(type, "expected smem type"))
4747 return failure();
4748
4749 if (consumeIf(FIRToken::comma)) {
4750 if (parseRUW(ruw))
4751 return failure();
4752 }
4753
4754 if (parseOptionalInfo()) {
4755 return failure();
4756 }
4757
4758 locationProcessor.setLoc(startTok.getLoc());
4759
4760 // Transform the parsed vector type into a memory type.
4761 auto vectorType = type_dyn_cast<FVectorType>(type);
4762 if (!vectorType)
4763 return emitError("smem requires vector type");
4764
4765 auto annotations = getConstants().emptyArrayAttr;
4766 StringAttr sym = {};
4767 auto result = SeqMemOp::create(
4768 builder, vectorType.getElementType(), vectorType.getNumElements(), ruw,
4769 id, NameKindEnum::InterestingName, annotations, sym);
4770 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
4771}
4772
4773/// mem ::= 'mem' id ':' info? INDENT memField* DEDENT
4774/// memField ::= 'data-type' '=>' type NEWLINE
4775/// ::= 'depth' '=>' intLit NEWLINE
4776/// ::= 'read-latency' '=>' intLit NEWLINE
4777/// ::= 'write-latency' '=>' intLit NEWLINE
4778/// ::= 'read-under-write' '=>' ruw NEWLINE
4779/// ::= 'reader' '=>' id+ NEWLINE
4780/// ::= 'writer' '=>' id+ NEWLINE
4781/// ::= 'readwriter' '=>' id+ NEWLINE
4782ParseResult FIRStmtParser::parseMem(unsigned memIndent) {
4783 auto startTok = consumeToken(FIRToken::kw_mem);
4784
4785 // If this was actually the start of a connect or something else handle
4786 // that.
4787 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4788 return *isExpr;
4789
4790 StringRef id;
4791 if (parseId(id, "expected mem name") ||
4792 parseToken(FIRToken::colon, "expected ':' in mem") || parseOptionalInfo())
4793 return failure();
4794
4795 FIRRTLType type;
4796 int64_t depth = -1, readLatency = -1, writeLatency = -1;
4797 RUWBehavior ruw = RUWBehavior::Undefined;
4798
4799 SmallVector<std::pair<StringAttr, Type>, 4> ports;
4800
4801 // Parse all the memfield records, which are indented more than the mem.
4802 while (1) {
4803 auto nextIndent = getIndentation();
4804 if (!nextIndent || *nextIndent <= memIndent)
4805 break;
4806
4807 auto spelling = getTokenSpelling();
4808 if (parseToken(FIRToken::identifier, "unexpected token in 'mem'") ||
4809 parseToken(FIRToken::equal_greater, "expected '=>' in 'mem'"))
4810 return failure();
4811
4812 if (spelling == "data-type") {
4813 if (type)
4814 return emitError("'mem' type specified multiple times"), failure();
4815
4816 if (parseType(type, "expected type in data-type declaration"))
4817 return failure();
4818 continue;
4819 }
4820 if (spelling == "depth") {
4821 if (parseIntLit(depth, "expected integer in depth specification"))
4822 return failure();
4823 continue;
4824 }
4825 if (spelling == "read-latency") {
4826 if (parseIntLit(readLatency, "expected integer latency"))
4827 return failure();
4828 continue;
4829 }
4830 if (spelling == "write-latency") {
4831 if (parseIntLit(writeLatency, "expected integer latency"))
4832 return failure();
4833 continue;
4834 }
4835 if (spelling == "read-under-write") {
4836 if (getToken().isNot(FIRToken::kw_old, FIRToken::kw_new,
4837 FIRToken::kw_undefined))
4838 return emitError("expected specifier"), failure();
4839
4840 if (parseOptionalRUW(ruw))
4841 return failure();
4842 continue;
4843 }
4844
4845 MemOp::PortKind portKind;
4846 if (spelling == "reader")
4847 portKind = MemOp::PortKind::Read;
4848 else if (spelling == "writer")
4849 portKind = MemOp::PortKind::Write;
4850 else if (spelling == "readwriter")
4851 portKind = MemOp::PortKind::ReadWrite;
4852 else
4853 return emitError("unexpected field in 'mem' declaration"), failure();
4854
4855 StringRef portName;
4856 if (parseId(portName, "expected port name"))
4857 return failure();
4858 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
4859 if (!baseType)
4860 return emitError("unexpected type, must be base type");
4861 ports.push_back({builder.getStringAttr(portName),
4862 MemOp::getTypeForPort(depth, baseType, portKind)});
4863
4864 while (!getIndentation().has_value()) {
4865 if (parseId(portName, "expected port name"))
4866 return failure();
4867 ports.push_back({builder.getStringAttr(portName),
4868 MemOp::getTypeForPort(depth, baseType, portKind)});
4869 }
4870 }
4871
4872 // The FIRRTL dialect requires mems to have at least one port. Since portless
4873 // mems can never be referenced, it is always safe to drop them.
4874 if (ports.empty())
4875 return success();
4876
4877 // Canonicalize the ports into alphabetical order.
4878 // TODO: Move this into MemOp construction/canonicalization.
4879 llvm::array_pod_sort(ports.begin(), ports.end(),
4880 [](const std::pair<StringAttr, Type> *lhs,
4881 const std::pair<StringAttr, Type> *rhs) -> int {
4882 return lhs->first.getValue().compare(
4883 rhs->first.getValue());
4884 });
4885
4886 auto annotations = getConstants().emptyArrayAttr;
4887 SmallVector<Attribute, 4> resultNames;
4888 SmallVector<Type, 4> resultTypes;
4889 SmallVector<Attribute, 4> resultAnnotations;
4890 for (auto p : ports) {
4891 resultNames.push_back(p.first);
4892 resultTypes.push_back(p.second);
4893 resultAnnotations.push_back(annotations);
4894 }
4895
4896 locationProcessor.setLoc(startTok.getLoc());
4897
4898 auto result = MemOp::create(
4899 builder, resultTypes, readLatency, writeLatency, depth, ruw,
4900 builder.getArrayAttr(resultNames), id, NameKindEnum::InterestingName,
4901 annotations, builder.getArrayAttr(resultAnnotations), hw::InnerSymAttr(),
4902 MemoryInitAttr(), StringAttr());
4903
4904 UnbundledValueEntry unbundledValueEntry;
4905 unbundledValueEntry.reserve(result.getNumResults());
4906 for (size_t i = 0, e = result.getNumResults(); i != e; ++i)
4907 unbundledValueEntry.push_back({resultNames[i], result.getResult(i)});
4908
4909 moduleContext.unbundledValues.push_back(std::move(unbundledValueEntry));
4910 auto entryID = UnbundledID(moduleContext.unbundledValues.size());
4911 return moduleContext.addSymbolEntry(id, entryID, startTok.getLoc());
4912}
4913
4914/// node ::= 'node' id '=' exp info?
4915ParseResult FIRStmtParser::parseNode() {
4916 auto startTok = consumeToken(FIRToken::kw_node);
4917
4918 // If this was actually the start of a connect or something else handle
4919 // that.
4920 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4921 return *isExpr;
4922
4923 StringRef id;
4924 Value initializer;
4925 if (parseId(id, "expected node name") ||
4926 parseToken(FIRToken::equal, "expected '=' in node") ||
4927 parseExp(initializer, "expected expression for node") ||
4928 parseOptionalInfo())
4929 return failure();
4930
4931 locationProcessor.setLoc(startTok.getLoc());
4932
4933 // Error out in the following conditions:
4934 //
4935 // 1. Node type is Analog (at the top level)
4936 // 2. Node type is not passive under an optional outer flip
4937 // (analog field is okay)
4938 //
4939 // Note: (1) is more restictive than normal NodeOp verification, but
4940 // this is added to align with the SFC. (2) is less restrictive than
4941 // the SFC to accomodate for situations where the node is something
4942 // weird like a module output or an instance input.
4943 auto initializerType = type_cast<FIRRTLType>(initializer.getType());
4944 auto initializerBaseType =
4945 type_dyn_cast<FIRRTLBaseType>(initializer.getType());
4946 if (type_isa<AnalogType>(initializerType) ||
4947 !(initializerBaseType && initializerBaseType.isPassive())) {
4948 emitError(startTok.getLoc())
4949 << "Node cannot be analog and must be passive or passive under a flip "
4950 << initializer.getType();
4951 return failure();
4952 }
4953
4954 auto annotations = getConstants().emptyArrayAttr;
4955 StringAttr sym = {};
4956
4957 auto result = NodeOp::create(builder, initializer, id,
4958 NameKindEnum::InterestingName, annotations, sym);
4959 return moduleContext.addSymbolEntry(id, result.getResult(),
4960 startTok.getLoc());
4961}
4962
4963/// wire ::= 'wire' id ':' type info?
4964ParseResult FIRStmtParser::parseWire() {
4965 auto startTok = consumeToken(FIRToken::kw_wire);
4966
4967 // If this was actually the start of a connect or something else handle
4968 // that.
4969 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
4970 return *isExpr;
4971
4972 StringRef id;
4973 FIRRTLType type;
4974 if (parseId(id, "expected wire name") ||
4975 parseToken(FIRToken::colon, "expected ':' in wire") ||
4976 parseType(type, "expected wire type") || parseOptionalInfo())
4977 return failure();
4978
4979 locationProcessor.setLoc(startTok.getLoc());
4980
4981 auto annotations = getConstants().emptyArrayAttr;
4982 StringAttr sym = {};
4983
4984 // Names of only-nonHW should be droppable.
4985 auto namekind = isa<PropertyType, RefType>(type)
4986 ? NameKindEnum::DroppableName
4987 : NameKindEnum::InterestingName;
4988
4989 auto result = WireOp::create(builder, type, id, namekind, annotations, sym);
4990 return moduleContext.addSymbolEntry(id, result.getResult(),
4991 startTok.getLoc());
4992}
4993
4994/// register ::= 'reg' id ':' type exp ('with' ':' reset_block)? info?
4995///
4996/// reset_block ::= INDENT simple_reset info? NEWLINE DEDENT
4997/// ::= '(' simple_reset ')'
4998///
4999/// simple_reset ::= simple_reset0
5000/// ::= '(' simple_reset0 ')'
5001///
5002/// simple_reset0: 'reset' '=>' '(' exp exp ')'
5003///
5004ParseResult FIRStmtParser::parseRegister(unsigned regIndent) {
5005 auto startTok = consumeToken(FIRToken::kw_reg);
5006
5007 // If this was actually the start of a connect or something else handle
5008 // that.
5009 if (auto isExpr = parseExpWithLeadingKeyword(startTok))
5010 return *isExpr;
5011
5012 StringRef id;
5013 FIRRTLType type;
5014 Value clock;
5015
5016 // TODO(firrtl spec): info? should come after the clock expression before
5017 // the 'with'.
5018 if (parseId(id, "expected reg name") ||
5019 parseToken(FIRToken::colon, "expected ':' in reg") ||
5020 parseType(type, "expected reg type") ||
5021 parseToken(FIRToken::comma, "expected ','") ||
5022 parseExp(clock, "expected expression for register clock"))
5023 return failure();
5024
5025 if (!type_isa<FIRRTLBaseType>(type))
5026 return emitError(startTok.getLoc(), "register must have base type");
5027
5028 // Parse the 'with' specifier if present.
5029 Value resetSignal, resetValue;
5030 if (consumeIf(FIRToken::kw_with)) {
5031 if (removedFeature({3, 0, 0}, "'reg with' registers"))
5032 return failure();
5033
5034 if (parseToken(FIRToken::colon, "expected ':' in reg"))
5035 return failure();
5036
5037 // TODO(firrtl spec): Simplify the grammar for register reset logic.
5038 // Why allow multiple ambiguous parentheses? Why rely on indentation at
5039 // all?
5040
5041 // This implements what the examples have in practice.
5042 bool hasExtraLParen = consumeIf(FIRToken::l_paren);
5043
5044 auto indent = getIndentation();
5045 if (!indent || *indent <= regIndent)
5046 if (!hasExtraLParen)
5047 return emitError("expected indented reset specifier in reg"), failure();
5048
5049 if (parseToken(FIRToken::kw_reset, "expected 'reset' in reg") ||
5050 parseToken(FIRToken::equal_greater, "expected => in reset specifier") ||
5051 parseToken(FIRToken::l_paren, "expected '(' in reset specifier") ||
5052 parseExp(resetSignal, "expected expression for reset signal") ||
5053 parseToken(FIRToken::comma, "expected ','"))
5054 return failure();
5055
5056 // The Scala implementation of FIRRTL represents registers without resets
5057 // as a self referential register... and the pretty printer doesn't print
5058 // the right form. Recognize that this is happening and treat it as a
5059 // register without a reset for compatibility.
5060 // TODO(firrtl scala impl): pretty print registers without resets right.
5061 if (getTokenSpelling() == id) {
5062 consumeToken();
5063 if (parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5064 return failure();
5065 resetSignal = Value();
5066 } else {
5067 if (parseExp(resetValue, "expected expression for reset value") ||
5068 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5069 return failure();
5070 }
5071
5072 if (hasExtraLParen &&
5073 parseToken(FIRToken::r_paren, "expected ')' in reset specifier"))
5074 return failure();
5075 }
5076
5077 // Finally, handle the last info if present, providing location info for the
5078 // clock expression.
5079 if (parseOptionalInfo())
5080 return failure();
5081
5082 locationProcessor.setLoc(startTok.getLoc());
5083
5084 ArrayAttr annotations = getConstants().emptyArrayAttr;
5085 Value result;
5086 StringAttr sym = {};
5087 if (resetSignal)
5088 result =
5089 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5090 NameKindEnum::InterestingName, annotations, sym)
5091 .getResult();
5092 else
5093 result = RegOp::create(builder, type, clock, id,
5094 NameKindEnum::InterestingName, annotations, sym)
5095 .getResult();
5096 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5097}
5098
5099/// registerWithReset ::= 'regreset' id ':' type exp exp exp
5100///
5101/// This syntax is only supported in FIRRTL versions >= 3.0.0. Because this
5102/// syntax is only valid for >= 3.0.0, there is no need to check if the leading
5103/// "regreset" is part of an expression with a leading keyword.
5104ParseResult FIRStmtParser::parseRegisterWithReset() {
5105 auto startTok = consumeToken(FIRToken::kw_regreset);
5106
5107 StringRef id;
5108 FIRRTLType type;
5109 Value clock, resetSignal, resetValue;
5110
5111 if (parseId(id, "expected reg name") ||
5112 parseToken(FIRToken::colon, "expected ':' in reg") ||
5113 parseType(type, "expected reg type") ||
5114 parseToken(FIRToken::comma, "expected ','") ||
5115 parseExp(clock, "expected expression for register clock") ||
5116 parseToken(FIRToken::comma, "expected ','") ||
5117 parseExp(resetSignal, "expected expression for register reset") ||
5118 parseToken(FIRToken::comma, "expected ','") ||
5119 parseExp(resetValue, "expected expression for register reset value") ||
5120 parseOptionalInfo())
5121 return failure();
5122
5123 if (!type_isa<FIRRTLBaseType>(type))
5124 return emitError(startTok.getLoc(), "register must have base type");
5125
5126 locationProcessor.setLoc(startTok.getLoc());
5127
5128 auto result =
5129 RegResetOp::create(builder, type, clock, resetSignal, resetValue, id,
5130 NameKindEnum::InterestingName,
5131 getConstants().emptyArrayAttr, StringAttr{})
5132 .getResult();
5133
5134 return moduleContext.addSymbolEntry(id, result, startTok.getLoc());
5135}
5136
5137/// contract ::= 'contract' (id,+ '=' exp,+) ':' info? contract_body
5138/// contract_body ::= simple_stmt | INDENT simple_stmt+ DEDENT
5139ParseResult FIRStmtParser::parseContract(unsigned blockIndent) {
5140 if (requireFeature(missingSpecFIRVersion, "contracts"))
5141 return failure();
5142
5143 auto startTok = consumeToken(FIRToken::kw_contract);
5144
5145 // Parse the contract results and expressions.
5146 SmallVector<StringRef> ids;
5147 SmallVector<SMLoc> locs;
5148 SmallVector<Value> values;
5149 SmallVector<Type> types;
5150 if (!consumeIf(FIRToken::colon)) {
5151 auto parseContractId = [&] {
5152 StringRef id;
5153 locs.push_back(getToken().getLoc());
5154 if (parseId(id, "expected contract result name"))
5155 return failure();
5156 ids.push_back(id);
5157 return success();
5158 };
5159 auto parseContractValue = [&] {
5160 Value value;
5161 if (parseExp(value, "expected expression for contract result"))
5162 return failure();
5163 values.push_back(value);
5164 types.push_back(value.getType());
5165 return success();
5166 };
5167 if (parseListUntil(FIRToken::equal, parseContractId) ||
5168 parseListUntil(FIRToken::colon, parseContractValue))
5169 return failure();
5170 }
5171 if (parseOptionalInfo())
5172 return failure();
5173
5174 // Each result must have a corresponding expression assigned.
5175 if (ids.size() != values.size())
5176 return emitError(startTok.getLoc())
5177 << "contract requires same number of results and expressions; got "
5178 << ids.size() << " results and " << values.size()
5179 << " expressions instead";
5180
5181 locationProcessor.setLoc(startTok.getLoc());
5182
5183 // Add block arguments for each result and declare their names in a subscope
5184 // for the contract body.
5185 auto contract = ContractOp::create(builder, types, values);
5186 auto &block = contract.getBody().emplaceBlock();
5187
5188 // Parse the contract body.
5189 {
5190 FIRModuleContext::ContextScope scope(moduleContext, &block);
5191 for (auto [id, loc, type] : llvm::zip(ids, locs, types)) {
5192 auto arg = block.addArgument(type, LocWithInfo(loc, this).getLoc());
5193 if (failed(moduleContext.addSymbolEntry(id, arg, loc)))
5194 return failure();
5195 }
5196 if (getIndentation() > blockIndent)
5197 if (parseSubBlock(block, blockIndent, SymbolRefAttr{}))
5198 return failure();
5199 }
5200
5201 // Declare the results.
5202 for (auto [id, loc, value, result] :
5203 llvm::zip(ids, locs, values, contract.getResults())) {
5204 // Remove previous symbol to avoid duplicates
5205 moduleContext.removeSymbolEntry(id);
5206 if (failed(moduleContext.addSymbolEntry(id, result, loc)))
5207 return failure();
5208 }
5209 return success();
5210}
5211
5212//===----------------------------------------------------------------------===//
5213// FIRCircuitParser
5214//===----------------------------------------------------------------------===//
5215
5216namespace {
5217/// This class implements the outer level of the parser, including things
5218/// like circuit and module.
5219struct FIRCircuitParser : public FIRParser {
5220 explicit FIRCircuitParser(SharedParserConstants &state, FIRLexer &lexer,
5221 ModuleOp mlirModule, FIRVersion version)
5222 : FIRParser(state, lexer, version), mlirModule(mlirModule) {}
5223
5224 ParseResult
5225 parseCircuit(SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBuf,
5226 mlir::TimingScope &ts);
5227
5228private:
5229 /// Extract Annotations from a JSON-encoded Annotation array string and add
5230 /// them to a vector of attributes.
5231 ParseResult importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5232 SmallVectorImpl<Attribute> &attrs);
5233
5234 ParseResult parseToplevelDefinition(CircuitOp circuit, unsigned indent);
5235
5236 ParseResult parseClass(CircuitOp circuit, unsigned indent);
5237 ParseResult parseDomain(CircuitOp circuit, unsigned indent);
5238 ParseResult parseExtClass(CircuitOp circuit, unsigned indent);
5239 ParseResult parseExtModule(CircuitOp circuit, unsigned indent);
5240 ParseResult parseIntModule(CircuitOp circuit, unsigned indent);
5241 ParseResult parseModule(CircuitOp circuit, bool isPublic, unsigned indent);
5242 ParseResult parseFormal(CircuitOp circuit, unsigned indent);
5243 ParseResult parseSimulation(CircuitOp circuit, unsigned indent);
5244 template <class Op>
5245 ParseResult parseFormalLike(CircuitOp circuit, unsigned indent);
5246
5247 ParseResult parseLayerName(SymbolRefAttr &result);
5248 ParseResult parseLayerList(SmallVectorImpl<Attribute> &result);
5249 ParseResult parseEnableLayerSpec(SmallVectorImpl<Attribute> &result);
5250 ParseResult parseKnownLayerSpec(SmallVectorImpl<Attribute> &result);
5251 ParseResult parseModuleLayerSpec(ArrayAttr &enabledLayers);
5252 ParseResult parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5253 ArrayAttr &knownLayers);
5254
5255 ParseResult parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5256 SmallVectorImpl<SMLoc> &resultPortLocs,
5257 unsigned indent);
5258 ParseResult parseParameterList(ArrayAttr &resultParameters);
5259
5260 ParseResult skipToModuleEnd(unsigned indent);
5261
5262 ParseResult parseTypeDecl();
5263
5264 ParseResult parseOptionDecl(CircuitOp circuit);
5265
5266 ParseResult parseLayer(CircuitOp circuit);
5267
5268 ParseResult resolveDomains(
5269 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
5270 const DenseMap<Attribute, size_t> &nameToIndex,
5271 SmallVectorImpl<Attribute> &domainsByIndex);
5272
5273 ParseResult
5274 parseDomains(SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
5275 const DenseMap<Attribute, size_t> &nameToIndex);
5276
5277 struct DeferredModuleToParse {
5278 FModuleLike moduleOp;
5279 SmallVector<SMLoc> portLocs;
5280 FIRLexerCursor lexerCursor;
5281 unsigned indent;
5282 };
5283
5284 ParseResult parseModuleBody(const SymbolTable &circuitSymTbl,
5285 DeferredModuleToParse &deferredModule,
5286 InnerSymFixups &fixups);
5287
5288 SmallVector<DeferredModuleToParse, 0> deferredModules;
5289
5290 SmallVector<InnerSymFixups, 0> moduleFixups;
5291
5292 hw::InnerSymbolNamespaceCollection innerSymbolNamespaces;
5293
5294 ModuleOp mlirModule;
5295};
5296
5297} // end anonymous namespace
5298ParseResult
5299FIRCircuitParser::importAnnotationsRaw(SMLoc loc, StringRef annotationsStr,
5300 SmallVectorImpl<Attribute> &attrs) {
5301
5302 auto annotations = json::parse(annotationsStr);
5303 if (auto err = annotations.takeError()) {
5304 handleAllErrors(std::move(err), [&](const json::ParseError &a) {
5305 auto diag = emitError(loc, "Failed to parse JSON Annotations");
5306 diag.attachNote() << a.message();
5307 });
5308 return failure();
5309 }
5310
5311 json::Path::Root root;
5312 llvm::StringMap<ArrayAttr> thisAnnotationMap;
5313 if (!importAnnotationsFromJSONRaw(annotations.get(), attrs, root,
5314 getContext())) {
5315 auto diag = emitError(loc, "Invalid/unsupported annotation format");
5316 std::string jsonErrorMessage =
5317 "See inline comments for problem area in JSON:\n";
5318 llvm::raw_string_ostream s(jsonErrorMessage);
5319 root.printErrorContext(annotations.get(), s);
5320 diag.attachNote() << jsonErrorMessage;
5321 return failure();
5322 }
5323
5324 return success();
5325}
5326
5327ParseResult FIRCircuitParser::parseLayerName(SymbolRefAttr &result) {
5328 auto *context = getContext();
5329 SmallVector<StringRef> strings;
5330 do {
5331 StringRef name;
5332 if (parseId(name, "expected layer name"))
5333 return failure();
5334 strings.push_back(name);
5335 } while (consumeIf(FIRToken::period));
5336
5337 SmallVector<FlatSymbolRefAttr> nested;
5338 nested.reserve(strings.size() - 1);
5339 for (unsigned i = 1, e = strings.size(); i < e; ++i)
5340 nested.push_back(FlatSymbolRefAttr::get(context, strings[i]));
5341
5342 result = SymbolRefAttr::get(context, strings[0], nested);
5343 return success();
5344}
5345
5346ParseResult FIRCircuitParser::parseModuleLayerSpec(ArrayAttr &enabledLayers) {
5347 SmallVector<Attribute> enabledLayersBuffer;
5348 while (true) {
5349 auto tokenKind = getToken().getKind();
5350 // Parse an enablelayer spec.
5351 if (tokenKind == FIRToken::kw_enablelayer) {
5352 if (parseEnableLayerSpec(enabledLayersBuffer))
5353 return failure();
5354 continue;
5355 }
5356 // Didn't parse a layer spec.
5357 break;
5358 }
5359
5360 if (enabledLayersBuffer.size() != 0)
5361 if (requireFeature({4, 0, 0}, "modules with layers enabled"))
5362 return failure();
5363
5364 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5365 return success();
5366}
5367
5368ParseResult FIRCircuitParser::parseExtModuleLayerSpec(ArrayAttr &enabledLayers,
5369 ArrayAttr &knownLayers) {
5370 SmallVector<Attribute> enabledLayersBuffer;
5371 SmallVector<Attribute> knownLayersBuffer;
5372 while (true) {
5373 auto tokenKind = getToken().getKind();
5374 // Parse an enablelayer spec.
5375 if (tokenKind == FIRToken::kw_enablelayer) {
5376 if (parseEnableLayerSpec(enabledLayersBuffer))
5377 return failure();
5378 continue;
5379 }
5380 // Parse a knownlayer spec.
5381 if (tokenKind == FIRToken::kw_knownlayer) {
5382 if (parseKnownLayerSpec(knownLayersBuffer))
5383 return failure();
5384 continue;
5385 }
5386 // Didn't parse a layer spec.
5387 break;
5388 }
5389
5390 if (enabledLayersBuffer.size() != 0)
5391 if (requireFeature({4, 0, 0}, "extmodules with layers enabled"))
5392 return failure();
5393
5394 if (knownLayersBuffer.size() != 0)
5395 if (requireFeature(nextFIRVersion, "extmodules with known layers"))
5396 return failure();
5397
5398 enabledLayers = ArrayAttr::get(getContext(), enabledLayersBuffer);
5399 knownLayers = ArrayAttr::get(getContext(), knownLayersBuffer);
5400 return success();
5401}
5402
5403ParseResult
5404FIRCircuitParser::parseLayerList(SmallVectorImpl<Attribute> &result) {
5405 do {
5406 SymbolRefAttr layer;
5407 if (parseLayerName(layer))
5408 return failure();
5409 result.push_back(layer);
5410 } while (consumeIf(FIRToken::comma));
5411 return success();
5412}
5413
5414ParseResult
5415FIRCircuitParser::parseEnableLayerSpec(SmallVectorImpl<Attribute> &result) {
5416 consumeToken(FIRToken::kw_enablelayer);
5417 return parseLayerList(result);
5418}
5419
5420ParseResult
5421FIRCircuitParser::parseKnownLayerSpec(SmallVectorImpl<Attribute> &result) {
5422 consumeToken(FIRToken::kw_knownlayer);
5423 return parseLayerList(result);
5424}
5425
5426/// portlist ::= port*
5427/// port ::= dir id ':' type info? NEWLINE
5428/// dir ::= 'input' | 'output'
5429ParseResult
5430FIRCircuitParser::parsePortList(SmallVectorImpl<PortInfo> &resultPorts,
5431 SmallVectorImpl<SMLoc> &resultPortLocs,
5432 unsigned indent) {
5433 // Stores of information about domains as they are parsed:
5434 // 1. Mapping of domain name to port index
5435 // 2. Mapping of port index to domain associations, using domain _names_.
5436 // The locations are recorded to generate good error messages.
5437 DenseMap<Attribute, size_t> nameToIndex;
5438 DenseMap<size_t, SmallVector<std::pair<Attribute, SMLoc>>> domainNames;
5439
5440 // Parse any ports. Populate domain information.
5441 while (getToken().isAny(FIRToken::kw_input, FIRToken::kw_output) &&
5442 // Must be nested under the module.
5443 getIndentation() > indent) {
5444
5445 // We need one token lookahead to resolve the ambiguity between:
5446 // output foo ; port
5447 // output <= input ; identifier expression
5448 // output.thing <= input ; identifier expression
5449 auto backtrackState = getLexer().getCursor();
5450
5451 bool isOutput = getToken().is(FIRToken::kw_output);
5452 consumeToken();
5453
5454 // If we have something that isn't a keyword then this must be an
5455 // identifier, not an input/output marker.
5456 if (!getToken().isAny(FIRToken::identifier, FIRToken::literal_identifier) &&
5457 !getToken().isKeyword()) {
5458 backtrackState.restore(getLexer());
5459 break;
5460 }
5461
5462 StringAttr name;
5463 FIRRTLType type;
5464 LocWithInfo info(getToken().getLoc(), this);
5465 if (parseId(name, "expected port name") ||
5466 parseToken(FIRToken::colon, "expected ':' in port definition") ||
5467 parseType(type, "expected a type in port declaration"))
5468 return failure();
5469 Attribute domainInfoElement = {};
5470 size_t portIdx = resultPorts.size();
5471 if (isa<DomainType>(type)) {
5472 StringAttr domainKind;
5473 if (parseToken(FIRToken::kw_of, "expected 'of' after Domain type port") ||
5474 parseId(domainKind, "expected domain kind"))
5475 return failure();
5476 domainInfoElement = FlatSymbolRefAttr::get(domainKind);
5477 } else {
5478 if (getToken().is(FIRToken::kw_domains))
5479 if (parseDomains(domainNames[portIdx], nameToIndex))
5480 return failure();
5481 }
5482
5483 if (info.parseOptionalInfo())
5484 return failure();
5485
5486 StringAttr innerSym = {};
5487 resultPorts.push_back(PortInfo{name,
5488 type,
5489 direction::get(isOutput),
5490 innerSym,
5491 info.getLoc(),
5492 {},
5493 domainInfoElement});
5494 resultPortLocs.push_back(info.getFIRLoc());
5495 nameToIndex.insert({name, portIdx});
5496 }
5497
5498 // Apply domain assocations to ports.
5499 for (size_t portIdx = 0, e = resultPorts.size(); portIdx != e; ++portIdx) {
5500 auto &port = resultPorts[portIdx];
5501 Attribute &attr = port.domains;
5502 if (attr)
5503 continue;
5504
5505 SmallVector<Attribute> domainInfo;
5506 if (failed(resolveDomains(domainNames[portIdx], nameToIndex, domainInfo)))
5507 return failure();
5508 attr = ArrayAttr::get(getContext(), domainInfo);
5509 }
5510
5511 // Check for port name collisions.
5513 for (auto portAndLoc : llvm::zip(resultPorts, resultPortLocs)) {
5514 PortInfo &port = std::get<0>(portAndLoc);
5515 auto &entry = portIds[port.name];
5516 if (!entry.isValid()) {
5517 entry = std::get<1>(portAndLoc);
5518 continue;
5519 }
5520
5521 emitError(std::get<1>(portAndLoc),
5522 "redefinition of name '" + port.getName() + "'")
5523 .attachNote(translateLocation(entry))
5524 << "previous definition here";
5525 return failure();
5526 }
5527
5528 return success();
5529}
5530
5531/// We're going to defer parsing this module, so just skip tokens until we
5532/// get to the next module or the end of the file.
5533ParseResult FIRCircuitParser::skipToModuleEnd(unsigned indent) {
5534 while (true) {
5535 switch (getToken().getKind()) {
5536
5537 // End of file or invalid token will be handled by outer level.
5538 case FIRToken::eof:
5539 case FIRToken::error:
5540 return success();
5541
5542 // If we got to the next top-level declaration, then we're done.
5543 case FIRToken::kw_class:
5544 case FIRToken::kw_domain:
5545 case FIRToken::kw_declgroup:
5546 case FIRToken::kw_extclass:
5547 case FIRToken::kw_extmodule:
5548 case FIRToken::kw_intmodule:
5549 case FIRToken::kw_formal:
5550 case FIRToken::kw_module:
5551 case FIRToken::kw_public:
5552 case FIRToken::kw_layer:
5553 case FIRToken::kw_option:
5554 case FIRToken::kw_simulation:
5555 case FIRToken::kw_type:
5556 // All module declarations should have the same indentation
5557 // level. Use this fact to differentiate between module
5558 // declarations and usages of "module" as identifiers.
5559 if (getIndentation() == indent)
5560 return success();
5561 [[fallthrough]];
5562 default:
5563 consumeToken();
5564 break;
5565 }
5566 }
5567}
5568
5569/// parameter-list ::= parameter*
5570/// parameter ::= 'parameter' param NEWLINE
5571ParseResult FIRCircuitParser::parseParameterList(ArrayAttr &resultParameters) {
5572 SmallVector<Attribute, 8> parameters;
5573 SmallPtrSet<StringAttr, 8> seen;
5574 while (consumeIf(FIRToken::kw_parameter)) {
5575 StringAttr name;
5576 Attribute value;
5577 SMLoc loc;
5578 if (parseParameter(name, value, loc))
5579 return failure();
5580 auto typedValue = dyn_cast<TypedAttr>(value);
5581 if (!typedValue)
5582 return emitError(loc)
5583 << "invalid value for parameter '" << name.getValue() << "'";
5584 if (!seen.insert(name).second)
5585 return emitError(loc,
5586 "redefinition of parameter '" + name.getValue() + "'");
5587 parameters.push_back(ParamDeclAttr::get(name, typedValue));
5588 }
5589 resultParameters = ArrayAttr::get(getContext(), parameters);
5590 return success();
5591}
5592
5593/// class ::= 'class' id ':' info? INDENT portlist simple_stmt_block DEDENT
5594ParseResult FIRCircuitParser::parseClass(CircuitOp circuit, unsigned indent) {
5595 StringAttr name;
5596 SmallVector<PortInfo, 8> portList;
5597 SmallVector<SMLoc> portLocs;
5598 LocWithInfo info(getToken().getLoc(), this);
5599
5600 if (requireFeature(missingSpecFIRVersion, "classes"))
5601 return failure();
5602
5603 consumeToken(FIRToken::kw_class);
5604 if (parseId(name, "expected class name") ||
5605 parseToken(FIRToken::colon, "expected ':' in class definition") ||
5606 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5607 return failure();
5608
5609 if (name == circuit.getName())
5610 return mlir::emitError(info.getLoc(),
5611 "class cannot be the top of a circuit");
5612
5613 for (auto &portInfo : portList)
5614 if (!isa<PropertyType>(portInfo.type))
5615 return mlir::emitError(portInfo.loc,
5616 "ports on classes must be properties");
5617
5618 // build it
5619 auto builder = circuit.getBodyBuilder();
5620 auto classOp = ClassOp::create(builder, info.getLoc(), name, portList);
5621 classOp.setPrivate();
5622 deferredModules.emplace_back(
5623 DeferredModuleToParse{classOp, portLocs, getLexer().getCursor(), indent});
5624
5625 // Stash the class name -> op in the constants, so we can resolve Inst types.
5626 getConstants().classMap[name.getValue()] = classOp;
5627 return skipToModuleEnd(indent);
5628}
5629
5630/// domain ::= 'domain' id ':' info?
5631ParseResult FIRCircuitParser::parseDomain(CircuitOp circuit, unsigned indent) {
5632 consumeToken(FIRToken::kw_domain);
5633
5634 StringAttr name;
5635 LocWithInfo info(getToken().getLoc(), this);
5636 if (parseId(name, "domain name") ||
5637 parseToken(FIRToken::colon, "expected ':' after domain definition") ||
5638 info.parseOptionalInfo())
5639 return failure();
5640
5641 SmallVector<Attribute> fields;
5642 while (true) {
5643 auto nextIndent = getIndentation();
5644 if (!nextIndent || *nextIndent <= indent)
5645 break;
5646
5647 StringAttr fieldName;
5648 PropertyType type;
5649 if (parseId(fieldName, "field name") ||
5650 parseToken(FIRToken::colon, "expected ':' after field name") ||
5651 parsePropertyType(type, "field type") || info.parseOptionalInfo())
5652 return failure();
5653
5654 fields.push_back(
5655 DomainFieldAttr::get(circuit.getContext(), fieldName, type));
5656 }
5657
5658 auto builder = circuit.getBodyBuilder();
5659 DomainOp::create(builder, info.getLoc(), name, builder.getArrayAttr(fields));
5660
5661 return success();
5662}
5663
5664/// extclass ::= 'extclass' id ':' info? INDENT portlist DEDENT
5665ParseResult FIRCircuitParser::parseExtClass(CircuitOp circuit,
5666 unsigned indent) {
5667 StringAttr name;
5668 SmallVector<PortInfo, 8> portList;
5669 SmallVector<SMLoc> portLocs;
5670 LocWithInfo info(getToken().getLoc(), this);
5671
5672 if (requireFeature(missingSpecFIRVersion, "classes"))
5673 return failure();
5674
5675 consumeToken(FIRToken::kw_extclass);
5676 if (parseId(name, "expected extclass name") ||
5677 parseToken(FIRToken::colon, "expected ':' in extclass definition") ||
5678 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5679 return failure();
5680
5681 if (name == circuit.getName())
5682 return mlir::emitError(info.getLoc(),
5683 "extclass cannot be the top of a circuit");
5684
5685 for (auto &portInfo : portList)
5686 if (!isa<PropertyType>(portInfo.type))
5687 return mlir::emitError(portInfo.loc,
5688 "ports on extclasses must be properties");
5689
5690 // Build it
5691 auto builder = circuit.getBodyBuilder();
5692 auto extClassOp = ExtClassOp::create(builder, info.getLoc(), name, portList);
5693
5694 // Stash the class name -> op in the constants, so we can resolve Inst types.
5695 getConstants().classMap[name.getValue()] = extClassOp;
5696 return skipToModuleEnd(indent);
5697}
5698
5699/// extmodule ::=
5700/// 'extmodule' id ':' info?
5701/// INDENT portlist defname? parameter-list ref-list DEDENT
5702/// defname ::= 'defname' '=' id NEWLINE
5703ParseResult FIRCircuitParser::parseExtModule(CircuitOp circuit,
5704 unsigned indent) {
5705 StringAttr name;
5706 ArrayAttr enabledLayers;
5707 ArrayAttr knownLayers;
5708 SmallVector<PortInfo, 8> portList;
5709 SmallVector<SMLoc> portLocs;
5710 LocWithInfo info(getToken().getLoc(), this);
5711 consumeToken(FIRToken::kw_extmodule);
5712 if (parseId(name, "expected extmodule name") ||
5713 parseExtModuleLayerSpec(enabledLayers, knownLayers) ||
5714 parseToken(FIRToken::colon, "expected ':' in extmodule definition") ||
5715 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5716 return failure();
5717
5718 StringRef defName;
5719 if (consumeIf(FIRToken::kw_defname)) {
5720 if (parseToken(FIRToken::equal, "expected '=' in defname") ||
5721 parseId(defName, "expected defname name"))
5722 return failure();
5723 }
5724
5725 ArrayAttr parameters;
5726 if (parseParameterList(parameters))
5727 return failure();
5728
5729 if (version >= FIRVersion({4, 0, 0})) {
5730 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5731 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5732 if (ftype.hasUninferredWidth())
5733 return emitError(loc, "extmodule port must have known width");
5734 }
5735 }
5736 }
5737
5738 auto builder = circuit.getBodyBuilder();
5739 auto isMainModule = (name == circuit.getName());
5740 auto convention =
5741 (isMainModule && getConstants().options.scalarizePublicModules) ||
5742 getConstants().options.scalarizeExtModules
5743 ? Convention::Scalarized
5744 : Convention::Internal;
5745 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5746 auto annotations = ArrayAttr::get(getContext(), {});
5747 auto extModuleOp = FExtModuleOp::create(
5748 builder, info.getLoc(), name, conventionAttr, portList, knownLayers,
5749 defName, annotations, parameters, enabledLayers);
5750 auto visibility = isMainModule ? SymbolTable::Visibility::Public
5751 : SymbolTable::Visibility::Private;
5752 SymbolTable::setSymbolVisibility(extModuleOp, visibility);
5753 return success();
5754}
5755
5756/// intmodule ::=
5757/// 'intmodule' id ':' info?
5758/// INDENT portlist intname parameter-list ref-list DEDENT
5759/// intname ::= 'intrinsic' '=' id NEWLINE
5760ParseResult FIRCircuitParser::parseIntModule(CircuitOp circuit,
5761 unsigned indent) {
5762 StringAttr name;
5763 StringRef intName;
5764 ArrayAttr enabledLayers;
5765 SmallVector<PortInfo, 8> portList;
5766 SmallVector<SMLoc> portLocs;
5767 LocWithInfo info(getToken().getLoc(), this);
5768 consumeToken(FIRToken::kw_intmodule);
5769 if (parseId(name, "expected intmodule name") ||
5770 parseModuleLayerSpec(enabledLayers) ||
5771 parseToken(FIRToken::colon, "expected ':' in intmodule definition") ||
5772 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent) ||
5773 parseToken(FIRToken::kw_intrinsic, "expected 'intrinsic'") ||
5774 parseToken(FIRToken::equal, "expected '=' in intrinsic") ||
5775 parseId(intName, "expected intrinsic name"))
5776 return failure();
5777
5778 ArrayAttr parameters;
5779 if (parseParameterList(parameters))
5780 return failure();
5781
5782 ArrayAttr annotations = getConstants().emptyArrayAttr;
5783 auto builder = circuit.getBodyBuilder();
5784 FIntModuleOp::create(builder, info.getLoc(), name, portList, intName,
5785 annotations, parameters, enabledLayers)
5786 .setPrivate();
5787 return success();
5788}
5789
5790/// module ::= 'module' id ':' info? INDENT portlist simple_stmt_block DEDENT
5791ParseResult FIRCircuitParser::parseModule(CircuitOp circuit, bool isPublic,
5792 unsigned indent) {
5793 StringAttr name;
5794 SmallVector<PortInfo, 8> portList;
5795 SmallVector<SMLoc> portLocs;
5796 ArrayAttr enabledLayers;
5797 auto modLoc = getToken().getLoc();
5798 LocWithInfo info(modLoc, this);
5799 consumeToken(FIRToken::kw_module);
5800 if (parseId(name, "expected module name") ||
5801 parseModuleLayerSpec(enabledLayers) ||
5802 parseToken(FIRToken::colon, "expected ':' in module definition") ||
5803 info.parseOptionalInfo() || parsePortList(portList, portLocs, indent))
5804 return failure();
5805
5806 // The main module is implicitly public.
5807 if (name == circuit.getName()) {
5808 if (!isPublic && removedFeature({4, 0, 0}, "private main modules", modLoc))
5809 return failure();
5810 isPublic = true;
5811 }
5812
5813 if (isPublic && version >= FIRVersion({4, 0, 0})) {
5814 for (auto [pi, loc] : llvm::zip_equal(portList, portLocs)) {
5815 if (auto ftype = type_dyn_cast<FIRRTLType>(pi.type)) {
5816 if (ftype.hasUninferredWidth())
5817 return emitError(loc, "public module port must have known width");
5818 if (ftype.hasUninferredReset())
5819 return emitError(loc,
5820 "public module port must have concrete reset type");
5821 }
5822 }
5823 }
5824
5825 ArrayAttr annotations = getConstants().emptyArrayAttr;
5826 auto convention = Convention::Internal;
5827 if (isPublic && getConstants().options.scalarizePublicModules)
5828 convention = Convention::Scalarized;
5829 if (!isPublic && getConstants().options.scalarizeInternalModules)
5830 convention = Convention::Scalarized;
5831 auto conventionAttr = ConventionAttr::get(getContext(), convention);
5832 auto builder = circuit.getBodyBuilder();
5833 auto moduleOp =
5834 FModuleOp::create(builder, info.getLoc(), name, conventionAttr, portList,
5835 annotations, enabledLayers);
5836
5837 auto visibility = isPublic ? SymbolTable::Visibility::Public
5838 : SymbolTable::Visibility::Private;
5839 SymbolTable::setSymbolVisibility(moduleOp, visibility);
5840
5841 // Parse the body of this module after all prototypes have been parsed. This
5842 // allows us to handle forward references correctly.
5843 deferredModules.emplace_back(DeferredModuleToParse{
5844 moduleOp, portLocs, getLexer().getCursor(), indent});
5845
5846 if (skipToModuleEnd(indent))
5847 return failure();
5848 return success();
5849}
5850
5851/// formal ::= 'formal' formal-like
5852ParseResult FIRCircuitParser::parseFormal(CircuitOp circuit, unsigned indent) {
5853 consumeToken(FIRToken::kw_formal);
5854 return parseFormalLike<FormalOp>(circuit, indent);
5855}
5856
5857/// simulation ::= 'simulation' formal-like
5858ParseResult FIRCircuitParser::parseSimulation(CircuitOp circuit,
5859 unsigned indent) {
5860 consumeToken(FIRToken::kw_simulation);
5861 return parseFormalLike<SimulationOp>(circuit, indent);
5862}
5863
5864/// formal-like ::= formal-like-old | formal-like-new
5865/// formal-like-old ::= id 'of' id ',' 'bound' '=' int info?
5866/// formal-like-new ::= id 'of' id ':' info? INDENT (param NEWLINE)* DEDENT
5867template <class Op>
5868ParseResult FIRCircuitParser::parseFormalLike(CircuitOp circuit,
5869 unsigned indent) {
5870 StringRef id, moduleName;
5871 int64_t bound = 0;
5872 LocWithInfo info(getToken().getLoc(), this);
5873 auto builder = circuit.getBodyBuilder();
5874
5875 // Parse the name and target module of the test.
5876 if (parseId(id, "expected test name") ||
5877 parseToken(FIRToken::kw_of, "expected 'of' in test") ||
5878 parseId(moduleName, "expected module name"))
5879 return failure();
5880
5881 // TODO: Remove the old `, bound = N` variant in favor of the new parameters.
5882 NamedAttrList params;
5883 if (consumeIf(FIRToken::comma)) {
5884 // Parse the old style declaration with a `, bound = N` suffix.
5885 if (getToken().isNot(FIRToken::identifier) || getTokenSpelling() != "bound")
5886 return emitError("expected 'bound' after ','");
5887 consumeToken();
5888 if (parseToken(FIRToken::equal, "expected '=' after 'bound'") ||
5889 parseIntLit(bound, "expected integer bound after '='"))
5890 return failure();
5891 if (bound <= 0)
5892 return emitError("bound must be a positive integer");
5893 if (info.parseOptionalInfo())
5894 return failure();
5895 params.set("bound", builder.getIntegerAttr(builder.getI32Type(), bound));
5896 } else {
5897 // Parse the new style declaration with a `:` and parameter list.
5898 if (parseToken(FIRToken::colon, "expected ':' in test") ||
5899 info.parseOptionalInfo())
5900 return failure();
5901 while (getIndentation() > indent) {
5902 StringAttr paramName;
5903 Attribute paramValue;
5904 SMLoc paramLoc;
5905 if (parseParameter(paramName, paramValue, paramLoc,
5906 /*allowAggregates=*/true))
5907 return failure();
5908 if (params.set(paramName, paramValue))
5909 return emitError(paramLoc, "redefinition of parameter '" +
5910 paramName.getValue() + "'");
5911 }
5912 }
5913
5914 Op::create(builder, info.getLoc(), id, moduleName,
5915 params.getDictionary(getContext()));
5916 return success();
5917}
5918
5919ParseResult FIRCircuitParser::parseToplevelDefinition(CircuitOp circuit,
5920 unsigned indent) {
5921 switch (getToken().getKind()) {
5922 case FIRToken::kw_class:
5923 return parseClass(circuit, indent);
5924 case FIRToken::kw_declgroup:
5925 if (requireFeature({3, 2, 0}, "optional groups") ||
5926 removedFeature({3, 3, 0}, "optional groups"))
5927 return failure();
5928 return parseLayer(circuit);
5929 case FIRToken::kw_domain:
5930 if (requireFeature(missingSpecFIRVersion, "domains"))
5931 return failure();
5932 return parseDomain(circuit, indent);
5933 case FIRToken::kw_extclass:
5934 return parseExtClass(circuit, indent);
5935 case FIRToken::kw_extmodule:
5936 return parseExtModule(circuit, indent);
5937 case FIRToken::kw_formal:
5938 if (requireFeature({4, 0, 0}, "formal tests"))
5939 return failure();
5940 return parseFormal(circuit, indent);
5941 case FIRToken::kw_intmodule:
5942 if (requireFeature({1, 2, 0}, "intrinsic modules") ||
5943 removedFeature({4, 0, 0}, "intrinsic modules"))
5944 return failure();
5945 return parseIntModule(circuit, indent);
5946 case FIRToken::kw_layer:
5947 if (requireFeature({3, 3, 0}, "layers"))
5948 return failure();
5949 return parseLayer(circuit);
5950 case FIRToken::kw_module:
5951 return parseModule(circuit, /*isPublic=*/false, indent);
5952 case FIRToken::kw_public:
5953 if (requireFeature({3, 3, 0}, "public modules"))
5954 return failure();
5955 consumeToken();
5956 if (getToken().getKind() == FIRToken::kw_module)
5957 return parseModule(circuit, /*isPublic=*/true, indent);
5958 return emitError(getToken().getLoc(), "only modules may be public");
5959 case FIRToken::kw_simulation:
5960 if (requireFeature(nextFIRVersion, "simulation tests"))
5961 return failure();
5962 return parseSimulation(circuit, indent);
5963 case FIRToken::kw_type:
5964 return parseTypeDecl();
5965 case FIRToken::kw_option:
5966 if (requireFeature(missingSpecFIRVersion, "option groups/instance choices"))
5967 return failure();
5968 return parseOptionDecl(circuit);
5969 default:
5970 return emitError(getToken().getLoc(), "unknown toplevel definition");
5971 }
5972}
5973
5974// Parse a type declaration.
5975ParseResult FIRCircuitParser::parseTypeDecl() {
5976 StringRef id;
5977 FIRRTLType type;
5978 consumeToken();
5979 auto loc = getToken().getLoc();
5980
5981 if (getToken().isKeyword())
5982 return emitError(loc) << "cannot use keyword '" << getToken().getSpelling()
5983 << "' for type alias name";
5984
5985 if (parseId(id, "expected type name") ||
5986 parseToken(FIRToken::equal, "expected '=' in type decl") ||
5987 parseType(type, "expected a type"))
5988 return failure();
5989 auto name = StringAttr::get(type.getContext(), id);
5990 // Create type alias only for base types. Otherwise just pass through the
5991 // type.
5992 if (auto base = type_dyn_cast<FIRRTLBaseType>(type))
5993 type = BaseTypeAliasType::get(name, base);
5994 else
5995 emitWarning(loc)
5996 << "type alias for non-base type " << type
5997 << " is currently not supported. Type alias is stripped immediately";
5998
5999 if (!getConstants().aliasMap.insert({id, type}).second)
6000 return emitError(loc) << "type alias `" << name.getValue()
6001 << "` is already defined";
6002 return success();
6003}
6004
6005// Parse an option group declaration.
6006ParseResult FIRCircuitParser::parseOptionDecl(CircuitOp circuit) {
6007 StringRef id;
6008 consumeToken();
6009 auto loc = getToken().getLoc();
6010
6011 LocWithInfo info(getToken().getLoc(), this);
6012 if (parseId(id, "expected an option group name") ||
6013 parseToken(FIRToken::colon,
6014 "expected ':' after option group definition") ||
6015 info.parseOptionalInfo())
6016 return failure();
6017
6018 auto builder = OpBuilder::atBlockEnd(circuit.getBodyBlock());
6019 auto optionOp = OptionOp::create(builder, info.getLoc(), id);
6020 auto *block = new Block;
6021 optionOp.getBody().push_back(block);
6022 builder.setInsertionPointToEnd(block);
6023
6024 auto baseIndent = getIndentation();
6025 StringSet<> cases;
6026 while (getIndentation() == baseIndent) {
6027 StringRef id;
6028 LocWithInfo caseInfo(getToken().getLoc(), this);
6029 if (parseId(id, "expected an option case ID") ||
6030 caseInfo.parseOptionalInfo())
6031 return failure();
6032
6033 if (!cases.insert(id).second)
6034 return emitError(loc)
6035 << "duplicate option case definition '" << id << "'";
6036
6037 OptionCaseOp::create(builder, caseInfo.getLoc(), id);
6038 }
6039
6040 return success();
6041}
6042
6043// Parse a layer definition.
6044ParseResult FIRCircuitParser::parseLayer(CircuitOp circuit) {
6045 auto baseIndent = getIndentation();
6046
6047 // A stack of all layers that are possibly parents of the current layer.
6048 SmallVector<std::pair<std::optional<unsigned>, LayerOp>> layerStack;
6049
6050 // Parse a single layer and add it to the layerStack.
6051 auto parseOne = [&](Block *block) -> ParseResult {
6052 auto indent = getIndentation();
6053 StringRef id, convention;
6054 LocWithInfo info(getToken().getLoc(), this);
6055 consumeToken();
6056 if (parseId(id, "expected layer name") ||
6057 parseToken(FIRToken::comma, "expected ','") ||
6058 parseGetSpelling(convention))
6059 return failure();
6060
6061 auto layerConvention = symbolizeLayerConvention(convention);
6062 if (!layerConvention) {
6063 emitError() << "unknown convention '" << convention
6064 << "' (did you misspell it?)";
6065 return failure();
6066 }
6067 if (layerConvention == LayerConvention::Inline &&
6068 requireFeature({4, 1, 0}, "inline layers"))
6069 return failure();
6070 consumeToken();
6071
6072 hw::OutputFileAttr outputDir;
6073 if (consumeIf(FIRToken::comma)) {
6074 if (getToken().getKind() == FIRToken::string) {
6075 auto text = getToken().getStringValue();
6076 if (text.empty())
6077 return emitError() << "output directory must not be blank";
6078 outputDir = hw::OutputFileAttr::getAsDirectory(getContext(), text);
6079 consumeToken(FIRToken::string);
6080 }
6081 }
6082
6083 if (parseToken(FIRToken::colon, "expected ':' after layer definition") ||
6084 info.parseOptionalInfo())
6085 return failure();
6086 auto builder = OpBuilder::atBlockEnd(block);
6087 // Create the layer definition and give it an empty block.
6088 auto layerOp =
6089 LayerOp::create(builder, info.getLoc(), id, *layerConvention);
6090 layerOp->getRegion(0).push_back(new Block());
6091 if (outputDir)
6092 layerOp->setAttr("output_file", outputDir);
6093 layerStack.push_back({indent, layerOp});
6094 return success();
6095 };
6096
6097 if (parseOne(circuit.getBodyBlock()))
6098 return failure();
6099
6100 // Parse any nested layers.
6101 while (getIndentation() > baseIndent) {
6102 switch (getToken().getKind()) {
6103 case FIRToken::kw_declgroup:
6104 case FIRToken::kw_layer: {
6105 // Pop nested layers off the stack until we find out what layer to insert
6106 // this into.
6107 while (layerStack.back().first >= getIndentation())
6108 layerStack.pop_back();
6109 auto parentLayer = layerStack.back().second;
6110 if (parseOne(&parentLayer.getBody().front()))
6111 return failure();
6112 break;
6113 }
6114 default:
6115 return emitError("expected 'layer'"), failure();
6116 }
6117 }
6118
6119 return success();
6120}
6121
6122ParseResult FIRCircuitParser::resolveDomains(
6123 const SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domainsByName,
6124 const DenseMap<Attribute, size_t> &nameToIndex,
6125 SmallVectorImpl<Attribute> &domainsByIndex) {
6126
6127 for (auto [attr, loc] : domainsByName) {
6128 auto domain = cast<StringAttr>(attr);
6129 auto indexItr = nameToIndex.find(domain);
6130 if (indexItr == nameToIndex.end()) {
6131 emitError(loc) << "unknown domain name '" << domain.getValue() << "'";
6132 return failure();
6133 }
6134 domainsByIndex.push_back(IntegerAttr::get(
6135 IntegerType::get(getContext(), 32, IntegerType::Unsigned),
6136 indexItr->second));
6137 }
6138
6139 return success();
6140}
6141
6142ParseResult FIRCircuitParser::parseDomains(
6143 SmallVectorImpl<std::pair<Attribute, llvm::SMLoc>> &domains,
6144 const DenseMap<Attribute, size_t> &nameToIndex) {
6145 if (requireFeature(missingSpecFIRVersion, "domains"))
6146 return failure();
6147 if (parseToken(FIRToken::kw_domains, "expected 'domains'") ||
6148 parseToken(FIRToken::l_square, "expected '['"))
6149 return failure();
6150
6151 if (parseListUntil(FIRToken::r_square, [&]() -> ParseResult {
6152 StringAttr domain;
6153 auto domainLoc = getToken().getLoc();
6154 if (parseId(domain, "expected domain name"))
6155 return failure();
6156 domains.push_back({domain, domainLoc});
6157 return success();
6158 }))
6159 return failure();
6160
6161 return success();
6162}
6163
6164// Parse the body of this module.
6165ParseResult
6166FIRCircuitParser::parseModuleBody(const SymbolTable &circuitSymTbl,
6167 DeferredModuleToParse &deferredModule,
6168 InnerSymFixups &fixups) {
6169 FModuleLike moduleOp = deferredModule.moduleOp;
6170 auto &body = moduleOp->getRegion(0).front();
6171 auto &portLocs = deferredModule.portLocs;
6172
6173 // We parse the body of this module with its own lexer, enabling parallel
6174 // parsing with the rest of the other module bodies.
6175 FIRLexer moduleBodyLexer(getLexer().getSourceMgr(), getContext());
6176
6177 // Reset the parser/lexer state back to right after the port list.
6178 deferredModule.lexerCursor.restore(moduleBodyLexer);
6179
6180 FIRModuleContext moduleContext(&body, getConstants(), moduleBodyLexer,
6181 version);
6182
6183 // Install all of the ports into the symbol table, associated with their
6184 // block arguments.
6185 auto portList = moduleOp.getPorts();
6186 auto portArgs = body.getArguments();
6187 for (auto tuple : llvm::zip(portList, portLocs, portArgs)) {
6188 PortInfo &port = std::get<0>(tuple);
6189 llvm::SMLoc loc = std::get<1>(tuple);
6190 BlockArgument portArg = std::get<2>(tuple);
6191 assert(!port.sym);
6192 if (moduleContext.addSymbolEntry(port.getName(), portArg, loc))
6193 return failure();
6194 }
6195
6196 FIRStmtParser stmtParser(body, moduleContext, fixups, circuitSymTbl, version);
6197
6198 // Parse the moduleBlock.
6199 auto result = stmtParser.parseSimpleStmtBlock(deferredModule.indent);
6200 if (failed(result))
6201 return result;
6202
6203 // Scan for printf-encoded verif's to error on their use, no longer supported.
6204 {
6205 size_t numVerifPrintfs = 0;
6206 std::optional<Location> printfLoc;
6207
6208 deferredModule.moduleOp.walk([&](PrintFOp printFOp) {
6210 return;
6211 ++numVerifPrintfs;
6212 if (!printfLoc)
6213 printfLoc = printFOp.getLoc();
6214 });
6215
6216 if (numVerifPrintfs > 0) {
6217 auto diag =
6218 mlir::emitError(deferredModule.moduleOp.getLoc(), "module contains ")
6219 << numVerifPrintfs
6220 << " printf-encoded verification operation(s), which are no longer "
6221 "supported.";
6222 diag.attachNote(*printfLoc)
6223 << "example printf here, this is now just a printf and nothing more";
6224 diag.attachNote() << "For more information, see "
6225 "https://github.com/llvm/circt/issues/6970";
6226 return diag;
6227 }
6228 }
6229
6230 return success();
6231}
6232
6233/// file ::= circuit
6234/// versionHeader ::= 'FIRRTL' 'version' versionLit NEWLINE
6235/// circuit ::= versionHeader? 'circuit' id ':' info? INDENT module* DEDENT EOF
6236///
6237/// If non-null, annotationsBuf is a memory buffer containing JSON annotations.
6238///
6239ParseResult FIRCircuitParser::parseCircuit(
6240 SmallVectorImpl<const llvm::MemoryBuffer *> &annotationsBufs,
6241 mlir::TimingScope &ts) {
6242
6243 auto indent = getIndentation();
6244 if (parseToken(FIRToken::kw_FIRRTL, "expected 'FIRRTL'"))
6245 return failure();
6246 if (!indent.has_value())
6247 return emitError("'FIRRTL' must be first token on its line");
6248 if (parseToken(FIRToken::kw_version, "expected version after 'FIRRTL'") ||
6249 parseVersionLit("expected version literal"))
6250 return failure();
6251 indent = getIndentation();
6252
6253 if (!indent.has_value())
6254 return emitError("'circuit' must be first token on its line");
6255 unsigned circuitIndent = *indent;
6256
6257 LocWithInfo info(getToken().getLoc(), this);
6258 StringAttr name;
6259 SMLoc inlineAnnotationsLoc;
6260 StringRef inlineAnnotations;
6261
6262 // A file must contain a top level `circuit` definition.
6263 if (parseToken(FIRToken::kw_circuit,
6264 "expected a top-level 'circuit' definition") ||
6265 parseId(name, "expected circuit name") ||
6266 parseToken(FIRToken::colon, "expected ':' in circuit definition") ||
6267 parseOptionalAnnotations(inlineAnnotationsLoc, inlineAnnotations) ||
6268 info.parseOptionalInfo())
6269 return failure();
6270
6271 // Create the top-level circuit op in the MLIR module.
6272 OpBuilder b(mlirModule.getBodyRegion());
6273 auto circuit = CircuitOp::create(b, info.getLoc(), name);
6274
6275 // A timer to get execution time of annotation parsing.
6276 auto parseAnnotationTimer = ts.nest("Parse annotations");
6277
6278 // Deal with any inline annotations, if they exist. These are processed
6279 // first to place any annotations from an annotation file *after* the inline
6280 // annotations. While arbitrary, this makes the annotation file have
6281 // "append" semantics.
6282 SmallVector<Attribute> annos;
6283 if (!inlineAnnotations.empty())
6284 if (importAnnotationsRaw(inlineAnnotationsLoc, inlineAnnotations, annos))
6285 return failure();
6286
6287 // Deal with the annotation file if one was specified
6288 for (auto *annotationsBuf : annotationsBufs)
6289 if (importAnnotationsRaw(info.getFIRLoc(), annotationsBuf->getBuffer(),
6290 annos))
6291 return failure();
6292
6293 parseAnnotationTimer.stop();
6294
6295 // Get annotations that are supposed to be specially handled by the
6296 // LowerAnnotations pass.
6297 if (!annos.empty())
6298 circuit->setAttr(rawAnnotations, b.getArrayAttr(annos));
6299
6300 // A timer to get execution time of module parsing.
6301 auto parseTimer = ts.nest("Parse modules");
6302 deferredModules.reserve(16);
6303
6304 // Parse any contained modules.
6305 while (true) {
6306 switch (getToken().getKind()) {
6307 // If we got to the end of the file, then we're done.
6308 case FIRToken::eof:
6309 goto DoneParsing;
6310
6311 // If we got an error token, then the lexer already emitted an error,
6312 // just stop. We could introduce error recovery if there was demand for
6313 // it.
6314 case FIRToken::error:
6315 return failure();
6316
6317 default:
6318 emitError("unexpected token in circuit");
6319 return failure();
6320
6321 case FIRToken::kw_class:
6322 case FIRToken::kw_declgroup:
6323 case FIRToken::kw_domain:
6324 case FIRToken::kw_extclass:
6325 case FIRToken::kw_extmodule:
6326 case FIRToken::kw_intmodule:
6327 case FIRToken::kw_layer:
6328 case FIRToken::kw_formal:
6329 case FIRToken::kw_module:
6330 case FIRToken::kw_option:
6331 case FIRToken::kw_public:
6332 case FIRToken::kw_simulation:
6333 case FIRToken::kw_type: {
6334 auto indent = getIndentation();
6335 if (!indent.has_value())
6336 return emitError("'module' must be first token on its line"), failure();
6337 unsigned definitionIndent = *indent;
6338
6339 if (definitionIndent <= circuitIndent)
6340 return emitError("module should be indented more"), failure();
6341
6342 if (parseToplevelDefinition(circuit, definitionIndent))
6343 return failure();
6344 break;
6345 }
6346 }
6347 }
6348
6349 // After the outline of the file has been parsed, we can go ahead and parse
6350 // all the bodies. This allows us to resolve forward-referenced modules and
6351 // makes it possible to parse their bodies in parallel.
6352DoneParsing:
6353 // Each of the modules may translate source locations, and doing so touches
6354 // the SourceMgr to build a line number cache. This isn't thread safe, so we
6355 // proactively touch it to make sure that it is always already created.
6356 (void)getLexer().translateLocation(info.getFIRLoc());
6357
6358 // Pre-verify symbol table, so we can construct it next. Ideally, we would do
6359 // this verification through the trait.
6360 { // Memory is tight in parsing.
6361 // Check that all symbols are uniquely named within child regions.
6362 DenseMap<Attribute, Location> nameToOrigLoc;
6363 for (auto &op : *circuit.getBodyBlock()) {
6364 // Check for a symbol name attribute.
6365 auto nameAttr =
6366 op.getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName());
6367 if (!nameAttr)
6368 continue;
6369
6370 // Try to insert this symbol into the table.
6371 auto it = nameToOrigLoc.try_emplace(nameAttr, op.getLoc());
6372 if (!it.second) {
6373 op.emitError()
6374 .append("redefinition of symbol named '", nameAttr.getValue(), "'")
6375 .attachNote(it.first->second)
6376 .append("see existing symbol definition here");
6377 return failure();
6378 }
6379 }
6380 }
6381
6382 SymbolTable circuitSymTbl(circuit);
6383
6384 moduleFixups.resize(deferredModules.size());
6385
6386 // Stub out inner symbol namespace for each module,
6387 // none should be added so do this now to avoid walking later
6388 // to discover that this is the case.
6389 for (auto &d : deferredModules)
6390 innerSymbolNamespaces.get(d.moduleOp.getOperation());
6391
6392 // Next, parse all the module bodies.
6393 auto anyFailed = mlir::failableParallelForEachN(
6394 getContext(), 0, deferredModules.size(), [&](size_t index) {
6395 if (parseModuleBody(circuitSymTbl, deferredModules[index],
6396 moduleFixups[index]))
6397 return failure();
6398 return success();
6399 });
6400 if (failed(anyFailed))
6401 return failure();
6402
6403 // Walk operations created that have inner symbol references
6404 // that need replacing now that it's safe to create inner symbols everywhere.
6405 for (auto &fixups : moduleFixups) {
6406 if (failed(fixups.resolve(innerSymbolNamespaces)))
6407 return failure();
6408 }
6409
6410 // Helper to transform a layer name specification of the form `A::B::C` into
6411 // a SymbolRefAttr.
6412 auto parseLayerName = [&](StringRef name) -> Attribute {
6413 // Parse the layer name into a SymbolRefAttr.
6414 auto [head, rest] = name.split(".");
6415 SmallVector<FlatSymbolRefAttr> nestedRefs;
6416 while (!rest.empty()) {
6417 StringRef next;
6418 std::tie(next, rest) = rest.split(".");
6419 nestedRefs.push_back(FlatSymbolRefAttr::get(getContext(), next));
6420 }
6421 return SymbolRefAttr::get(getContext(), head, nestedRefs);
6422 };
6423
6424 auto getArrayAttr = [&](ArrayRef<std::string> strArray, auto getAttr) {
6425 SmallVector<Attribute> attrArray;
6426 auto *context = getContext();
6427 for (const auto &str : strArray)
6428 attrArray.push_back(getAttr(str));
6429 if (attrArray.empty())
6430 return ArrayAttr();
6431 return ArrayAttr::get(context, attrArray);
6432 };
6433
6434 if (auto enableLayers =
6435 getArrayAttr(getConstants().options.enableLayers, parseLayerName))
6436 circuit.setEnableLayersAttr(enableLayers);
6437 if (auto disableLayers =
6438 getArrayAttr(getConstants().options.disableLayers, parseLayerName))
6439 circuit.setDisableLayersAttr(disableLayers);
6440
6441 auto getStrAttr = [&](StringRef str) -> Attribute {
6442 return StringAttr::get(getContext(), str);
6443 };
6444
6445 if (auto selectInstChoice =
6446 getArrayAttr(getConstants().options.selectInstanceChoice, getStrAttr))
6447 circuit.setSelectInstChoiceAttr(selectInstChoice);
6448
6449 circuit.setDefaultLayerSpecialization(
6450 getConstants().options.defaultLayerSpecialization);
6451
6452 return success();
6453}
6454
6455//===----------------------------------------------------------------------===//
6456// Driver
6457//===----------------------------------------------------------------------===//
6458
6459// Parse the specified .fir file into the specified MLIR context.
6461circt::firrtl::importFIRFile(SourceMgr &sourceMgr, MLIRContext *context,
6462 mlir::TimingScope &ts, FIRParserOptions options) {
6463 auto sourceBuf = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
6464 SmallVector<const llvm::MemoryBuffer *> annotationsBufs;
6465 unsigned fileID = 1;
6466 for (unsigned e = options.numAnnotationFiles + 1; fileID < e; ++fileID)
6467 annotationsBufs.push_back(
6468 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID() + fileID));
6469
6470 context->loadDialect<CHIRRTLDialect>();
6471 context->loadDialect<FIRRTLDialect, hw::HWDialect>();
6472
6473 // This is the result module we are parsing into.
6474 mlir::OwningOpRef<mlir::ModuleOp> module(ModuleOp::create(
6475 FileLineColLoc::get(context, sourceBuf->getBufferIdentifier(),
6476 /*line=*/0,
6477 /*column=*/0)));
6478 SharedParserConstants state(context, options);
6479 FIRLexer lexer(sourceMgr, context);
6480 if (FIRCircuitParser(state, lexer, *module, minimumFIRVersion)
6481 .parseCircuit(annotationsBufs, ts))
6482 return nullptr;
6483
6484 // Make sure the parse module has no other structural problems detected by
6485 // the verifier.
6486 auto circuitVerificationTimer = ts.nest("Verify circuit");
6487 if (failed(verify(*module)))
6488 return {};
6489
6490 return module;
6491}
6492
6494 static mlir::TranslateToMLIRRegistration fromFIR(
6495 "import-firrtl", "import .fir",
6496 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
6497 mlir::TimingScope ts;
6498 return importFIRFile(sourceMgr, context, ts);
6499 });
6500}
assert(baseType &&"element must be base type")
MlirType elementType
Definition CHIRRTL.cpp:29
static ParseResult parseParameterList(OpAsmParser &parser, SmallVector< Attribute > &parameters)
Parse an parameter list if present.
static std::unique_ptr< Context > context
static mlir::Operation * resolve(Context &context, mlir::SymbolRefAttr sym)
std::vector< UnbundledValueEntry > UnbundledValuesList
SmallVector< std::pair< Attribute, Value > > UnbundledValueEntry
llvm::StringMap< std::pair< SMLoc, SymbolValueEntry >, llvm::BumpPtrAllocator > ModuleSymbolTable
llvm::PointerUnion< Value, UnbundledID > SymbolValueEntry
llvm::DenseMap< std::pair< Value, unsigned >, Value > SubaccessCache
ModuleSymbolTable::MapEntryTy ModuleSymbolTableEntry
llvm::PointerEmbeddedInt< unsigned, 31 > UnbundledID
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:216
static ParseResult parsePortList(OpAsmParser &p, SmallVectorImpl< module_like_impl::PortParse > &result)
static Block * getBodyBlock(FModuleLike mod)
This helper class is used to handle Info records, which specify higher level symbolic source location...
std::optional< Location > infoLoc
This is the location specified by the @ marker if present.
LocWithInfo(SMLoc firLoc, FIRParser *parser)
void setDefaultLoc(Location loc)
If we didn't parse an info locator for the specified value, this sets a default, overriding a fall ba...
FIRParser *const parser
SMLoc firLoc
This is the designated location in the .fir file for use when there is no @ info marker.
ParseResult parseOptionalInfo()
Parse an @info marker if present and update our location.
SMLoc getFIRLoc() const
This class represents a reference to a specific field or element of an aggregate value.
Definition FieldRef.h:28
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
Definition FieldRef.h: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:420
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
Definition FIRRTLEnums.h:36
Flow swapFlow(Flow flow)
Get a flow's reverse.
void registerFromFIRFileTranslation()
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * rawAnnotations
bool areTypesRefCastable(Type dstType, Type srcType)
Return true if destination ref type can be cast from source ref type, per FIRRTL spec rules they must...
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
mlir::OwningOpRef< mlir::ModuleOp > importFIRFile(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, FIRParserOptions options={})
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.