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