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